From ee4ebf64b91f991b8f0bbc78b3a211a0daabbded Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 14 Feb 2025 08:05:03 +0100 Subject: [PATCH] Use colon instead of as to cast --- README.md | 22 +++ boot/ast.cc | 110 ++++++----- boot/lexer.ll | 6 +- boot/parser.yy | 35 ++-- gcc/elna-generic.cc | 322 +++++++++++++++++++++++--------- gcc/elna-tree.cc | 15 +- include/elna/boot/ast.h | 150 ++++++++------- include/elna/gcc/elna-generic.h | 11 +- include/elna/gcc/elna-tree.h | 16 +- source.elna | 91 ++++----- 10 files changed, 488 insertions(+), 290 deletions(-) diff --git a/README.md b/README.md index c15d6a2..0c73162 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,25 @@ and a possbility to compile Elna programs for different platforms. Flex and bison grammar specifications, `lexer.ll` and `parser.yy`, can be found in the `boot/` directory. + +## Build + +The frontend requires GCC 14.2.0 (not tested with other versions). + +Download the GCC source. Copy the contents of this repository into `gcc/elna` +inside GCC. Finally build GCC enabling the frontend with +`--enable-languages=c,c++,elna`. After the installation the compiler can be +invoked with `$prefix/bin/gelna`. + +There is also a `Rakefile` that downloads, builds and installs GCC into the +`./build/` subdirectory. The `Rakefile` assumes that ruby and rake, as well as +all GCC dependencies are already available in the system. It works under Linux +and Mac OS. In the latter case GCC is patched with the patches used by Homebrew +(official GCC doesn't support Apple silicon targets). Invoke with + +```sh +rake boot +``` + +See `rake -T` for more tasks. The GCC source is under `build/tools`. The +installation path is `build/host/install`. diff --git a/boot/ast.cc b/boot/ast.cc index 9170485..d023b86 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -61,7 +61,7 @@ namespace boot expression->value().accept(this); } - void empty_visitor::visit(size_of_expression *expression) + void empty_visitor::visit(type_expression *expression) { expression->body().accept(this); } @@ -152,21 +152,21 @@ namespace boot expression->operand().accept(this); } - void empty_visitor::visit(basic_type_expression *) + void empty_visitor::visit(basic_type *) { } - void empty_visitor::visit(array_type_expression *expression) + void empty_visitor::visit(array_type *expression) { expression->base().accept(this); } - void empty_visitor::visit(pointer_type_expression *expression) + void empty_visitor::visit(pointer_type *expression) { expression->base().accept(this); } - void empty_visitor::visit(record_type_expression *expression) + void empty_visitor::visit(record_type *expression) { for (auto& field : expression->fields) { @@ -174,7 +174,7 @@ namespace boot } } - void empty_visitor::visit(union_type_expression *expression) + void empty_visitor::visit(union_type *expression) { for (auto& field : expression->fields) { @@ -250,115 +250,113 @@ namespace boot { } - type_expression::type_expression(const struct position position) + top_type::top_type(const struct position position) : node(position) { } - basic_type_expression *type_expression::is_basic() + basic_type *top_type::is_basic() { return nullptr; } - array_type_expression *type_expression::is_array() + array_type *top_type::is_array() { return nullptr; } - record_type_expression *type_expression::is_record() + record_type *top_type::is_record() { return nullptr; } - union_type_expression *type_expression::is_union() + union_type *top_type::is_union() { return nullptr; } - pointer_type_expression *type_expression::is_pointer() + pointer_type *top_type::is_pointer() { return nullptr; } - basic_type_expression::basic_type_expression( - const struct position position, const std::string& name) - : type_expression(position), m_name(name) + basic_type::basic_type(const struct position position, const std::string& name) + : top_type(position), m_name(name) { } - void basic_type_expression::accept(parser_visitor *visitor) + void basic_type::accept(parser_visitor *visitor) { visitor->visit(this); } - const std::string& basic_type_expression::base_name() + const std::string& basic_type::base_name() { return m_name; } - basic_type_expression *basic_type_expression::is_basic() + basic_type *basic_type::is_basic() { return this; } - array_type_expression::array_type_expression(const struct position position, type_expression *base, + array_type::array_type(const struct position position, top_type *base, const std::uint32_t size) - : type_expression(position), m_base(base), size(size) + : top_type(position), m_base(base), size(size) { } - void array_type_expression::accept(parser_visitor *visitor) + void array_type::accept(parser_visitor *visitor) { visitor->visit(this); } - type_expression& array_type_expression::base() + top_type& array_type::base() { return *m_base; } - array_type_expression *array_type_expression::is_array() + array_type*array_type::is_array() { return this; } - array_type_expression::~array_type_expression() + array_type::~array_type() { delete m_base; } - pointer_type_expression::pointer_type_expression(const struct position position, type_expression *base) - : type_expression(position), m_base(base) + pointer_type::pointer_type(const struct position position, top_type *base) + : top_type(position), m_base(base) { } - void pointer_type_expression::accept(parser_visitor *visitor) + void pointer_type::accept(parser_visitor *visitor) { visitor->visit(this); } - type_expression& pointer_type_expression::base() + top_type& pointer_type::base() { return *m_base; } - pointer_type_expression *pointer_type_expression::is_pointer() + pointer_type *pointer_type::is_pointer() { return this; } - pointer_type_expression::~pointer_type_expression() + pointer_type::~pointer_type() { delete m_base; } - composite_type_expression::composite_type_expression(const struct position position, - fields_t&& fields) - : type_expression(position), fields(std::move(fields)) + composite_type::composite_type(const struct position position, fields_t&& fields) + : top_type(position), fields(std::move(fields)) { } - composite_type_expression::~composite_type_expression() + composite_type::~composite_type() { for (auto& field_declaration : fields) { @@ -366,40 +364,38 @@ namespace boot } } - record_type_expression::record_type_expression(const struct position position, - fields_t&& fields) - : composite_type_expression(position, std::move(fields)) + record_type::record_type(const struct position position, fields_t&& fields) + : composite_type(position, std::move(fields)) { } - void record_type_expression::accept(parser_visitor *visitor) + void record_type::accept(parser_visitor *visitor) { visitor->visit(this); } - record_type_expression *record_type_expression::is_record() + record_type *record_type::is_record() { return this; } - union_type_expression::union_type_expression(const struct position position, - fields_t&& fields) - : composite_type_expression(position, std::move(fields)) + union_type::union_type(const struct position position, fields_t&& fields) + : composite_type(position, std::move(fields)) { } - union_type_expression *union_type_expression::is_union() + union_type *union_type::is_union() { return this; } - void union_type_expression::accept(parser_visitor *visitor) + void union_type::accept(parser_visitor *visitor) { visitor->visit(this); } variable_declaration::variable_declaration(const struct position position, const std::string& identifier, - const bool exported, type_expression *type) + const bool exported, top_type *type) : definition(position, identifier, exported), m_type(type) { } @@ -414,7 +410,7 @@ namespace boot visitor->visit(this); } - type_expression& variable_declaration::type() + top_type& variable_declaration::variable_type() { return *m_type; } @@ -446,7 +442,7 @@ namespace boot } procedure_definition::procedure_definition(const struct position position, const std::string& identifier, - const bool exported, type_expression *return_type) + const bool exported, top_type *return_type) : definition(position, identifier, exported), m_return_type(return_type) { } @@ -467,7 +463,7 @@ namespace boot return this; } - type_expression *procedure_definition::return_type() + top_type *procedure_definition::return_type() { return m_return_type; } @@ -485,7 +481,7 @@ namespace boot } type_definition::type_definition(const struct position position, const std::string& identifier, - const bool exported, type_expression *body) + const bool exported, top_type *body) : definition(position, identifier, exported), m_body(body) { } @@ -495,7 +491,7 @@ namespace boot visitor->visit(this); } - type_expression& type_definition::body() + top_type& type_definition::body() { return *m_body; } @@ -776,7 +772,7 @@ namespace boot } } - cast_expression::cast_expression(const struct position position, type_expression *target, expression *value) + cast_expression::cast_expression(const struct position position, top_type *target, expression *value) : expression(position), m_target(target), m_value(value) { } @@ -786,7 +782,7 @@ namespace boot visitor->visit(this); } - type_expression& cast_expression::target() + top_type& cast_expression::target() { return *m_target; } @@ -802,22 +798,22 @@ namespace boot delete m_value; } - size_of_expression::size_of_expression(const struct position position, type_expression *body) + type_expression::type_expression(const struct position position, top_type *body) : expression(position), m_body(body) { } - void size_of_expression::accept(parser_visitor *visitor) + void type_expression::accept(parser_visitor *visitor) { visitor->visit(this); } - type_expression& size_of_expression::body() + top_type& type_expression::body() { return *m_body; } - size_of_expression::~size_of_expression() + type_expression::~type_expression() { delete m_body; } @@ -1014,6 +1010,8 @@ namespace boot return "and"; case binary_operator::disjunction: return "or"; + case binary_operator::exclusive_disjunction: + return "xor"; } __builtin_unreachable(); }; diff --git a/boot/lexer.ll b/boot/lexer.ll index f0bbe8a..4fc2664 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -122,6 +122,9 @@ nil { and { return yy::parser::make_AND(this->location); } +xor { + return yy::parser::make_XOR(this->location); + } or { return yy::parser::make_OR(this->location); } @@ -134,9 +137,6 @@ return { cast { return yy::parser::make_CAST(this->location); } -as { - return yy::parser::make_AS(this->location); - } sizeof { return yy::parser::make_SIZEOF(this->location); } diff --git a/boot/parser.yy b/boot/parser.yy index f59f8ab..9de5c3b 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -85,12 +85,12 @@ along with GCC; see the file COPYING3. If not see %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION %token BEGIN_BLOCK END_BLOCK EXTERN DEFER %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA -%token AND OR NOT CAST AS SIZEOF +%token AND OR NOT CAST SIZEOF %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS %token PLUS MINUS MULTIPLICATION DIVISION REMAINDER %token ASSIGNMENT COLON HAT AT NIL ARROW -%left OR AND +%left OR AND XOR %left EQUALS NOT_EQUAL LESS_THAN GREATER_THAN LESS_EQUAL GREATER_EQUAL %left PLUS MINUS %left MULTIPLICATION DIVISION REMAINDER @@ -101,7 +101,7 @@ along with GCC; see the file COPYING3. If not see %type variable_declaration; %type > variable_declarations variable_part formal_parameter_list; -%type type_expression; +%type type_expression; %type expression operand unary; %type > expressions actual_parameter_list; %type designator_expression; @@ -117,8 +117,8 @@ along with GCC; see the file COPYING3. If not see %type type_definition; %type > type_definitions type_part; %type block; -%type > field_declaration; -%type >> field_list; +%type > field_declaration; +%type >> field_list; %type > elsif_statement_list; %type cast_expression; %type defer_statement; @@ -189,7 +189,7 @@ call_expression: IDENTIFIER actual_parameter_list $$ = new elna::boot::call_expression(elna::boot::make_position(@1), $1); std::swap($$->arguments(), $2); } -cast_expression: CAST LEFT_PAREN expression AS type_expression RIGHT_PAREN +cast_expression: CAST LEFT_PAREN expression COLON type_expression RIGHT_PAREN { $$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3); } @@ -265,9 +265,9 @@ literal: operand: literal { $$ = $1; } | designator_expression { $$ = $1; } - | SIZEOF LEFT_PAREN type_expression RIGHT_PAREN + | LEFT_PAREN type_expression RIGHT_PAREN { - $$ = new elna::boot::size_of_expression(elna::boot::make_position(@1), $3); + $$ = new elna::boot::type_expression(elna::boot::make_position(@1), $2); } | cast_expression { $$ = $1; } | call_expression { $$ = $1; } @@ -339,6 +339,11 @@ expression: $$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, elna::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); + } unary: AT operand { @@ -403,32 +408,32 @@ optional_statements: field_declaration: IDENTIFIER COLON type_expression { $$ = std::make_pair($1, $3); } field_list: - field_declaration SEMICOLON field_list + field_declaration field_list { - std::swap($$, $3); + std::swap($$, $2); $$.emplace($$.cbegin(), $1); } | field_declaration { $$.emplace_back($1); } type_expression: ARRAY INTEGER OF type_expression { - $$ = new elna::boot::array_type_expression(elna::boot::make_position(@1), $4, $2); + $$ = new elna::boot::array_type(elna::boot::make_position(@1), $4, $2); } | POINTER TO type_expression { - $$ = new elna::boot::pointer_type_expression(elna::boot::make_position(@1), $3); + $$ = new elna::boot::pointer_type(elna::boot::make_position(@1), $3); } | RECORD field_list END_BLOCK { - $$ = new elna::boot::record_type_expression(elna::boot::make_position(@1), std::move($2)); + $$ = new elna::boot::record_type(elna::boot::make_position(@1), std::move($2)); } | UNION field_list END_BLOCK { - $$ = new elna::boot::union_type_expression(elna::boot::make_position(@1), std::move($2)); + $$ = new elna::boot::union_type(elna::boot::make_position(@1), std::move($2)); } | IDENTIFIER { - $$ = new elna::boot::basic_type_expression(elna::boot::make_position(@1), $1); + $$ = new elna::boot::basic_type(elna::boot::make_position(@1), $1); } variable_declaration: identifier_definition COLON type_expression { diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index bd704bc..91abf3d 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -43,6 +43,94 @@ namespace gcc this->symbol_map = symbol_table; } + void generic_visitor::build_procedure_call(location_t call_location, + tree symbol, const std::vector& arguments) + { + vec *argument_trees = nullptr; + tree current_parameter = TYPE_ARG_TYPES(TREE_TYPE(symbol)); + + vec_alloc(argument_trees, arguments.size()); + for (boot::expression *const argument : arguments) + { + location_t argument_location = get_location(&argument->position()); + if (is_void_type(TREE_VALUE(current_parameter))) + { + error_at(argument_location, "too many arguments, expected %i, got %lu", + list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size()); + this->current_expression = error_mark_node; + break; + } + argument->accept(this); + if (!is_assignable_from(TREE_VALUE(current_parameter), this->current_expression)) + { + error_at(argument_location, + "cannot assign value of type '%s' to variable of type '%s'", + print_type(TREE_TYPE(this->current_expression)).c_str(), + print_type(TREE_VALUE(current_parameter)).c_str()); + this->current_expression = error_mark_node; + } + current_parameter = TREE_CHAIN(current_parameter); + argument_trees->quick_push(this->current_expression); + } + tree stmt = build_call_expr_loc_vec(call_location, symbol, argument_trees); + + if (!is_void_type(TREE_VALUE(current_parameter))) + { + error_at(call_location, "too few arguments, expected %i, got %lu", + list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size()); + this->current_expression = error_mark_node; + } + else if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node) + { + append_statement(stmt); + this->current_expression = NULL_TREE; + } + else + { + this->current_expression = stmt; + } + } + + void generic_visitor::build_record_call(location_t call_location, + tree symbol, const std::vector& arguments) + { + vec *tree_arguments = nullptr; + tree record_fields = TYPE_FIELDS(symbol); + for (boot::expression *const argument : arguments) + { + location_t argument_location = get_location(&argument->position()); + + if (is_void_type(record_fields)) + { + error_at(argument_location, "too many arguments, expected %i, got %lu", + list_length(TYPE_FIELDS(symbol)), arguments.size()); + this->current_expression = error_mark_node; + break; + } + argument->accept(this); + if (!is_assignable_from(TREE_TYPE(record_fields), this->current_expression)) + { + error_at(argument_location, + "cannot assign value of type '%s' to variable of type '%s'", + print_type(TREE_TYPE(this->current_expression)).c_str(), + print_type(TREE_TYPE(record_fields)).c_str()); + this->current_expression = error_mark_node; + } + CONSTRUCTOR_APPEND_ELT(tree_arguments, record_fields, this->current_expression); + record_fields = TREE_CHAIN(record_fields); + } + if (!is_void_type(record_fields)) + { + error_at(call_location, "too few arguments, expected %i, got %lu", + list_length(TYPE_FIELDS(symbol)), arguments.size()); + this->current_expression = error_mark_node; + } + else + { + this->current_expression = build_constructor(symbol, tree_arguments); + } + } + void generic_visitor::visit(boot::call_expression *expression) { tree symbol = this->lookup(expression->name()); @@ -56,37 +144,11 @@ namespace gcc } else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol))) { - vec *arguments = nullptr; - - vec_alloc(arguments, expression->arguments().size()); - for (boot::expression *const argument : expression->arguments()) - { - argument->accept(this); - arguments->quick_push(this->current_expression); - } - tree stmt = build_call_expr_loc_vec(get_location(&expression->position()), symbol, arguments); - - if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node) - { - append_statement(stmt); - this->current_expression = NULL_TREE; - } - else - { - this->current_expression = stmt; - } + build_procedure_call(call_location, symbol, expression->arguments()); } - else if (TYPE_P(symbol) && is_record_type(symbol)) + else if (TYPE_P(symbol) && TREE_CODE(symbol) == RECORD_TYPE) { - vec *arguments = nullptr; - tree record_fields = TYPE_FIELDS(symbol); - for (boot::expression *const argument : expression->arguments()) - { - argument->accept(this); - CONSTRUCTOR_APPEND_ELT(arguments, record_fields, this->current_expression); - record_fields = TREE_CHAIN(record_fields); - } - this->current_expression = build_constructor(symbol, arguments); + build_record_call(call_location, symbol, expression->arguments()); } else { @@ -107,11 +169,9 @@ namespace gcc cast_target, this->current_expression); } - void generic_visitor::visit(boot::size_of_expression *expression) + void generic_visitor::visit(boot::type_expression *expression) { - auto body_type = build_type(expression->body()); - - this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, size_in_bytes(body_type)); + this->current_expression = build_type(expression->body()); } void generic_visitor::visit(boot::program *program) @@ -185,7 +245,7 @@ namespace gcc for (std::size_t i = 0; i < definition->parameters.size(); ++i) { - parameter_types[i] = build_type(definition->parameters.at(i)->type()); + parameter_types[i] = build_type(definition->parameters.at(i)->variable_type()); } tree return_type = definition->return_type() == nullptr ? void_type_node @@ -315,12 +375,12 @@ namespace gcc void generic_visitor::visit(boot::number_literal *literal) { - this->current_expression = build_int_cst(elna_int_type_node, literal->number()); + this->current_expression = build_int_cst(elna_int_type_node, literal->value); } void generic_visitor::visit(boot::number_literal *literal) { - this->current_expression = build_int_cstu(elna_word_type_node, literal->number()); + this->current_expression = build_int_cstu(elna_word_type_node, literal->value); } void generic_visitor::visit(boot::number_literal *literal) @@ -329,7 +389,7 @@ namespace gcc mpfr_t number; mpfr_init2(number, SIGNIFICAND_BITS); - mpfr_set_d(number, literal->number(), MPFR_RNDN); + mpfr_set_d(number, literal->value, MPFR_RNDN); real_from_mpfr(&real_value1, number, double_type_node, MPFR_RNDN); @@ -340,12 +400,12 @@ namespace gcc void generic_visitor::visit(boot::number_literal *boolean) { - this->current_expression = boolean->number() ? boolean_true_node : boolean_false_node; + this->current_expression = boolean->value ? boolean_true_node : boolean_false_node; } void generic_visitor::visit(boot::number_literal *character) { - this->current_expression = build_int_cstu(elna_char_type_node, character->number()); + this->current_expression = build_int_cstu(elna_char_type_node, character->value); } void generic_visitor::visit(boot::number_literal *) @@ -355,10 +415,10 @@ namespace gcc void generic_visitor::visit(boot::number_literal *string) { - tree index_constant = build_int_cstu(elna_word_type_node, string->number().size()); + tree index_constant = build_int_cstu(elna_word_type_node, string->value.size()); tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant)); - tree string_literal = build_string(string->number().size(), string->number().c_str()); + tree string_literal = build_string(string->value.size(), string->value.c_str()); TREE_TYPE(string_literal) = string_type; TREE_CONSTANT(string_literal) = 1; TREE_READONLY(string_literal) = 1; @@ -390,11 +450,49 @@ namespace gcc expression, operator_code, left, right, elna_bool_type_node); } - tree generic_visitor::build_logic_operation(boot::binary_expression *expression, - tree_code operator_code, tree left, tree right) + tree generic_visitor::build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right) { - return build_binary_operation(TREE_TYPE(left) == elna_bool_type_node, - expression, operator_code, left, right, elna_bool_type_node); + location_t expression_location = get_location(&expression->position()); + tree left_type = TREE_TYPE(left); + tree right_type = TREE_TYPE(right); + tree_code logical_code, bit_code; + + if (expression->operation() == boot::binary_operator::conjunction) + { + bit_code = BIT_AND_EXPR; + logical_code = TRUTH_ANDIF_EXPR; + } + else if (expression->operation() == boot::binary_operator::disjunction) + { + bit_code = BIT_IOR_EXPR; + logical_code = TRUTH_ORIF_EXPR; + } + else if (expression->operation() == boot::binary_operator::exclusive_disjunction) + { + bit_code = BIT_XOR_EXPR; + logical_code = TRUTH_XOR_EXPR; + } + else + { + gcc_unreachable(); + } + + if (left_type == elna_bool_type_node) + { + return build2_loc(expression_location, logical_code, elna_bool_type_node, left, right); + } + else if (is_integral_type(left_type)) + { + return build2_loc(expression_location, bit_code, left_type, left, right); + } + else + { + error_at(expression_location, + "invalid operands of type '%s' and '%s' for operator %s", + print_type(left_type).c_str(), print_type(right_type).c_str(), + elna::boot::print_binary_operator(expression->operation())); + return error_mark_node; + } } tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right) @@ -475,7 +573,9 @@ namespace gcc } return; } - if (left_type != right_type && !are_compatible_pointers(left, right) && !are_compatible_pointers(right, left)) + if (left_type != right_type + && !are_compatible_pointers(left_type, right) + && !are_compatible_pointers(right_type, left)) { error_at(expression_location, "invalid operands of type %s and %s for operator %s", @@ -514,10 +614,13 @@ namespace gcc this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right); break; case boot::binary_operator::conjunction: - this->current_expression = build_logic_operation(expression, TRUTH_ANDIF_EXPR, left, right); + this->current_expression = build_bit_logic_operation(expression, left, right); break; case boot::binary_operator::disjunction: - this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, left, right); + this->current_expression = build_bit_logic_operation(expression, left, right); + break; + case boot::binary_operator::exclusive_disjunction: + this->current_expression = build_bit_logic_operation(expression, left, right); break; case boot::binary_operator::equals: this->current_expression = build_equality_operation(expression, left, right); @@ -531,23 +634,47 @@ namespace gcc void generic_visitor::visit(boot::unary_expression *expression) { expression->operand().accept(this); + location_t location = get_location(&expression->position()); switch (expression->operation()) { case boot::unary_operator::reference: TREE_ADDRESSABLE(this->current_expression) = 1; - this->current_expression = build_fold_addr_expr_with_type_loc(get_location(&expression->position()), + this->current_expression = build_fold_addr_expr_with_type_loc(location, this->current_expression, build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true)); TREE_NO_TRAMPOLINE(this->current_expression) = 1; break; case boot::unary_operator::negation: - this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR, - boolean_type_node, this->current_expression); + if (TREE_TYPE(this->current_expression) == elna_bool_type_node) + { + this->current_expression = build1_loc(location, TRUTH_NOT_EXPR, + boolean_type_node, this->current_expression); + } + else if (is_integral_type(TREE_TYPE(this->current_expression))) + { + this->current_expression = build1_loc(location, BIT_NOT_EXPR, + TREE_TYPE(this->current_expression), this->current_expression); + } + else + { + error_at(location, "type '%s' cannot be negated", + print_type(TREE_TYPE(this->current_expression)).c_str()); + this->current_expression = error_mark_node; + } break; case boot::unary_operator::minus: - this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression), - this->current_expression); + if (is_integral_type(TREE_TYPE(this->current_expression))) + { + this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression), + this->current_expression); + } + else + { + error_at(location, "type '%s' cannot be negated", + print_type(TREE_TYPE(this->current_expression)).c_str()); + this->current_expression = error_mark_node; + } } } @@ -603,9 +730,9 @@ namespace gcc } } - tree generic_visitor::build_type(boot::type_expression& type) + tree generic_visitor::build_type(boot::top_type& type) { - if (boot::basic_type_expression *basic_type = type.is_basic()) + if (boot::basic_type *basic_type = type.is_basic()) { tree symbol = this->lookup(basic_type->base_name()); @@ -618,7 +745,7 @@ namespace gcc return error_mark_node; } - else if (boot::array_type_expression *array_type = type.is_array()) + else if (boot::array_type *array_type = type.is_array()) { tree lower_bound = build_int_cst_type(integer_type_node, 0); tree upper_bound = build_int_cst_type(integer_type_node, array_type->size); @@ -632,7 +759,7 @@ namespace gcc return build_array_type(base_type, range_type); } - else if (boot::pointer_type_expression *pointer_type = type.is_pointer()) + else if (boot::pointer_type *pointer_type = type.is_pointer()) { tree base_type = build_type(pointer_type->base()); @@ -642,7 +769,7 @@ namespace gcc } return build_pointer_type_for_mode(base_type, VOIDmode, true); } - else if (boot::record_type_expression *record_type = type.is_record()) + else if (boot::record_type *record_type = type.is_record()) { std::set field_names; tree record_type_node = make_node(RECORD_TYPE); @@ -669,7 +796,7 @@ namespace gcc return record_type_node; } - else if (boot::union_type_expression *union_type = type.is_union()) + else if (boot::union_type *union_type = type.is_union()) { std::set field_names; tree union_type_node = make_node(UNION_TYPE); @@ -701,7 +828,7 @@ namespace gcc void generic_visitor::visit(boot::variable_declaration *declaration) { - tree declaration_type = build_type(declaration->type()); + tree declaration_type = build_type(declaration->variable_type()); gcc_assert(declaration_type != NULL_TREE); location_t declaration_location = get_location(&declaration->position()); @@ -709,6 +836,10 @@ namespace gcc get_identifier(declaration->identifier.c_str()), declaration_type); bool result = this->symbol_map->enter(declaration->identifier, declaration_tree); + if (is_pointer_type(declaration_type)) + { + DECL_INITIAL(declaration_tree) = elna_pointer_nil_node; + } if (!result) { error_at(declaration_location, "variable '%s' already declared in this scope", @@ -795,32 +926,56 @@ namespace gcc void generic_visitor::visit(boot::field_access_expression *expression) { expression->base().accept(this); - tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression)); - - while (field_declaration != NULL_TREE) - { - tree declaration_name = DECL_NAME(field_declaration); - const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name); - - if (expression->field() == identifier_pointer) - { - break; - } - field_declaration = TREE_CHAIN(field_declaration); - } location_t expression_location = get_location(&expression->position()); - if (field_declaration == NULL_TREE) + + if (TYPE_P(this->current_expression)) { - error_at(expression_location, - "record type does not have a field named '%s'", - expression->field().c_str()); - this->current_expression = error_mark_node; + if (expression->field() == "size") + { + this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, + size_in_bytes(this->current_expression)); + } + else if (expression->field() == "alignment") + { + this->current_expression = build_int_cstu(elna_word_type_node, + TYPE_ALIGN_UNIT(this->current_expression)); + } + else + { + error_at(expression_location, "type '%s' does not have property '%s'", + print_type(this->current_expression).c_str(), expression->field().c_str()); + this->current_expression = error_mark_node; + } + } - else + else if (is_aggregate_type(TREE_TYPE(this->current_expression))) { - this->current_expression = build3_loc(expression_location, COMPONENT_REF, - TREE_TYPE(field_declaration), this->current_expression, - field_declaration, NULL_TREE); + tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression)); + + while (field_declaration != NULL_TREE) + { + tree declaration_name = DECL_NAME(field_declaration); + const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name); + + if (expression->field() == identifier_pointer) + { + break; + } + field_declaration = TREE_CHAIN(field_declaration); + } + if (field_declaration == NULL_TREE) + { + error_at(expression_location, + "record type does not have a field named '%s'", + expression->field().c_str()); + this->current_expression = error_mark_node; + } + else + { + this->current_expression = build3_loc(expression_location, COMPONENT_REF, + TREE_TYPE(field_declaration), this->current_expression, + field_declaration, NULL_TREE); + } } } @@ -848,8 +1003,7 @@ namespace gcc this->current_expression = error_mark_node; return; } - if (TREE_TYPE(this->current_expression) == TREE_TYPE(lvalue) - || are_compatible_pointers(lvalue, this->current_expression)) + if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression)) { tree assignment = build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, this->current_expression); diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index a51b540..2b7bb0a 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -62,20 +62,27 @@ namespace gcc return type == NULL_TREE || type == void_type_node; } - bool is_record_type(tree type) + bool is_aggregate_type(tree type) { - return TREE_CODE(type) == RECORD_TYPE; + gcc_assert(TYPE_P(type)); + return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE; } - bool are_compatible_pointers(tree lhs, tree rhs) + bool are_compatible_pointers(tree lhs_type, tree rhs) { - tree lhs_type = TREE_TYPE(lhs); + gcc_assert(TYPE_P(lhs_type)); tree rhs_type = TREE_TYPE(rhs); return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node) || (is_pointer_type(lhs_type) && lhs_type == rhs_type); } + bool is_assignable_from(tree assignee, tree assignment) + { + return TREE_TYPE(assignment) == assignee + || are_compatible_pointers(assignee, assignment); + } + void append_statement(tree statement_tree) { if (!vec_safe_is_empty(f_binding_level->defers)) diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 32072fe..10800d2 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -41,7 +41,8 @@ namespace boot less_equal, greater_equal, disjunction, - conjunction + conjunction, + exclusive_disjunction }; enum class unary_operator @@ -57,7 +58,7 @@ namespace boot class type_definition; class call_expression; class cast_expression; - class size_of_expression; + class type_expression; class assign_statement; class if_statement; class while_statement; @@ -67,11 +68,11 @@ namespace boot class program; class binary_expression; class unary_expression; - class basic_type_expression; - class array_type_expression; - class pointer_type_expression; - class record_type_expression; - class union_type_expression; + class basic_type; + class array_type; + class pointer_type; + class record_type; + class union_type; class variable_expression; class array_access_expression; class field_access_expression; @@ -91,7 +92,7 @@ namespace boot virtual void visit(type_definition *) = 0; virtual void visit(call_expression *) = 0; virtual void visit(cast_expression *) = 0; - virtual void visit(size_of_expression *) = 0; + virtual void visit(type_expression *) = 0; virtual void visit(call_statement *) = 0; virtual void visit(assign_statement *) = 0; virtual void visit(if_statement *) = 0; @@ -102,11 +103,11 @@ namespace boot virtual void visit(program *) = 0; virtual void visit(binary_expression *) = 0; virtual void visit(unary_expression *) = 0; - virtual void visit(basic_type_expression *) = 0; - virtual void visit(array_type_expression *) = 0; - virtual void visit(pointer_type_expression *) = 0; - virtual void visit(record_type_expression *) = 0; - virtual void visit(union_type_expression *) = 0; + virtual void visit(basic_type *) = 0; + virtual void visit(array_type *) = 0; + virtual void visit(pointer_type *) = 0; + virtual void visit(record_type *) = 0; + virtual void visit(union_type *) = 0; virtual void visit(variable_expression *) = 0; virtual void visit(array_access_expression *) = 0; virtual void visit(field_access_expression *is_field_access) = 0; @@ -131,7 +132,7 @@ namespace boot virtual void visit(type_definition *definition) override; virtual void visit(call_expression *expression) override; virtual void visit(cast_expression *expression) override; - virtual void visit(size_of_expression *expression) override; + virtual void visit(type_expression *expression) override; virtual void visit(call_statement *statement) override; virtual void visit(assign_statement *statement) override; virtual void visit(if_statement *) override; @@ -142,11 +143,11 @@ namespace boot virtual void visit(program *program) override; virtual void visit(binary_expression *expression) override; virtual void visit(unary_expression *expression) override; - virtual void visit(basic_type_expression *) override; - virtual void visit(array_type_expression *expression) override; - virtual void visit(pointer_type_expression *) override; - virtual void visit(record_type_expression *expression) override; - virtual void visit(union_type_expression *expression) override; + virtual void visit(basic_type *) override; + virtual void visit(array_type *expression) override; + virtual void visit(pointer_type *) override; + virtual void visit(record_type *expression) override; + virtual void visit(union_type *expression) override; virtual void visit(variable_expression *) override; virtual void visit(array_access_expression *expression) override; virtual void visit(field_access_expression *expression) override; @@ -217,23 +218,23 @@ namespace boot /** * Some type expression. */ - class type_expression : public node + class top_type : public node { public: - virtual basic_type_expression *is_basic(); - virtual array_type_expression *is_array(); - virtual pointer_type_expression *is_pointer(); - virtual record_type_expression *is_record(); - virtual union_type_expression *is_union(); + virtual basic_type *is_basic(); + virtual array_type *is_array(); + virtual pointer_type *is_pointer(); + virtual record_type *is_record(); + virtual union_type *is_union(); protected: - type_expression(const struct position position); + top_type(const struct position position); }; /** * Expression defining a basic type. */ - class basic_type_expression final : public type_expression + class basic_type : public top_type { const std::string m_name; @@ -242,76 +243,76 @@ namespace boot * \param position Source code position. * \param name Type name. */ - basic_type_expression(const struct position position, const std::string& name); + basic_type(const struct position position, const std::string& name); virtual void accept(parser_visitor *visitor) override; const std::string& base_name(); - basic_type_expression *is_basic() override; + basic_type *is_basic() override; }; - class array_type_expression final : public type_expression + class array_type : public top_type { - type_expression *m_base; + top_type *m_base; public: const std::uint32_t size; - array_type_expression(const struct position position, type_expression *base, const std::uint32_t size); + array_type(const struct position position, top_type*base, const std::uint32_t size); virtual void accept(parser_visitor *visitor) override; - type_expression& base(); + top_type& base(); - array_type_expression *is_array() override; + array_type *is_array() override; - virtual ~array_type_expression() override; + virtual ~array_type() override; }; - class pointer_type_expression final : public type_expression + class pointer_type : public top_type { - type_expression *m_base; + top_type *m_base; public: - pointer_type_expression(const struct position position, type_expression *base); + pointer_type(const struct position position, top_type *base); virtual void accept(parser_visitor *visitor) override; - type_expression& base(); + top_type& base(); - pointer_type_expression *is_pointer() override; + pointer_type *is_pointer() override; - virtual ~pointer_type_expression() override; + virtual ~pointer_type() override; }; - using field_t = std::pair; + using field_t = std::pair; using fields_t = std::vector; - class composite_type_expression : public type_expression + class composite_type : public top_type { protected: - composite_type_expression(const struct position position, fields_t&& fields); + composite_type(const struct position position, fields_t&& fields); public: fields_t fields; - virtual ~composite_type_expression() override; + virtual ~composite_type() override; }; - class record_type_expression final : public composite_type_expression + class record_type : public composite_type { public: - record_type_expression(const struct position position, fields_t&& fields); + record_type(const struct position position, fields_t&& fields); virtual void accept(parser_visitor *visitor) override; - record_type_expression *is_record() override; + record_type *is_record() override; }; - class union_type_expression final : public composite_type_expression + class union_type : public composite_type { public: - union_type_expression(const struct position position, fields_t&& fields); + union_type(const struct position position, fields_t&& fields); virtual void accept(parser_visitor *visitor) override; - union_type_expression *is_union() override; + union_type *is_union() override; }; /** @@ -319,14 +320,14 @@ namespace boot */ class variable_declaration : public definition { - type_expression *m_type; + top_type *m_type; public: variable_declaration(const struct position position, const std::string& identifier, - const bool exported, type_expression *type); + const bool exported, top_type *type); virtual void accept(parser_visitor *visitor) override; - type_expression& type(); + top_type& variable_type(); virtual ~variable_declaration() override; }; @@ -367,17 +368,17 @@ namespace boot */ class procedure_definition : public definition { - type_expression *m_return_type{ nullptr }; + top_type *m_return_type{ nullptr }; block *m_body{ nullptr }; public: std::vector parameters; procedure_definition(const struct position position, const std::string& identifier, - const bool exported, type_expression *return_type = nullptr); + const bool exported, top_type *return_type = nullptr); virtual void accept(parser_visitor *visitor) override; - type_expression *return_type(); + top_type *return_type(); block *body(); procedure_definition *add_body(block *procedure_body); @@ -390,14 +391,14 @@ namespace boot */ class type_definition : public definition { - type_expression *m_body; + top_type *m_body; public: type_definition(const struct position position, const std::string& identifier, - const bool exported, type_expression *expression); + const bool exported, top_type *expression); virtual void accept(parser_visitor *visitor) override; - type_expression& body(); + top_type& body(); virtual ~type_definition() override; }; @@ -429,33 +430,33 @@ namespace boot */ class cast_expression : public expression { - type_expression *m_target; + top_type *m_target; expression *m_value; public: - cast_expression(const struct position position, type_expression *target, expression *value); + cast_expression(const struct position position, top_type *target, expression *value); virtual void accept(parser_visitor *visitor) override; - type_expression& target(); + top_type& target(); expression& value(); virtual ~cast_expression() override; }; /** - * sizeOf operator. + * Type inside an expression. */ - class size_of_expression : public expression + class type_expression : public expression { - type_expression *m_body; + top_type *m_body; public: - size_of_expression(const struct position position, type_expression *body); + type_expression(const struct position position, top_type *body); virtual void accept(parser_visitor *visitor) override; - type_expression& body(); + top_type& body(); - virtual ~size_of_expression() override; + virtual ~type_expression() override; }; class call_statement : public statement @@ -662,11 +663,11 @@ namespace boot template class number_literal : public literal { - T m_value; - public: + T value; + number_literal(const struct position position, const T& value) - : literal(position), m_value(value) + : literal(position), value(value) { } @@ -674,11 +675,6 @@ namespace boot { visitor->visit(this); } - - const T& number() const - { - return m_value; - } }; class defer_statement : public statement diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 6bd2b4c..638ca07 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -40,7 +40,7 @@ namespace gcc std::shared_ptr> symbol_map; tree build_label_decl(const char *name, location_t loc); - tree build_type(boot::type_expression& type); + tree build_type(boot::top_type& type); void enter_scope(); tree leave_scope(); @@ -53,9 +53,12 @@ namespace gcc tree_code operator_code, tree left, tree right); tree build_comparison_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right); - tree build_logic_operation(boot::binary_expression *expression, - tree_code operator_code, tree left, tree right); + tree build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right); tree build_equality_operation(boot::binary_expression *expression, tree left, tree right); + void build_procedure_call(location_t call_location, + tree symbol, const std::vector& arguments); + void build_record_call(location_t call_location, + tree symbol, const std::vector& arguments); public: generic_visitor(std::shared_ptr> symbol_table); @@ -64,7 +67,7 @@ namespace gcc void visit(boot::procedure_definition *definition) override; void visit(boot::call_expression *expression) override; void visit(boot::cast_expression *expression) override; - void visit(boot::size_of_expression *expression) override; + void visit(boot::type_expression *expression) override; void visit(boot::number_literal *literal) override; void visit(boot::number_literal *literal) override; void visit(boot::number_literal *literal) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index d1970e9..5339135 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -39,14 +39,26 @@ namespace gcc bool is_array_type(tree type); bool is_procedure_type(tree type); bool is_void_type(tree type); - bool is_record_type(tree type); + + /** + * \param type The type to evaluate. + * \return Whether the given type is record or union. + */ + bool is_aggregate_type(tree type); /** * \param lhs Left hand value. * \param rhs Right hand value. * \return Whether rhs can be assigned to lhs. */ - bool are_compatible_pointers(tree lhs, tree rhs); + bool are_compatible_pointers(tree lhs_type, tree rhs); + + /** + * \param assignee Assignee. + * \param assignee Assignment. + * \return Whether an expression assignment can be assigned to a variable of type assignee. + */ + bool is_assignable_from(tree assignee, tree assignment); void append_statement(tree statement_tree); void defer(tree statement_tree); diff --git a/source.elna b/source.elna index 51c6e9c..5c4df3c 100644 --- a/source.elna +++ b/source.elna @@ -63,46 +63,46 @@ const type Position* = record - line: Word; + line: Word column: Word end Location* = record - first: Position; + first: Position last: Position end SourceCode = record - position: Position; + position: Position text: String end TokenValue* = union - int_value: Int; - string_value: pointer to Char; - string: String; - boolean_value: Bool; + int_value: Int + string_value: pointer to Char + string: String + boolean_value: Bool char_value: Char end Token* = record - kind: Int; - value: TokenValue; + kind: Int + value: TokenValue location: Location end FILE* = record dummy: Int end CommandLine* = record - input: pointer to Char; - tokenize: Bool; + input: pointer to Char + tokenize: Bool syntax_tree: Bool end Literal* = record value: Int end ConstantDefinition* = record - name: pointer to Char; + name: pointer to Char body: pointer to Literal end ConstantPart* = record - elements: pointer to pointer to ConstantDefinition; + elements: pointer to pointer to ConstantDefinition count: Word end Program* = record @@ -148,12 +148,12 @@ end proc write_s(value: String); begin - write(0, value.ptr, value.length) + write(0, cast(value.ptr: pointer to Byte), cast(value.length: Int)) end proc write_z(value: pointer to Char); begin - write(0, value, strlen(value)) + write(0, cast(value: pointer to Byte), cast(strlen(value): Int)) end proc write_b(value: Bool); @@ -167,7 +167,7 @@ end proc write_c(value: Char); begin - write(0, @value, 1) + write(0, cast(@value: pointer to Byte), 1) end proc write_i(value: Int); @@ -184,7 +184,7 @@ begin digit := value % 10; value := value / 10; - buffer[n] := cast(cast('0' as Int) + digit as Char); + buffer[n] := cast(cast('0': Int) + digit: Char); n := n - 1u end; while n < 10u do @@ -195,17 +195,17 @@ end proc write_u(value: Word); begin - write_i(value) + write_i(cast(value: Int)) end proc is_digit(c: Char) -> Bool; begin - return cast(c as Int) >= cast('0' as Int) and cast(c as Int) <= cast('9' as Int) + return cast(c: Int) >= cast('0': Int) and cast(c: Int) <= cast('9': Int) end proc is_alpha(c: Char) -> Bool; begin - return cast(c as Int) >= cast('A' as Int) and cast(c as Int) <= cast('z' as Int) + return cast(c: Int) >= cast('A': Int) and cast(c: Int) <= cast('z': Int) end proc is_alnum(c: Char) -> Bool; @@ -232,7 +232,7 @@ proc string_dup(origin: String) -> String; var copy: pointer to Char; begin - copy := cast(malloc(origin.length) as pointer to Char); + copy := cast(malloc(origin.length): pointer to Char); strncpy(copy, origin.ptr, origin.length); return String(copy, origin.length) @@ -246,9 +246,7 @@ proc make_position() -> Position; var result: Position; begin - result.line := 1u; - result.column := 1u; - return result + return Position(1u, 1u) end proc read_source(filename: pointer to Char, result: pointer to String) -> Bool; @@ -274,12 +272,12 @@ begin end; rewind(input_file); - input := malloc(source_size); - if fread(input, source_size, 1, input_file) <> 1u then + input := malloc(cast(source_size: Word)); + if fread(input, cast(source_size: Word), 1u, input_file) <> 1u then return false end; - result^.length := cast(source_size as Word); - result^.ptr := cast(input as pointer to Char); + result^.length := cast(source_size: Word); + result^.ptr := cast(input: pointer to Char); return true end @@ -373,12 +371,12 @@ begin while source_code^.text.length > 1u do if source_code^.text[1u] = '*' and source_code^.text[2u] = ')' then source_code^ := advance_source(source_code^, 2u); - token_content^ := substring(token_content^, 0, content_length); + token_content^ := substring(token_content^, 0u, content_length); return true end; content_length := content_length + 1u; - source_code^ := advance_source(source_code^, 1) + source_code^ := advance_source(source_code^, 1u) end; return false @@ -413,8 +411,8 @@ begin if token_end^ <> '\"' then return input end; - token_length := cast(token_end - input as Word); - current_token^.value.string_value := cast(calloc(token_length, 1) as pointer to Char); + token_length := cast(token_end - input: Word); + current_token^.value.string_value := cast(calloc(token_length, 1u): pointer to Char); is_valid := true; constructed_string := current_token^.value.string_value; @@ -565,7 +563,7 @@ begin write_s("u>") elsif current_token^.kind = TOKEN_CHARACTER then write_c('<'); - write_i(current_token^.value.char_value); + write_i(cast(current_token^.value.char_value: Int)); write_s("c>") elsif current_token^.kind = TOKEN_STRING then write_s("\"...\"") @@ -671,7 +669,7 @@ begin source_code := skip_spaces(source_code); while source_code.text.length <> 0u do - tokens := cast(reallocarray(tokens, tokens_size^ + 1u, sizeof(Token)) as pointer to Token); + tokens := cast(reallocarray(cast(tokens: pointer to Byte), tokens_size^ + 1u, Token.size): pointer to Token); current_token := tokens + tokens_size^; first_char := source_code.text[1u]; @@ -681,7 +679,7 @@ begin elsif is_digit(first_char) then token_end := nil; current_token^.value.int_value := strtol(source_code.text.ptr, @token_end, 10); - token_length := cast(token_end - source_code.text.ptr as Word); + token_length := cast(token_end - source_code.text.ptr: Word); if token_end^ = 'u' then current_token^.kind := TOKEN_WORD; @@ -712,7 +710,7 @@ begin source_code := advance_source(source_code, 1u) elsif first_char = '\'' then token_end := lex_character(source_code.text.ptr + 1, current_token); - token_length := cast(token_end - source_code.text.ptr as Word); + token_length := cast(token_end - source_code.text.ptr: Word); if token_end^ = '\'' then current_token^.kind := TOKEN_CHARACTER; @@ -725,7 +723,7 @@ begin if token_end^ = '"' then current_token^.kind := TOKEN_STRING; - token_length := cast(token_end - source_code.text.ptr as Word); + token_length := cast(token_end - source_code.text.ptr: Word); source_code := advance_source(source_code, token_length + 1u) end elsif first_char = '[' then @@ -823,7 +821,7 @@ end proc parse_literal(tokens: pointer to pointer to Token, tokens_size: pointer to Word) -> pointer to Literal; begin - return cast(calloc(1, sizeof(Literal)) as pointer to Literal) + return cast(calloc(1u, Literal.size): pointer to Literal) end proc parse_constant_definition(tokens: pointer to pointer to Token, @@ -831,9 +829,9 @@ proc parse_constant_definition(tokens: pointer to pointer to Token, var result: pointer to ConstantDefinition; begin - result := cast(calloc(1, sizeof(ConstantDefinition)) as pointer to ConstantDefinition); + result := cast(calloc(1u, ConstantDefinition.size): pointer to ConstantDefinition); - result^.name := cast(malloc(strlen(tokens^^.value.string_value)) as pointer to Char); + result^.name := cast(malloc(strlen(tokens^^.value.string_value)): pointer to Char); strcpy(result^.name, tokens^^.value.string_value); tokens^ := tokens^ + 2u; @@ -855,7 +853,7 @@ var result: pointer to Program, current_constant: pointer to pointer to ConstantDefinition; begin - result := cast(calloc(1, sizeof(Program)) as pointer to Program); + result := cast(calloc(1u, Program.size): pointer to Program); result^.constants.elements := nil; result^.constants.count := 0u; @@ -866,8 +864,11 @@ begin while tokens_size^ > 0u and tokens^^.kind = TOKEN_IDENTIFIER do result^.constants.elements := cast( - reallocarray(result^.constants.elements, result^.constants.count + 1u, sizeof(pointer to ConstantDefinition)) - as pointer to pointer to ConstantDefinition); + reallocarray( + cast(result^.constants.elements: pointer to Byte), + result^.constants.count + 1u, + (pointer to ConstantDefinition).size + ) : pointer to pointer to ConstantDefinition); current_constant := result^.constants.elements + result^.constants.count; result^.constants.count := result^.constants.count + 1u; @@ -887,7 +888,7 @@ var result: pointer to CommandLine; begin i := 1; - result := cast(malloc(sizeof(CommandLine)) as pointer to CommandLine); + result := cast(malloc(CommandLine.size): pointer to CommandLine); result^.tokenize := false; result^.syntax_tree := false; result^.input := nil; @@ -950,5 +951,5 @@ begin end begin - exit(process(count, parameters)) + exit(process(cast(count: Int), cast(parameters: pointer to pointer to Char))) end.