Restrict cast types

This commit is contained in:
Eugen Wissner 2025-03-21 10:24:57 +01:00
parent 5e8555b4f4
commit aaa3de325b
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
4 changed files with 93 additions and 86 deletions

View File

@ -18,6 +18,10 @@ along with GCC; see the file COPYING3. If not see
%require "3.4"
%language "c++"
%code {
using namespace elna;
}
%code requires {
#include <cstdint>
#include <iostream>
@ -52,7 +56,7 @@ along with GCC; see the file COPYING3. If not see
{
}
yy::parser::symbol_type lex(elna::boot::driver& driver);
yy::parser::symbol_type lex(driver& driver);
};
}
@ -157,7 +161,7 @@ along with GCC; see the file COPYING3. If not see
program:
constant_part type_part variable_part procedure_part "begin" statements "end" "."
{
auto tree = new elna::boot::program(elna::boot::make_position(@5));
auto tree = new boot::program(boot::make_position(@5));
std::swap(tree->constants, $1);
std::swap(tree->types , $2);
@ -169,7 +173,7 @@ program:
}
block: constant_part variable_part "begin" statements "end"
{
$$ = new elna::boot::block(elna::boot::make_position(@3));
$$ = new boot::block(boot::make_position(@3));
std::swap($$->constants, $1);
std::swap($$->variables, $2);
@ -193,12 +197,12 @@ identifier_definitions:
| identifier_definition { $$.emplace_back(std::move($1)); }
return_declaration:
/* proper procedure */ {}
| "->" "!" { $$ = elna::boot::return_declaration(std::monostate{}); }
| "->" type_expression { $$ = elna::boot::return_declaration($2); }
| "->" "!" { $$ = boot::return_declaration(std::monostate{}); }
| "->" type_expression { $$ = boot::return_declaration($2); }
procedure_heading:
"(" formal_parameters ")" return_declaration
{
$$.second = std::make_shared<elna::boot::procedure_type_expression>(elna::boot::make_position(@1),
$$.second = std::make_shared<boot::procedure_type_expression>(boot::make_position(@1),
std::move($4));
for (auto& [name, type] : $2)
{
@ -209,13 +213,13 @@ procedure_heading:
procedure_definition:
"proc" identifier_definition procedure_heading ";" block
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$$ = new boot::procedure_definition(boot::make_position(@1),
$2.first, $2.second, $3.second, $5);
std::swap($3.first, $$->parameter_names);
}
| "proc" identifier_definition procedure_heading ";" "extern"
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), $2.first, $2.second, $3.second);
$$ = new boot::procedure_definition(boot::make_position(@1), $2.first, $2.second, $3.second);
std::swap($3.first, $$->parameter_names);
}
procedure_definitions:
@ -230,21 +234,21 @@ procedure_part:
| procedure_definitions { std::swap($$, $1); }
assign_statement: designator_expression ":=" expression
{
$$ = new elna::boot::assign_statement(elna::boot::make_position(@1), $1, $3);
$$ = new boot::assign_statement(boot::make_position(@1), $1, $3);
}
call_expression: designator_expression actual_parameter_list
{
$$ = new elna::boot::procedure_call(elna::boot::make_position(@1), $1);
$$ = new boot::procedure_call(boot::make_position(@1), $1);
std::swap($$->arguments, $2);
}
cast_expression: "cast" "(" expression ":" type_expression ")"
{
$$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3);
$$ = new boot::cast_expression(boot::make_position(@1), $5, $3);
}
elsif_do_statements:
"elsif" expression "do" statements elsif_do_statements
{
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
boot::conditional_statements *branch = new boot::conditional_statements($2);
std::swap(branch->statements, $4);
std::swap($5, $$);
$$.emplace($$.begin(), branch);
@ -252,15 +256,15 @@ elsif_do_statements:
| {}
while_statement: "while" expression "do" statements elsif_do_statements "end"
{
auto body = new elna::boot::conditional_statements($2);
auto body = new boot::conditional_statements($2);
std::swap($4, body->statements);
$$ = new elna::boot::while_statement(elna::boot::make_position(@1), body);
$$ = new boot::while_statement(boot::make_position(@1), body);
std::swap($5, $$->branches);
}
elsif_then_statements:
"elsif" expression "then" statements elsif_then_statements
{
elna::boot::conditional_statements *branch = new elna::boot::conditional_statements($2);
boot::conditional_statements *branch = new boot::conditional_statements($2);
std::swap(branch->statements, $4);
std::swap($5, $$);
$$.emplace($$.begin(), branch);
@ -269,61 +273,61 @@ elsif_then_statements:
if_statement:
"if" expression "then" statements elsif_then_statements "end"
{
auto then = new elna::boot::conditional_statements($2);
auto then = new boot::conditional_statements($2);
std::swap($4, then->statements);
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then);
$$ = new boot::if_statement(boot::make_position(@1), then);
std::swap($5, $$->branches);
}
| "if" expression "then" statements elsif_then_statements "else" statements "end"
{
auto then = new elna::boot::conditional_statements($2);
auto then = new boot::conditional_statements($2);
std::swap($4, then->statements);
auto _else = new std::vector<elna::boot::statement *>(std::move($7));
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then, _else);
auto _else = new std::vector<boot::statement *>(std::move($7));
$$ = new boot::if_statement(boot::make_position(@1), then, _else);
std::swap($5, $$->branches);
}
return_statement: "return" expression
{
$$ = new elna::boot::return_statement(elna::boot::make_position(@1), $2);
$$ = new boot::return_statement(boot::make_position(@1), $2);
}
defer_statement: DEFER statements "end"
{
$$ = new elna::boot::defer_statement(elna::boot::make_position(@1));
$$ = new boot::defer_statement(boot::make_position(@1));
std::swap($2, $$->statements);
}
literal:
INTEGER
{
$$ = new elna::boot::literal<std::int32_t>(elna::boot::make_position(@1), $1);
$$ = new boot::literal<std::int32_t>(boot::make_position(@1), $1);
}
| WORD
{
$$ = new elna::boot::literal<std::uint32_t>(elna::boot::make_position(@1), $1);
$$ = new boot::literal<std::uint32_t>(boot::make_position(@1), $1);
}
| FLOAT
{
$$ = new elna::boot::literal<double>(elna::boot::make_position(@1), $1);
$$ = new boot::literal<double>(boot::make_position(@1), $1);
}
| BOOLEAN
{
$$ = new elna::boot::literal<bool>(elna::boot::make_position(@1), $1);
$$ = new boot::literal<bool>(boot::make_position(@1), $1);
}
| CHARACTER
{
$$ = new elna::boot::literal<unsigned char>(elna::boot::make_position(@1), $1.at(0));
$$ = new boot::literal<unsigned char>(boot::make_position(@1), $1.at(0));
}
| "nil"
{
$$ = new elna::boot::literal<std::nullptr_t>(elna::boot::make_position(@1), nullptr);
$$ = new boot::literal<std::nullptr_t>(boot::make_position(@1), nullptr);
}
| STRING
{
$$ = new elna::boot::literal<std::string>(elna::boot::make_position(@1), $1);
$$ = new boot::literal<std::string>(boot::make_position(@1), $1);
}
traits_expression:
TRAIT "(" type_expressions ")"
{
$$ = new elna::boot::traits_expression(elna::boot::make_position(@1), $1);
$$ = new boot::traits_expression(boot::make_position(@1), $1);
std::swap($3, $$->parameters);
}
qualident:
@ -342,99 +346,82 @@ expression:
binary_expression:
expression "*" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::multiplication);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::multiplication);
}
| expression "/" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::division);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::division);
}
| expression "%" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::remainder);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::remainder);
}
| expression "+" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::sum);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::sum);
}
| expression "-" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::subtraction);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::subtraction);
}
| expression "=" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::equals);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::equals);
}
| expression "<>" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::not_equals);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::not_equals);
}
| expression "<" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::less);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::less);
}
| expression ">" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::greater);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater);
}
| expression "<=" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::less_equal);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3,
boot::binary_operator::less_equal);
}
| expression ">=" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::greater_equal);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater_equal);
}
| expression "&" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::conjunction);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::conjunction);
}
| expression "|" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::disjunction);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::disjunction);
}
| expression "xor" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::exclusive_disjunction);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3,
boot::binary_operator::exclusive_disjunction);
}
| expression "<<" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::shift_left);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_left);
}
| expression ">>" expression
{
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3,
elna::boot::binary_operator::shift_right);
$$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_right);
}
unary_expression:
"@" operand
{
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
elna::boot::unary_operator::reference);
$$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::reference);
}
| "~" operand
{
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
elna::boot::unary_operator::negation);
$$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::negation);
}
| "-" operand
{
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2,
elna::boot::unary_operator::minus);
$$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::minus);
}
expressions:
expression "," expressions
@ -453,19 +440,19 @@ type_expressions:
designator_expression:
qualident "[" expression "]"
{
$$ = new elna::boot::array_access_expression(elna::boot::make_position(@2), $1, $3);
$$ = new boot::array_access_expression(boot::make_position(@2), $1, $3);
}
| qualident "." IDENTIFIER
{
$$ = new elna::boot::field_access_expression(elna::boot::make_position(@2), $1, $3);
$$ = new boot::field_access_expression(boot::make_position(@2), $1, $3);
}
| qualident "^"
{
$$ = new elna::boot::dereference_expression(elna::boot::make_position(@1), $1);
$$ = new boot::dereference_expression(boot::make_position(@1), $1);
}
| IDENTIFIER
{
$$ = new elna::boot::variable_expression(elna::boot::make_position(@1), $1);
$$ = new boot::variable_expression(boot::make_position(@1), $1);
}
statement:
assign_statement { $$ = $1; }
@ -497,37 +484,37 @@ optional_fields:
type_expression:
"[" INTEGER "]" type_expression
{
$$ = std::make_shared<elna::boot::array_type_expression>(elna::boot::make_position(@1), $4, $2);
$$ = std::make_shared<boot::array_type_expression>(boot::make_position(@1), $4, $2);
}
| "^" type_expression
{
$$ = std::make_shared<elna::boot::pointer_type_expression>(elna::boot::make_position(@1), $2);
$$ = std::make_shared<boot::pointer_type_expression>(boot::make_position(@1), $2);
}
| "record" optional_fields "end"
{
$$ = std::make_shared<elna::boot::record_type_expression>(elna::boot::make_position(@1), std::move($2));
$$ = std::make_shared<boot::record_type_expression>(boot::make_position(@1), std::move($2));
}
| "union" required_fields "end"
{
$$ = std::make_shared<elna::boot::union_type_expression>(elna::boot::make_position(@1), std::move($2));
$$ = std::make_shared<boot::union_type_expression>(boot::make_position(@1), std::move($2));
}
| "proc" "(" type_expressions ")" return_declaration
{
auto result = std::make_shared<elna::boot::procedure_type_expression>(elna::boot::make_position(@1),
auto result = std::make_shared<boot::procedure_type_expression>(boot::make_position(@1),
std::move($5));
std::swap(result->parameters, $3);
$$ = result;
}
| IDENTIFIER
{
$$ = std::make_shared<elna::boot::primitive_type_expression>(elna::boot::make_position(@1), $1);
$$ = std::make_shared<boot::primitive_type_expression>(boot::make_position(@1), $1);
}
variable_declaration: identifier_definitions ":" type_expression
{
for (const std::pair<std::string, bool>& identifier : $1)
{
elna::boot::variable_declaration *declaration = new elna::boot::variable_declaration(
elna::boot::make_position(@2), identifier.first, $3, identifier.second);
boot::variable_declaration *declaration = new boot::variable_declaration(
boot::make_position(@2), identifier.first, $3, identifier.second);
$$.push_back(declaration);
}
}
@ -544,7 +531,7 @@ variable_part:
| "var" variable_declarations { std::swap($$, $2); }
constant_definition: identifier_definition "=" literal
{
$$ = new elna::boot::constant_definition(elna::boot::make_position(@1), $1.first, $1.second, $3);
$$ = new boot::constant_definition(boot::make_position(@1), $1.first, $1.second, $3);
}
constant_definitions:
constant_definition constant_definitions
@ -558,7 +545,7 @@ constant_part:
| "const" constant_definitions { std::swap($$, $2); }
type_definition: identifier_definition "=" type_expression
{
$$ = new elna::boot::type_definition(elna::boot::make_position(@1), $1.first, $1.second, $3);
$$ = new boot::type_definition(boot::make_position(@1), $1.first, $1.second, $3);
}
type_definitions:
type_definition type_definitions
@ -590,5 +577,5 @@ actual_parameter_list:
void yy::parser::error(const location_type& loc, const std::string& message)
{
driver.add_error<elna::boot::syntax_error>(message, driver.input_file, loc);
driver.add_error<boot::syntax_error>(message, driver.input_file, loc);
}

View File

@ -229,10 +229,21 @@ namespace elna::gcc
tree cast_target = this->current_expression;
expression->value().accept(this);
tree cast_source = TREE_TYPE(this->current_expression);
if ((is_primitive_type(cast_target) || is_pointer_type(cast_target))
&& (is_primitive_type(cast_source) || is_pointer_type(cast_source)))
{
this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR,
cast_target, this->current_expression);
}
else
{
error_at(get_location(&expression->position()), "Type '%s' cannot be converted to '%s'",
print_type(cast_target).c_str(), print_type(cast_source).c_str());
this->current_expression = error_mark_node;
}
}
void generic_visitor::visit(boot::program *program)
{

View File

@ -35,7 +35,7 @@ namespace elna::gcc
bool is_integral_type(tree type)
{
gcc_assert(TYPE_P(type));
return TREE_CODE(type) == INTEGER_TYPE;
return TREE_CODE(type) == INTEGER_TYPE && type != elna_char_type_node;
}
bool is_numeric_type(tree type)
@ -43,6 +43,14 @@ namespace elna::gcc
return is_integral_type(type) || type == elna_float_type_node;
}
bool is_primitive_type(tree type)
{
gcc_assert(TYPE_P(type));
return TREE_CODE(type) == INTEGER_TYPE
|| type == elna_float_type_node
|| type == elna_bool_type_node;
}
bool is_array_type(tree type)
{
gcc_assert(TYPE_P(type));

View File

@ -36,6 +36,7 @@ namespace elna::gcc
bool is_pointer_type(tree type);
bool is_integral_type(tree type);
bool is_numeric_type(tree type);
bool is_primitive_type(tree type);
bool is_array_type(tree type);
bool is_void_type(tree type);