Implement case statements

This commit is contained in:
Eugen Wissner 2025-04-10 23:55:56 +02:00
parent 18c4e79012
commit d01f36cc1a
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
8 changed files with 96 additions and 24 deletions

View File

@ -141,7 +141,7 @@ along with GCC; see the file COPYING3. If not see
%type <elna::boot::unary_expression *> unary_expression; %type <elna::boot::unary_expression *> unary_expression;
%type <elna::boot::binary_expression *> binary_expression; %type <elna::boot::binary_expression *> binary_expression;
%type <std::vector<elna::boot::expression *>> expressions actual_parameter_list; %type <std::vector<elna::boot::expression *>> expressions actual_parameter_list;
%type <elna::boot::designator_expression *> designator_expression; %type <elna::boot::designator_expression *> designator_expression dereference_expression;
%type <elna::boot::procedure_call*> call_expression; %type <elna::boot::procedure_call*> call_expression;
%type <elna::boot::while_statement *> while_statement; %type <elna::boot::while_statement *> while_statement;
%type <elna::boot::if_statement *> if_statement; %type <elna::boot::if_statement *> if_statement;
@ -324,6 +324,10 @@ literal:
{ {
$$ = new boot::literal<std::string>(boot::make_position(@1), $1); $$ = new boot::literal<std::string>(boot::make_position(@1), $1);
} }
| IDENTIFIER
{
$$ = new boot::variable_expression(boot::make_position(@1), $1);
}
traits_expression: traits_expression:
TRAIT "(" type_expressions ")" TRAIT "(" type_expressions ")"
{ {
@ -332,7 +336,7 @@ traits_expression:
} }
simple_expression: simple_expression:
literal { $$ = $1; } literal { $$ = $1; }
| designator_expression { $$ = $1; } | dereference_expression { $$ = $1; }
| traits_expression { $$ = $1; } | traits_expression { $$ = $1; }
| cast_expression { $$ = $1; } | cast_expression { $$ = $1; }
| call_expression { $$ = $1; } | call_expression { $$ = $1; }
@ -437,16 +441,18 @@ type_expressions:
$$.emplace($$.cbegin(), $1); $$.emplace($$.cbegin(), $1);
} }
| type_expression { $$.push_back($1); } | type_expression { $$.push_back($1); }
designator_expression: dereference_expression:
simple_expression "[" expression "]" simple_expression "[" expression "]"
{ {
$$ = new boot::array_access_expression(boot::make_position(@2), $1, $3); $$ = new boot::array_access_expression(boot::make_position(@2), $1, $3);
} }
| qualident { $$ = $1; } | qualident { $$ = $1; }
| simple_expression "^" | simple_expression "^"
{ {
$$ = new boot::dereference_expression(boot::make_position(@1), $1); $$ = new boot::dereference_expression(boot::make_position(@1), $1);
} }
designator_expression:
dereference_expression { $$ = $1; }
| IDENTIFIER | IDENTIFIER
{ {
$$ = new boot::variable_expression(boot::make_position(@1), $1); $$ = new boot::variable_expression(boot::make_position(@1), $1);

View File

@ -292,6 +292,16 @@ namespace elna::boot
return nullptr; return nullptr;
} }
std::shared_ptr<constant_info> info::is_constant()
{
return nullptr;
}
std::shared_ptr<variable_info> info::is_variable()
{
return nullptr;
}
type_info::type_info(const type symbol) type_info::type_info(const type symbol)
: symbol(symbol) : symbol(symbol)
{ {
@ -317,6 +327,21 @@ namespace elna::boot
{ {
} }
std::shared_ptr<constant_info> constant_info::is_constant()
{
return std::static_pointer_cast<constant_info>(shared_from_this());
}
variable_info::variable_info(const std::string& name, const type symbol)
: name(name), symbol(symbol)
{
}
std::shared_ptr<variable_info> variable_info::is_variable()
{
return std::static_pointer_cast<variable_info>(shared_from_this());;
}
std::shared_ptr<symbol_table> builtin_symbol_table() std::shared_ptr<symbol_table> builtin_symbol_table()
{ {
auto result = std::make_shared<symbol_table>(); auto result = std::make_shared<symbol_table>();

View File

@ -138,7 +138,7 @@ namespace elna::gcc
location_t argument_location = get_location(&argument->position()); location_t argument_location = get_location(&argument->position());
if (VOID_TYPE_P(TREE_VALUE(current_parameter))) if (VOID_TYPE_P(TREE_VALUE(current_parameter)))
{ {
error_at(argument_location, "too many arguments, expected %i, got %lu", error_at(argument_location, "Too many arguments, expected %i, got %lu",
list_length(TYPE_ARG_TYPES(symbol_type)) - 1, arguments.size()); list_length(TYPE_ARG_TYPES(symbol_type)) - 1, arguments.size());
this->current_expression = error_mark_node; this->current_expression = error_mark_node;
break; break;
@ -182,7 +182,7 @@ namespace elna::gcc
if (is_void_type(record_fields)) if (is_void_type(record_fields))
{ {
error_at(argument_location, "too many arguments, expected %i, got %lu", error_at(argument_location, "Too many arguments, expected %i, got %lu",
list_length(TYPE_FIELDS(symbol)), arguments.size()); list_length(TYPE_FIELDS(symbol)), arguments.size());
this->current_expression = error_mark_node; this->current_expression = error_mark_node;
break; break;
@ -767,6 +767,11 @@ namespace elna::gcc
location_t definition_location = get_location(&definition->position()); location_t definition_location = get_location(&definition->position());
definition->body().accept(this); definition->body().accept(this);
if (!extract_constant(definition_location))
{
this->current_expression = NULL_TREE;
return;
}
tree definition_tree = build_decl(definition_location, CONST_DECL, tree definition_tree = build_decl(definition_location, CONST_DECL,
get_identifier(definition->identifier.c_str()), TREE_TYPE(this->current_expression)); get_identifier(definition->identifier.c_str()), TREE_TYPE(this->current_expression));
auto result = this->symbols->enter(definition->identifier, definition_tree); auto result = this->symbols->enter(definition->identifier, definition_tree);
@ -1419,9 +1424,18 @@ namespace elna::gcc
void generic_visitor::visit(boot::case_statement *statement) void generic_visitor::visit(boot::case_statement *statement)
{ {
statement->condition().accept(this); statement->condition().accept(this);
tree condition_expression = this->current_expression; tree condition_expression = this->current_expression;
tree end_label_declaration = create_artificial_label(UNKNOWN_LOCATION); tree unqualified_condition = get_qualified_type(TREE_TYPE(this->current_expression), TYPE_UNQUALIFIED);
if (!INTEGRAL_TYPE_P(unqualified_condition))
{
error_at(get_location(&statement->condition().position()),
"Case expressions can only be integral numbers, characters and enumerations, given '%s'",
print_type(unqualified_condition).c_str());
this->current_expression = NULL_TREE;
return;
}
tree end_label_declaration = create_artificial_label(get_location(&statement->position()));
tree switch_statements = alloc_stmt_list(); tree switch_statements = alloc_stmt_list();
for (const boot::switch_case& case_block : statement->cases) for (const boot::switch_case& case_block : statement->cases)
@ -1429,7 +1443,17 @@ namespace elna::gcc
for (boot::literal_expression *const case_label : case_block.labels) for (boot::literal_expression *const case_label : case_block.labels)
{ {
case_label->accept(this); case_label->accept(this);
tree case_label_declaration = create_artificial_label(get_location(&case_label->position())); location_t case_location = get_location(&case_label->position());
if (extract_constant(case_location)
&& !is_assignable_from(unqualified_condition, this->current_expression))
{
error_at(case_location, "Case type '%s' does not match the expression type '%s'",
print_type(TREE_TYPE(this->current_expression)).c_str(),
print_type(unqualified_condition).c_str());
this->current_expression = error_mark_node;
}
tree case_label_declaration = create_artificial_label(case_location);
tree case_expression = build_case_label(this->current_expression, NULL_TREE, case_label_declaration); tree case_expression = build_case_label(this->current_expression, NULL_TREE, case_label_declaration);
append_to_statement_list(case_expression, &switch_statements); append_to_statement_list(case_expression, &switch_statements);
@ -1452,4 +1476,19 @@ namespace elna::gcc
this->current_expression = NULL_TREE; this->current_expression = NULL_TREE;
} }
bool generic_visitor::extract_constant(location_t expression_location)
{
if (TREE_CODE(this->current_expression) == CONST_DECL)
{
this->current_expression = DECL_INITIAL(this->current_expression);
}
if (TREE_CONSTANT(this->current_expression) == 0)
{
error_at(expression_location, "Expected a constant expression");
this->current_expression = error_mark_node;
return false;
}
return true;
}
} }

View File

@ -37,14 +37,6 @@ 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));
@ -59,9 +51,7 @@ namespace elna::gcc
bool is_castable_type(tree type) bool is_castable_type(tree type)
{ {
gcc_assert(TYPE_P(type)); gcc_assert(TYPE_P(type));
auto code = TREE_CODE(type); return INTEGRAL_TYPE_P(type) || POINTER_TYPE_P(type) || TREE_CODE(type) == REAL_TYPE;
return is_primitive_type(type) || POINTER_TYPE_P(type) || code == ENUMERAL_TYPE;
} }
bool are_compatible_pointers(tree lhs_type, tree rhs) bool are_compatible_pointers(tree lhs_type, tree rhs)

View File

@ -483,7 +483,7 @@ namespace elna::boot
designator_expression(); designator_expression();
}; };
class variable_expression : public designator_expression class variable_expression : public designator_expression, public literal_expression
{ {
public: public:
const std::string name; const std::string name;

View File

@ -155,6 +155,7 @@ namespace elna::boot
class type_info; class type_info;
class procedure_info; class procedure_info;
class constant_info; class constant_info;
class variable_info;
class info : public std::enable_shared_from_this<info> class info : public std::enable_shared_from_this<info>
{ {
@ -163,6 +164,8 @@ namespace elna::boot
virtual std::shared_ptr<type_info> is_type(); virtual std::shared_ptr<type_info> is_type();
virtual std::shared_ptr<procedure_info> is_procedure(); virtual std::shared_ptr<procedure_info> is_procedure();
virtual std::shared_ptr<constant_info> is_constant();
virtual std::shared_ptr<variable_info> is_variable();
}; };
class type_info : public info class type_info : public info
@ -171,7 +174,6 @@ namespace elna::boot
const type symbol; const type symbol;
explicit type_info(const type symbol); explicit type_info(const type symbol);
std::shared_ptr<type_info> is_type() override; std::shared_ptr<type_info> is_type() override;
}; };
@ -182,7 +184,6 @@ namespace elna::boot
const std::vector<std::string> names; const std::vector<std::string> names;
procedure_info(const procedure_type symbol, const std::vector<std::string> names); procedure_info(const procedure_type symbol, const std::vector<std::string> names);
std::shared_ptr<procedure_info> is_procedure() override; std::shared_ptr<procedure_info> is_procedure() override;
}; };
@ -195,6 +196,17 @@ namespace elna::boot
const variant symbol; const variant symbol;
explicit constant_info(const variant& symbol); explicit constant_info(const variant& symbol);
std::shared_ptr<constant_info> is_constant() override;
};
class variable_info : public info
{
public:
const std::string name;
const type symbol;
variable_info(const std::string& name, const type symbol);
std::shared_ptr<variable_info> is_variable() override;
}; };
/** /**

View File

@ -70,6 +70,7 @@ namespace elna::gcc
bool expect_trait_type_only(boot::traits_expression *trait); bool expect_trait_type_only(boot::traits_expression *trait);
bool expect_trait_for_integral_type(boot::traits_expression *trait); bool expect_trait_for_integral_type(boot::traits_expression *trait);
void visit_statements(const std::vector<boot::statement *>& statements); void visit_statements(const std::vector<boot::statement *>& statements);
bool extract_constant(location_t expression_location);
public: public:
generic_visitor(std::shared_ptr<symbol_table> symbol_table, generic_visitor(std::shared_ptr<symbol_table> symbol_table,

View File

@ -35,7 +35,6 @@ namespace elna::gcc
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);