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" %require "3.4"
%language "c++" %language "c++"
%code {
using namespace elna;
}
%code requires { %code requires {
#include <cstdint> #include <cstdint>
#include <iostream> #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: program:
constant_part type_part variable_part procedure_part "begin" statements "end" "." 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->constants, $1);
std::swap(tree->types , $2); std::swap(tree->types , $2);
@ -169,7 +173,7 @@ program:
} }
block: constant_part variable_part "begin" statements "end" 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($$->constants, $1);
std::swap($$->variables, $2); std::swap($$->variables, $2);
@ -193,12 +197,12 @@ identifier_definitions:
| identifier_definition { $$.emplace_back(std::move($1)); } | identifier_definition { $$.emplace_back(std::move($1)); }
return_declaration: return_declaration:
/* proper procedure */ {} /* proper procedure */ {}
| "->" "!" { $$ = elna::boot::return_declaration(std::monostate{}); } | "->" "!" { $$ = boot::return_declaration(std::monostate{}); }
| "->" type_expression { $$ = elna::boot::return_declaration($2); } | "->" type_expression { $$ = boot::return_declaration($2); }
procedure_heading: procedure_heading:
"(" formal_parameters ")" return_declaration "(" 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)); std::move($4));
for (auto& [name, type] : $2) for (auto& [name, type] : $2)
{ {
@ -209,13 +213,13 @@ procedure_heading:
procedure_definition: procedure_definition:
"proc" identifier_definition procedure_heading ";" block "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); $2.first, $2.second, $3.second, $5);
std::swap($3.first, $$->parameter_names); std::swap($3.first, $$->parameter_names);
} }
| "proc" identifier_definition procedure_heading ";" "extern" | "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); std::swap($3.first, $$->parameter_names);
} }
procedure_definitions: procedure_definitions:
@ -230,21 +234,21 @@ procedure_part:
| procedure_definitions { std::swap($$, $1); } | procedure_definitions { std::swap($$, $1); }
assign_statement: designator_expression ":=" expression 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 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); std::swap($$->arguments, $2);
} }
cast_expression: "cast" "(" expression ":" type_expression ")" 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_do_statements:
"elsif" expression "do" statements 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(branch->statements, $4);
std::swap($5, $$); std::swap($5, $$);
$$.emplace($$.begin(), branch); $$.emplace($$.begin(), branch);
@ -252,15 +256,15 @@ elsif_do_statements:
| {} | {}
while_statement: "while" expression "do" statements elsif_do_statements "end" 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); 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); std::swap($5, $$->branches);
} }
elsif_then_statements: elsif_then_statements:
"elsif" expression "then" statements 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(branch->statements, $4);
std::swap($5, $$); std::swap($5, $$);
$$.emplace($$.begin(), branch); $$.emplace($$.begin(), branch);
@ -269,61 +273,61 @@ elsif_then_statements:
if_statement: if_statement:
"if" expression "then" statements elsif_then_statements "end" "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); 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); std::swap($5, $$->branches);
} }
| "if" expression "then" statements elsif_then_statements "else" statements "end" | "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); std::swap($4, then->statements);
auto _else = new std::vector<elna::boot::statement *>(std::move($7)); auto _else = new std::vector<boot::statement *>(std::move($7));
$$ = new elna::boot::if_statement(elna::boot::make_position(@1), then, _else); $$ = new boot::if_statement(boot::make_position(@1), then, _else);
std::swap($5, $$->branches); std::swap($5, $$->branches);
} }
return_statement: "return" expression 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" 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); std::swap($2, $$->statements);
} }
literal: literal:
INTEGER 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 | 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 | FLOAT
{ {
$$ = new elna::boot::literal<double>(elna::boot::make_position(@1), $1); $$ = new boot::literal<double>(boot::make_position(@1), $1);
} }
| BOOLEAN | BOOLEAN
{ {
$$ = new elna::boot::literal<bool>(elna::boot::make_position(@1), $1); $$ = new boot::literal<bool>(boot::make_position(@1), $1);
} }
| CHARACTER | 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" | "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 | 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: traits_expression:
TRAIT "(" type_expressions ")" 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); std::swap($3, $$->parameters);
} }
qualident: qualident:
@ -342,99 +346,82 @@ expression:
binary_expression: binary_expression:
expression "*" expression expression "*" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::multiplication);
elna::boot::binary_operator::multiplication);
} }
| expression "/" expression | expression "/" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::division);
elna::boot::binary_operator::division);
} }
| expression "%" expression | expression "%" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::remainder);
elna::boot::binary_operator::remainder);
} }
| expression "+" expression | expression "+" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::sum);
elna::boot::binary_operator::sum);
} }
| expression "-" expression | expression "-" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::subtraction);
elna::boot::binary_operator::subtraction);
} }
| expression "=" expression | expression "=" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::equals);
elna::boot::binary_operator::equals);
} }
| expression "<>" expression | expression "<>" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::not_equals);
elna::boot::binary_operator::not_equals);
} }
| expression "<" expression | expression "<" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::less);
elna::boot::binary_operator::less);
} }
| expression ">" expression | expression ">" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater);
elna::boot::binary_operator::greater);
} }
| expression "<=" expression | expression "<=" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3,
elna::boot::binary_operator::less_equal); boot::binary_operator::less_equal);
} }
| expression ">=" expression | expression ">=" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater_equal);
elna::boot::binary_operator::greater_equal);
} }
| expression "&" expression | expression "&" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::conjunction);
elna::boot::binary_operator::conjunction);
} }
| expression "|" expression | expression "|" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::disjunction);
elna::boot::binary_operator::disjunction);
} }
| expression "xor" expression | expression "xor" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3,
elna::boot::binary_operator::exclusive_disjunction); boot::binary_operator::exclusive_disjunction);
} }
| expression "<<" expression | expression "<<" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_left);
elna::boot::binary_operator::shift_left);
} }
| expression ">>" expression | expression ">>" expression
{ {
$$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_right);
elna::boot::binary_operator::shift_right);
} }
unary_expression: unary_expression:
"@" operand "@" operand
{ {
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2, $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::reference);
elna::boot::unary_operator::reference);
} }
| "~" operand | "~" operand
{ {
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2, $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::negation);
elna::boot::unary_operator::negation);
} }
| "-" operand | "-" operand
{ {
$$ = new elna::boot::unary_expression(elna::boot::make_position(@1), $2, $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::minus);
elna::boot::unary_operator::minus);
} }
expressions: expressions:
expression "," expressions expression "," expressions
@ -453,19 +440,19 @@ type_expressions:
designator_expression: designator_expression:
qualident "[" 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 | 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 "^" | qualident "^"
{ {
$$ = new elna::boot::dereference_expression(elna::boot::make_position(@1), $1); $$ = new boot::dereference_expression(boot::make_position(@1), $1);
} }
| IDENTIFIER | IDENTIFIER
{ {
$$ = new elna::boot::variable_expression(elna::boot::make_position(@1), $1); $$ = new boot::variable_expression(boot::make_position(@1), $1);
} }
statement: statement:
assign_statement { $$ = $1; } assign_statement { $$ = $1; }
@ -497,37 +484,37 @@ optional_fields:
type_expression: type_expression:
"[" INTEGER "]" 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 | "^" 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" | "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" | "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 | "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::move($5));
std::swap(result->parameters, $3); std::swap(result->parameters, $3);
$$ = result; $$ = result;
} }
| IDENTIFIER | 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 variable_declaration: identifier_definitions ":" type_expression
{ {
for (const std::pair<std::string, bool>& identifier : $1) for (const std::pair<std::string, bool>& identifier : $1)
{ {
elna::boot::variable_declaration *declaration = new elna::boot::variable_declaration( boot::variable_declaration *declaration = new boot::variable_declaration(
elna::boot::make_position(@2), identifier.first, $3, identifier.second); boot::make_position(@2), identifier.first, $3, identifier.second);
$$.push_back(declaration); $$.push_back(declaration);
} }
} }
@ -544,7 +531,7 @@ variable_part:
| "var" variable_declarations { std::swap($$, $2); } | "var" variable_declarations { std::swap($$, $2); }
constant_definition: identifier_definition "=" literal 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_definitions:
constant_definition constant_definitions constant_definition constant_definitions
@ -558,7 +545,7 @@ constant_part:
| "const" constant_definitions { std::swap($$, $2); } | "const" constant_definitions { std::swap($$, $2); }
type_definition: identifier_definition "=" type_expression 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_definitions:
type_definition 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) 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,9 +229,20 @@ namespace elna::gcc
tree cast_target = this->current_expression; tree cast_target = this->current_expression;
expression->value().accept(this); expression->value().accept(this);
tree cast_source = TREE_TYPE(this->current_expression);
this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR, if ((is_primitive_type(cast_target) || is_pointer_type(cast_target))
cast_target, this->current_expression); && (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) void generic_visitor::visit(boot::program *program)

View File

@ -35,7 +35,7 @@ namespace elna::gcc
bool is_integral_type(tree type) bool is_integral_type(tree type)
{ {
gcc_assert(TYPE_P(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) bool is_numeric_type(tree type)
@ -43,6 +43,14 @@ namespace elna::gcc
return is_integral_type(type) || type == elna_float_type_node; 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) bool is_array_type(tree type)
{ {
gcc_assert(TYPE_P(type)); gcc_assert(TYPE_P(type));

View File

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