Use colon instead of as to cast
This commit is contained in:
		
							
								
								
									
										22
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								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 | Flex and bison grammar specifications, `lexer.ll` and `parser.yy`, can be found | ||||||
| in the `boot/` directory. | 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`. | ||||||
|   | |||||||
							
								
								
									
										110
									
								
								boot/ast.cc
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								boot/ast.cc
									
									
									
									
									
								
							| @@ -61,7 +61,7 @@ namespace boot | |||||||
|         expression->value().accept(this); |         expression->value().accept(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void empty_visitor::visit(size_of_expression *expression) |     void empty_visitor::visit(type_expression *expression) | ||||||
|     { |     { | ||||||
|         expression->body().accept(this); |         expression->body().accept(this); | ||||||
|     } |     } | ||||||
| @@ -152,21 +152,21 @@ namespace boot | |||||||
|         expression->operand().accept(this); |         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); |         expression->base().accept(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void empty_visitor::visit(pointer_type_expression *expression) |     void empty_visitor::visit(pointer_type *expression) | ||||||
|     { |     { | ||||||
|         expression->base().accept(this); |         expression->base().accept(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void empty_visitor::visit(record_type_expression *expression) |     void empty_visitor::visit(record_type *expression) | ||||||
|     { |     { | ||||||
|         for (auto& field : expression->fields) |         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) |         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) |         : node(position) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     basic_type_expression *type_expression::is_basic() |     basic_type *top_type::is_basic() | ||||||
|     { |     { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     array_type_expression *type_expression::is_array() |     array_type *top_type::is_array() | ||||||
|     { |     { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     record_type_expression *type_expression::is_record() |     record_type *top_type::is_record() | ||||||
|     { |     { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     union_type_expression *type_expression::is_union() |     union_type *top_type::is_union() | ||||||
|     { |     { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pointer_type_expression *type_expression::is_pointer() |     pointer_type *top_type::is_pointer() | ||||||
|     { |     { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     basic_type_expression::basic_type_expression( |     basic_type::basic_type(const struct position position, const std::string& name) | ||||||
|             const struct position position, const std::string& name) |         : top_type(position), m_name(name) | ||||||
|         : type_expression(position), m_name(name) |  | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void basic_type_expression::accept(parser_visitor *visitor) |     void basic_type::accept(parser_visitor *visitor) | ||||||
|     { |     { | ||||||
|         visitor->visit(this); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const std::string& basic_type_expression::base_name() |     const std::string& basic_type::base_name() | ||||||
|     { |     { | ||||||
|         return m_name; |         return m_name; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     basic_type_expression *basic_type_expression::is_basic() |     basic_type *basic_type::is_basic() | ||||||
|     { |     { | ||||||
|         return this; |         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) |             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); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_expression& array_type_expression::base() |     top_type& array_type::base() | ||||||
|     { |     { | ||||||
|         return *m_base; |         return *m_base; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     array_type_expression *array_type_expression::is_array() |     array_type*array_type::is_array() | ||||||
|     { |     { | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     array_type_expression::~array_type_expression() |     array_type::~array_type() | ||||||
|     { |     { | ||||||
|         delete m_base; |         delete m_base; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pointer_type_expression::pointer_type_expression(const struct position position, type_expression *base) |     pointer_type::pointer_type(const struct position position, top_type *base) | ||||||
|         : type_expression(position), m_base(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); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_expression& pointer_type_expression::base() |     top_type& pointer_type::base() | ||||||
|     { |     { | ||||||
|         return *m_base; |         return *m_base; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pointer_type_expression *pointer_type_expression::is_pointer() |     pointer_type *pointer_type::is_pointer() | ||||||
|     { |     { | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pointer_type_expression::~pointer_type_expression() |     pointer_type::~pointer_type() | ||||||
|     { |     { | ||||||
|         delete m_base; |         delete m_base; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     composite_type_expression::composite_type_expression(const struct position position, |     composite_type::composite_type(const struct position position, fields_t&& fields) | ||||||
|             fields_t&& fields) |         : top_type(position), fields(std::move(fields)) | ||||||
|         : type_expression(position), fields(std::move(fields)) |  | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     composite_type_expression::~composite_type_expression() |     composite_type::~composite_type() | ||||||
|     { |     { | ||||||
|         for (auto& field_declaration : fields) |         for (auto& field_declaration : fields) | ||||||
|         { |         { | ||||||
| @@ -366,40 +364,38 @@ namespace boot | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     record_type_expression::record_type_expression(const struct position position, |     record_type::record_type(const struct position position, fields_t&& fields) | ||||||
|             fields_t&& fields) |         : composite_type(position, std::move(fields)) | ||||||
|         : composite_type_expression(position, std::move(fields)) |  | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void record_type_expression::accept(parser_visitor *visitor) |     void record_type::accept(parser_visitor *visitor) | ||||||
|     { |     { | ||||||
|         visitor->visit(this); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     record_type_expression *record_type_expression::is_record() |     record_type *record_type::is_record() | ||||||
|     { |     { | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     union_type_expression::union_type_expression(const struct position position, |     union_type::union_type(const struct position position, fields_t&& fields) | ||||||
|             fields_t&& fields) |         : composite_type(position, std::move(fields)) | ||||||
|         : composite_type_expression(position, std::move(fields)) |  | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     union_type_expression *union_type_expression::is_union() |     union_type *union_type::is_union() | ||||||
|     { |     { | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void union_type_expression::accept(parser_visitor *visitor) |     void union_type::accept(parser_visitor *visitor) | ||||||
|     { |     { | ||||||
|         visitor->visit(this); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     variable_declaration::variable_declaration(const struct position position, const std::string& identifier, |     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) |         : definition(position, identifier, exported), m_type(type) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -414,7 +410,7 @@ namespace boot | |||||||
|         visitor->visit(this); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_expression& variable_declaration::type() |     top_type& variable_declaration::variable_type() | ||||||
|     { |     { | ||||||
|         return *m_type; |         return *m_type; | ||||||
|     } |     } | ||||||
| @@ -446,7 +442,7 @@ namespace boot | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     procedure_definition::procedure_definition(const struct position position, const std::string& identifier, |     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) |         : definition(position, identifier, exported), m_return_type(return_type) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -467,7 +463,7 @@ namespace boot | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_expression *procedure_definition::return_type() |     top_type *procedure_definition::return_type() | ||||||
|     { |     { | ||||||
|         return m_return_type; |         return m_return_type; | ||||||
|     } |     } | ||||||
| @@ -485,7 +481,7 @@ namespace boot | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_definition::type_definition(const struct position position, const std::string& identifier, |     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) |         : definition(position, identifier, exported), m_body(body) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -495,7 +491,7 @@ namespace boot | |||||||
|         visitor->visit(this); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_expression& type_definition::body() |     top_type& type_definition::body() | ||||||
|     { |     { | ||||||
|         return *m_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) |         : expression(position), m_target(target), m_value(value) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -786,7 +782,7 @@ namespace boot | |||||||
|         visitor->visit(this); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_expression& cast_expression::target() |     top_type& cast_expression::target() | ||||||
|     { |     { | ||||||
|         return *m_target; |         return *m_target; | ||||||
|     } |     } | ||||||
| @@ -802,22 +798,22 @@ namespace boot | |||||||
|         delete m_value; |         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) |         : expression(position), m_body(body) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void size_of_expression::accept(parser_visitor *visitor) |     void type_expression::accept(parser_visitor *visitor) | ||||||
|     { |     { | ||||||
|         visitor->visit(this); |         visitor->visit(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     type_expression& size_of_expression::body() |     top_type& type_expression::body() | ||||||
|     { |     { | ||||||
|         return *m_body; |         return *m_body; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     size_of_expression::~size_of_expression() |     type_expression::~type_expression() | ||||||
|     { |     { | ||||||
|         delete m_body; |         delete m_body; | ||||||
|     } |     } | ||||||
| @@ -1014,6 +1010,8 @@ namespace boot | |||||||
|                 return "and"; |                 return "and"; | ||||||
|             case binary_operator::disjunction: |             case binary_operator::disjunction: | ||||||
|                 return "or"; |                 return "or"; | ||||||
|  |             case binary_operator::exclusive_disjunction: | ||||||
|  |                 return "xor"; | ||||||
|         } |         } | ||||||
|         __builtin_unreachable(); |         __builtin_unreachable(); | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -122,6 +122,9 @@ nil                     { | |||||||
| and                     { | and                     { | ||||||
|                             return yy::parser::make_AND(this->location); |                             return yy::parser::make_AND(this->location); | ||||||
|                         } |                         } | ||||||
|  | xor                     { | ||||||
|  |                             return yy::parser::make_XOR(this->location); | ||||||
|  |                         } | ||||||
| or                      { | or                      { | ||||||
|                             return yy::parser::make_OR(this->location); |                             return yy::parser::make_OR(this->location); | ||||||
|                         } |                         } | ||||||
| @@ -134,9 +137,6 @@ return                  { | |||||||
| cast                    { | cast                    { | ||||||
|                             return yy::parser::make_CAST(this->location); |                             return yy::parser::make_CAST(this->location); | ||||||
|                         } |                         } | ||||||
| as                      { |  | ||||||
|                             return yy::parser::make_AS(this->location); |  | ||||||
|                         } |  | ||||||
| sizeof                  { | sizeof                  { | ||||||
|                             return yy::parser::make_SIZEOF(this->location); |                             return yy::parser::make_SIZEOF(this->location); | ||||||
|                         } |                         } | ||||||
|   | |||||||
| @@ -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 CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION | ||||||
| %token BEGIN_BLOCK END_BLOCK EXTERN DEFER | %token BEGIN_BLOCK END_BLOCK EXTERN DEFER | ||||||
| %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA | %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 GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS | ||||||
| %token PLUS MINUS MULTIPLICATION DIVISION REMAINDER | %token PLUS MINUS MULTIPLICATION DIVISION REMAINDER | ||||||
| %token ASSIGNMENT COLON HAT AT NIL ARROW | %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 EQUALS NOT_EQUAL LESS_THAN GREATER_THAN LESS_EQUAL GREATER_EQUAL | ||||||
| %left PLUS MINUS | %left PLUS MINUS | ||||||
| %left MULTIPLICATION DIVISION REMAINDER | %left MULTIPLICATION DIVISION REMAINDER | ||||||
| @@ -101,7 +101,7 @@ along with GCC; see the file COPYING3.  If not see | |||||||
| %type <elna::boot::variable_declaration *> variable_declaration; | %type <elna::boot::variable_declaration *> variable_declaration; | ||||||
| %type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part | %type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part | ||||||
|     formal_parameter_list; |     formal_parameter_list; | ||||||
| %type <elna::boot::type_expression *> type_expression; | %type <elna::boot::top_type *> type_expression; | ||||||
| %type <elna::boot::expression *> expression operand unary; | %type <elna::boot::expression *> expression operand unary; | ||||||
| %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; | ||||||
| @@ -117,8 +117,8 @@ along with GCC; see the file COPYING3.  If not see | |||||||
| %type <elna::boot::type_definition *> type_definition; | %type <elna::boot::type_definition *> type_definition; | ||||||
| %type <std::vector<elna::boot::type_definition *>> type_definitions type_part; | %type <std::vector<elna::boot::type_definition *>> type_definitions type_part; | ||||||
| %type <elna::boot::block *> block; | %type <elna::boot::block *> block; | ||||||
| %type <std::pair<std::string, elna::boot::type_expression *>> field_declaration; | %type <std::pair<std::string, elna::boot::top_type *>> field_declaration; | ||||||
| %type <std::vector<std::pair<std::string, elna::boot::type_expression *>>> field_list; | %type <std::vector<std::pair<std::string, elna::boot::top_type *>>> field_list; | ||||||
| %type <std::vector<elna::boot::conditional_statements *>> elsif_statement_list; | %type <std::vector<elna::boot::conditional_statements *>> elsif_statement_list; | ||||||
| %type <elna::boot::cast_expression *> cast_expression; | %type <elna::boot::cast_expression *> cast_expression; | ||||||
| %type <elna::boot::defer_statement *> defer_statement; | %type <elna::boot::defer_statement *> defer_statement; | ||||||
| @@ -189,7 +189,7 @@ call_expression: IDENTIFIER actual_parameter_list | |||||||
|             $$ = new elna::boot::call_expression(elna::boot::make_position(@1), $1); |             $$ = new elna::boot::call_expression(elna::boot::make_position(@1), $1); | ||||||
|             std::swap($$->arguments(), $2); |             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); |             $$ = new elna::boot::cast_expression(elna::boot::make_position(@1), $5, $3); | ||||||
|         } |         } | ||||||
| @@ -265,9 +265,9 @@ literal: | |||||||
| operand: | operand: | ||||||
|     literal { $$ = $1; } |     literal { $$ = $1; } | ||||||
|     | designator_expression { $$ = $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; } |     | cast_expression { $$ = $1; } | ||||||
|     | call_expression { $$ = $1; } |     | call_expression { $$ = $1; } | ||||||
| @@ -339,6 +339,11 @@ expression: | |||||||
|             $$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, |             $$ = new elna::boot::binary_expression(elna::boot::make_position(@2), $1, $3, | ||||||
|                 elna::boot::binary_operator::disjunction); |                 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: | unary: | ||||||
|     AT operand |     AT operand | ||||||
|         { |         { | ||||||
| @@ -403,32 +408,32 @@ optional_statements: | |||||||
| field_declaration: | field_declaration: | ||||||
|     IDENTIFIER COLON type_expression { $$ = std::make_pair($1, $3); } |     IDENTIFIER COLON type_expression { $$ = std::make_pair($1, $3); } | ||||||
| field_list: | field_list: | ||||||
|     field_declaration SEMICOLON field_list |     field_declaration field_list | ||||||
|         { |         { | ||||||
|             std::swap($$, $3); |             std::swap($$, $2); | ||||||
|             $$.emplace($$.cbegin(), $1); |             $$.emplace($$.cbegin(), $1); | ||||||
|         } |         } | ||||||
|     | field_declaration { $$.emplace_back($1); } |     | field_declaration { $$.emplace_back($1); } | ||||||
| type_expression: | type_expression: | ||||||
|     ARRAY INTEGER OF 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 |     | 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 |     | 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 |     | 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 |     | 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 | variable_declaration: identifier_definition COLON type_expression | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -43,6 +43,94 @@ namespace gcc | |||||||
|         this->symbol_map = symbol_table; |         this->symbol_map = symbol_table; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void generic_visitor::build_procedure_call(location_t call_location, | ||||||
|  |             tree symbol, const std::vector<boot::expression *>& arguments) | ||||||
|  |     { | ||||||
|  |         vec<tree, va_gc> *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<boot::expression *>& arguments) | ||||||
|  |     { | ||||||
|  |         vec<constructor_elt, va_gc> *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) |     void generic_visitor::visit(boot::call_expression *expression) | ||||||
|     { |     { | ||||||
|         tree symbol = this->lookup(expression->name()); |         tree symbol = this->lookup(expression->name()); | ||||||
| @@ -56,37 +144,11 @@ namespace gcc | |||||||
|         } |         } | ||||||
|         else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol))) |         else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol))) | ||||||
|         { |         { | ||||||
|             vec<tree, va_gc> *arguments = nullptr; |             build_procedure_call(call_location, symbol, expression->arguments()); | ||||||
|  |  | ||||||
|             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); |         else if (TYPE_P(symbol) && TREE_CODE(symbol) == RECORD_TYPE) | ||||||
|  |  | ||||||
|             if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node) |  | ||||||
|         { |         { | ||||||
|                 append_statement(stmt); |             build_record_call(call_location, symbol, expression->arguments()); | ||||||
|                 this->current_expression = NULL_TREE; |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 this->current_expression = stmt; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else if (TYPE_P(symbol) && is_record_type(symbol)) |  | ||||||
|         { |  | ||||||
|             vec<constructor_elt, va_gc> *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); |  | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
| @@ -107,11 +169,9 @@ namespace gcc | |||||||
|                 cast_target, this->current_expression); |                 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 = build_type(expression->body()); | ||||||
|  |  | ||||||
|         this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, size_in_bytes(body_type)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void generic_visitor::visit(boot::program *program) |     void generic_visitor::visit(boot::program *program) | ||||||
| @@ -185,7 +245,7 @@ namespace gcc | |||||||
|  |  | ||||||
|         for (std::size_t i = 0; i < definition->parameters.size(); ++i) |         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 |         tree return_type = definition->return_type() == nullptr | ||||||
|             ? void_type_node |             ? void_type_node | ||||||
| @@ -315,12 +375,12 @@ namespace gcc | |||||||
|  |  | ||||||
|     void generic_visitor::visit(boot::number_literal<std::int32_t> *literal) |     void generic_visitor::visit(boot::number_literal<std::int32_t> *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<std::uint32_t> *literal) |     void generic_visitor::visit(boot::number_literal<std::uint32_t> *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<double> *literal) |     void generic_visitor::visit(boot::number_literal<double> *literal) | ||||||
| @@ -329,7 +389,7 @@ namespace gcc | |||||||
|  |  | ||||||
|         mpfr_t number; |         mpfr_t number; | ||||||
|         mpfr_init2(number, SIGNIFICAND_BITS); |         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); |         real_from_mpfr(&real_value1, number, double_type_node, MPFR_RNDN); | ||||||
|  |  | ||||||
| @@ -340,12 +400,12 @@ namespace gcc | |||||||
|  |  | ||||||
|     void generic_visitor::visit(boot::number_literal<bool> *boolean) |     void generic_visitor::visit(boot::number_literal<bool> *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<unsigned char> *character) |     void generic_visitor::visit(boot::number_literal<unsigned char> *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<nullptr_t> *) |     void generic_visitor::visit(boot::number_literal<nullptr_t> *) | ||||||
| @@ -355,10 +415,10 @@ namespace gcc | |||||||
|  |  | ||||||
|     void generic_visitor::visit(boot::number_literal<std::string> *string) |     void generic_visitor::visit(boot::number_literal<std::string> *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_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_TYPE(string_literal) = string_type; | ||||||
|         TREE_CONSTANT(string_literal) = 1; |         TREE_CONSTANT(string_literal) = 1; | ||||||
|         TREE_READONLY(string_literal) = 1; |         TREE_READONLY(string_literal) = 1; | ||||||
| @@ -390,11 +450,49 @@ namespace gcc | |||||||
|                 expression, operator_code, left, right, elna_bool_type_node); |                 expression, operator_code, left, right, elna_bool_type_node); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     tree generic_visitor::build_logic_operation(boot::binary_expression *expression, |     tree generic_visitor::build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right) | ||||||
|             tree_code operator_code, tree left, tree right) |  | ||||||
|     { |     { | ||||||
|         return build_binary_operation(TREE_TYPE(left) == elna_bool_type_node, |         location_t expression_location = get_location(&expression->position()); | ||||||
|                 expression, operator_code, left, right, elna_bool_type_node); |         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) |     tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right) | ||||||
| @@ -475,7 +573,9 @@ namespace gcc | |||||||
|             } |             } | ||||||
|             return; |             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, |             error_at(expression_location, | ||||||
|                     "invalid operands of type %s and %s for operator %s", |                     "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); |                 this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right); | ||||||
|                 break; |                 break; | ||||||
|             case boot::binary_operator::conjunction: |             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; |                 break; | ||||||
|             case boot::binary_operator::disjunction: |             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; |                 break; | ||||||
|             case boot::binary_operator::equals: |             case boot::binary_operator::equals: | ||||||
|                 this->current_expression = build_equality_operation(expression, left, right); |                 this->current_expression = build_equality_operation(expression, left, right); | ||||||
| @@ -531,24 +634,48 @@ namespace gcc | |||||||
|     void generic_visitor::visit(boot::unary_expression *expression) |     void generic_visitor::visit(boot::unary_expression *expression) | ||||||
|     { |     { | ||||||
|         expression->operand().accept(this); |         expression->operand().accept(this); | ||||||
|  |         location_t location = get_location(&expression->position()); | ||||||
|  |  | ||||||
|         switch (expression->operation()) |         switch (expression->operation()) | ||||||
|         { |         { | ||||||
|             case boot::unary_operator::reference: |             case boot::unary_operator::reference: | ||||||
|                 TREE_ADDRESSABLE(this->current_expression) = 1; |                 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, |                         this->current_expression, | ||||||
|                         build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true)); |                         build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true)); | ||||||
|                 TREE_NO_TRAMPOLINE(this->current_expression) = 1; |                 TREE_NO_TRAMPOLINE(this->current_expression) = 1; | ||||||
|                 break; |                 break; | ||||||
|             case boot::unary_operator::negation: |             case boot::unary_operator::negation: | ||||||
|                 this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR, |                 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); |                             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; |                 break; | ||||||
|             case boot::unary_operator::minus: |             case boot::unary_operator::minus: | ||||||
|  |                 if (is_integral_type(TREE_TYPE(this->current_expression))) | ||||||
|  |                 { | ||||||
|                     this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression), |                     this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression), | ||||||
|                             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; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void generic_visitor::visit(boot::constant_definition *definition) |     void generic_visitor::visit(boot::constant_definition *definition) | ||||||
| @@ -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()); |             tree symbol = this->lookup(basic_type->base_name()); | ||||||
|  |  | ||||||
| @@ -618,7 +745,7 @@ namespace gcc | |||||||
|  |  | ||||||
|             return error_mark_node; |             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 lower_bound = build_int_cst_type(integer_type_node, 0); | ||||||
|             tree upper_bound = build_int_cst_type(integer_type_node, array_type->size); |             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); |             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()); |             tree base_type = build_type(pointer_type->base()); | ||||||
|  |  | ||||||
| @@ -642,7 +769,7 @@ namespace gcc | |||||||
|             } |             } | ||||||
|             return build_pointer_type_for_mode(base_type, VOIDmode, true); |             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<std::string> field_names; |             std::set<std::string> field_names; | ||||||
|             tree record_type_node = make_node(RECORD_TYPE); |             tree record_type_node = make_node(RECORD_TYPE); | ||||||
| @@ -669,7 +796,7 @@ namespace gcc | |||||||
|  |  | ||||||
|             return record_type_node; |             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<std::string> field_names; |             std::set<std::string> field_names; | ||||||
|             tree union_type_node = make_node(UNION_TYPE); |             tree union_type_node = make_node(UNION_TYPE); | ||||||
| @@ -701,7 +828,7 @@ namespace gcc | |||||||
|  |  | ||||||
|     void generic_visitor::visit(boot::variable_declaration *declaration) |     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); |         gcc_assert(declaration_type != NULL_TREE); | ||||||
|  |  | ||||||
|         location_t declaration_location = get_location(&declaration->position()); |         location_t declaration_location = get_location(&declaration->position()); | ||||||
| @@ -709,6 +836,10 @@ namespace gcc | |||||||
|                 get_identifier(declaration->identifier.c_str()), declaration_type); |                 get_identifier(declaration->identifier.c_str()), declaration_type); | ||||||
|         bool result = this->symbol_map->enter(declaration->identifier, declaration_tree); |         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) |         if (!result) | ||||||
|         { |         { | ||||||
|             error_at(declaration_location, "variable '%s' already declared in this scope", |             error_at(declaration_location, "variable '%s' already declared in this scope", | ||||||
| @@ -795,6 +926,30 @@ namespace gcc | |||||||
|     void generic_visitor::visit(boot::field_access_expression *expression) |     void generic_visitor::visit(boot::field_access_expression *expression) | ||||||
|     { |     { | ||||||
|         expression->base().accept(this); |         expression->base().accept(this); | ||||||
|  |         location_t expression_location = get_location(&expression->position()); | ||||||
|  |  | ||||||
|  |         if (TYPE_P(this->current_expression)) | ||||||
|  |         { | ||||||
|  |             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 if (is_aggregate_type(TREE_TYPE(this->current_expression))) | ||||||
|  |         { | ||||||
|             tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression)); |             tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression)); | ||||||
|  |  | ||||||
|             while (field_declaration != NULL_TREE) |             while (field_declaration != NULL_TREE) | ||||||
| @@ -808,7 +963,6 @@ namespace gcc | |||||||
|                 } |                 } | ||||||
|                 field_declaration = TREE_CHAIN(field_declaration); |                 field_declaration = TREE_CHAIN(field_declaration); | ||||||
|             } |             } | ||||||
|         location_t expression_location = get_location(&expression->position()); |  | ||||||
|             if (field_declaration == NULL_TREE) |             if (field_declaration == NULL_TREE) | ||||||
|             { |             { | ||||||
|                 error_at(expression_location, |                 error_at(expression_location, | ||||||
| @@ -823,6 +977,7 @@ namespace gcc | |||||||
|                         field_declaration, NULL_TREE); |                         field_declaration, NULL_TREE); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     void generic_visitor::visit(boot::dereference_expression *expression) |     void generic_visitor::visit(boot::dereference_expression *expression) | ||||||
|     { |     { | ||||||
| @@ -848,8 +1003,7 @@ namespace gcc | |||||||
|             this->current_expression = error_mark_node; |             this->current_expression = error_mark_node; | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if (TREE_TYPE(this->current_expression) == TREE_TYPE(lvalue) |         if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression)) | ||||||
|                 || are_compatible_pointers(lvalue, this->current_expression)) |  | ||||||
|         { |         { | ||||||
|             tree assignment = build2_loc(statement_location, MODIFY_EXPR, |             tree assignment = build2_loc(statement_location, MODIFY_EXPR, | ||||||
|                     void_type_node, lvalue, this->current_expression); |                     void_type_node, lvalue, this->current_expression); | ||||||
|   | |||||||
| @@ -62,20 +62,27 @@ namespace gcc | |||||||
|         return type == NULL_TREE || type == void_type_node; |         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); |         tree rhs_type = TREE_TYPE(rhs); | ||||||
|  |  | ||||||
|         return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node) |         return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node) | ||||||
|             || (is_pointer_type(lhs_type) && lhs_type == rhs_type); |             || (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) |     void append_statement(tree statement_tree) | ||||||
|     { |     { | ||||||
|         if (!vec_safe_is_empty(f_binding_level->defers)) |         if (!vec_safe_is_empty(f_binding_level->defers)) | ||||||
|   | |||||||
| @@ -41,7 +41,8 @@ namespace boot | |||||||
|         less_equal, |         less_equal, | ||||||
|         greater_equal, |         greater_equal, | ||||||
|         disjunction, |         disjunction, | ||||||
|         conjunction |         conjunction, | ||||||
|  |         exclusive_disjunction | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     enum class unary_operator |     enum class unary_operator | ||||||
| @@ -57,7 +58,7 @@ namespace boot | |||||||
|     class type_definition; |     class type_definition; | ||||||
|     class call_expression; |     class call_expression; | ||||||
|     class cast_expression; |     class cast_expression; | ||||||
|     class size_of_expression; |     class type_expression; | ||||||
|     class assign_statement; |     class assign_statement; | ||||||
|     class if_statement; |     class if_statement; | ||||||
|     class while_statement; |     class while_statement; | ||||||
| @@ -67,11 +68,11 @@ namespace boot | |||||||
|     class program; |     class program; | ||||||
|     class binary_expression; |     class binary_expression; | ||||||
|     class unary_expression; |     class unary_expression; | ||||||
|     class basic_type_expression; |     class basic_type; | ||||||
|     class array_type_expression; |     class array_type; | ||||||
|     class pointer_type_expression; |     class pointer_type; | ||||||
|     class record_type_expression; |     class record_type; | ||||||
|     class union_type_expression; |     class union_type; | ||||||
|     class variable_expression; |     class variable_expression; | ||||||
|     class array_access_expression; |     class array_access_expression; | ||||||
|     class field_access_expression; |     class field_access_expression; | ||||||
| @@ -91,7 +92,7 @@ namespace boot | |||||||
|         virtual void visit(type_definition *) = 0; |         virtual void visit(type_definition *) = 0; | ||||||
|         virtual void visit(call_expression *) = 0; |         virtual void visit(call_expression *) = 0; | ||||||
|         virtual void visit(cast_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(call_statement *) = 0; | ||||||
|         virtual void visit(assign_statement *) = 0; |         virtual void visit(assign_statement *) = 0; | ||||||
|         virtual void visit(if_statement *) = 0; |         virtual void visit(if_statement *) = 0; | ||||||
| @@ -102,11 +103,11 @@ namespace boot | |||||||
|         virtual void visit(program *) = 0; |         virtual void visit(program *) = 0; | ||||||
|         virtual void visit(binary_expression *) = 0; |         virtual void visit(binary_expression *) = 0; | ||||||
|         virtual void visit(unary_expression *) = 0; |         virtual void visit(unary_expression *) = 0; | ||||||
|         virtual void visit(basic_type_expression *) = 0; |         virtual void visit(basic_type *) = 0; | ||||||
|         virtual void visit(array_type_expression *) = 0; |         virtual void visit(array_type *) = 0; | ||||||
|         virtual void visit(pointer_type_expression *) = 0; |         virtual void visit(pointer_type *) = 0; | ||||||
|         virtual void visit(record_type_expression *) = 0; |         virtual void visit(record_type *) = 0; | ||||||
|         virtual void visit(union_type_expression *) = 0; |         virtual void visit(union_type *) = 0; | ||||||
|         virtual void visit(variable_expression *) = 0; |         virtual void visit(variable_expression *) = 0; | ||||||
|         virtual void visit(array_access_expression *) = 0; |         virtual void visit(array_access_expression *) = 0; | ||||||
|         virtual void visit(field_access_expression *is_field_access) = 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(type_definition *definition) override; | ||||||
|         virtual void visit(call_expression *expression) override; |         virtual void visit(call_expression *expression) override; | ||||||
|         virtual void visit(cast_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(call_statement *statement) override; | ||||||
|         virtual void visit(assign_statement *statement) override; |         virtual void visit(assign_statement *statement) override; | ||||||
|         virtual void visit(if_statement *) override; |         virtual void visit(if_statement *) override; | ||||||
| @@ -142,11 +143,11 @@ namespace boot | |||||||
|         virtual void visit(program *program) override; |         virtual void visit(program *program) override; | ||||||
|         virtual void visit(binary_expression *expression) override; |         virtual void visit(binary_expression *expression) override; | ||||||
|         virtual void visit(unary_expression *expression) override; |         virtual void visit(unary_expression *expression) override; | ||||||
|         virtual void visit(basic_type_expression *) override; |         virtual void visit(basic_type *) override; | ||||||
|         virtual void visit(array_type_expression *expression) override; |         virtual void visit(array_type *expression) override; | ||||||
|         virtual void visit(pointer_type_expression *) override; |         virtual void visit(pointer_type *) override; | ||||||
|         virtual void visit(record_type_expression *expression) override; |         virtual void visit(record_type *expression) override; | ||||||
|         virtual void visit(union_type_expression *expression) override; |         virtual void visit(union_type *expression) override; | ||||||
|         virtual void visit(variable_expression *) override; |         virtual void visit(variable_expression *) override; | ||||||
|         virtual void visit(array_access_expression *expression) override; |         virtual void visit(array_access_expression *expression) override; | ||||||
|         virtual void visit(field_access_expression *expression) override; |         virtual void visit(field_access_expression *expression) override; | ||||||
| @@ -217,23 +218,23 @@ namespace boot | |||||||
|     /** |     /** | ||||||
|      * Some type expression. |      * Some type expression. | ||||||
|      */ |      */ | ||||||
|     class type_expression : public node |     class top_type : public node | ||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         virtual basic_type_expression *is_basic(); |         virtual basic_type *is_basic(); | ||||||
|         virtual array_type_expression *is_array(); |         virtual array_type *is_array(); | ||||||
|         virtual pointer_type_expression *is_pointer(); |         virtual pointer_type *is_pointer(); | ||||||
|         virtual record_type_expression *is_record(); |         virtual record_type *is_record(); | ||||||
|         virtual union_type_expression *is_union(); |         virtual union_type *is_union(); | ||||||
|  |  | ||||||
|     protected: |     protected: | ||||||
|         type_expression(const struct position position); |         top_type(const struct position position); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Expression defining a basic type. |      * Expression defining a basic type. | ||||||
|      */ |      */ | ||||||
|     class basic_type_expression final : public type_expression |     class basic_type : public top_type | ||||||
|     { |     { | ||||||
|         const std::string m_name; |         const std::string m_name; | ||||||
|  |  | ||||||
| @@ -242,76 +243,76 @@ namespace boot | |||||||
|          * \param position Source code position. |          * \param position Source code position. | ||||||
|          * \param name Type name. |          * \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; |         virtual void accept(parser_visitor *visitor) override; | ||||||
|  |  | ||||||
|         const std::string& base_name(); |         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: |     public: | ||||||
|         const std::uint32_t size; |         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; |         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: |     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; |         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<std::string, type_expression *>; |     using field_t = std::pair<std::string, top_type *>; | ||||||
|     using fields_t = std::vector<field_t>; |     using fields_t = std::vector<field_t>; | ||||||
|  |  | ||||||
|     class composite_type_expression : public type_expression |     class composite_type : public top_type | ||||||
|     { |     { | ||||||
|     protected: |     protected: | ||||||
|         composite_type_expression(const struct position position, fields_t&& fields); |         composite_type(const struct position position, fields_t&& fields); | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|         fields_t fields; |         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: |     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; |         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: |     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; |         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 |     class variable_declaration : public definition | ||||||
|     { |     { | ||||||
|         type_expression *m_type; |         top_type *m_type; | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|         variable_declaration(const struct position position, const std::string& identifier, |         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; |         virtual void accept(parser_visitor *visitor) override; | ||||||
|  |  | ||||||
|         type_expression& type(); |         top_type& variable_type(); | ||||||
|  |  | ||||||
|         virtual ~variable_declaration() override; |         virtual ~variable_declaration() override; | ||||||
|     }; |     }; | ||||||
| @@ -367,17 +368,17 @@ namespace boot | |||||||
|      */ |      */ | ||||||
|     class procedure_definition : public definition |     class procedure_definition : public definition | ||||||
|     { |     { | ||||||
|         type_expression *m_return_type{ nullptr }; |         top_type *m_return_type{ nullptr }; | ||||||
|         block *m_body{ nullptr }; |         block *m_body{ nullptr }; | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|         std::vector<variable_declaration *> parameters; |         std::vector<variable_declaration *> parameters; | ||||||
|  |  | ||||||
|         procedure_definition(const struct position position, const std::string& identifier, |         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; |         virtual void accept(parser_visitor *visitor) override; | ||||||
|  |  | ||||||
|         type_expression *return_type(); |         top_type *return_type(); | ||||||
|  |  | ||||||
|         block *body(); |         block *body(); | ||||||
|         procedure_definition *add_body(block *procedure_body); |         procedure_definition *add_body(block *procedure_body); | ||||||
| @@ -390,14 +391,14 @@ namespace boot | |||||||
|      */ |      */ | ||||||
|     class type_definition : public definition |     class type_definition : public definition | ||||||
|     { |     { | ||||||
|         type_expression *m_body; |         top_type *m_body; | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|         type_definition(const struct position position, const std::string& identifier, |         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; |         virtual void accept(parser_visitor *visitor) override; | ||||||
|  |  | ||||||
|         type_expression& body(); |         top_type& body(); | ||||||
|  |  | ||||||
|         virtual ~type_definition() override; |         virtual ~type_definition() override; | ||||||
|     }; |     }; | ||||||
| @@ -429,33 +430,33 @@ namespace boot | |||||||
|      */ |      */ | ||||||
|     class cast_expression : public expression |     class cast_expression : public expression | ||||||
|     { |     { | ||||||
|         type_expression *m_target; |         top_type *m_target; | ||||||
|         expression *m_value; |         expression *m_value; | ||||||
|  |  | ||||||
|     public: |     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; |         virtual void accept(parser_visitor *visitor) override; | ||||||
|  |  | ||||||
|         type_expression& target(); |         top_type& target(); | ||||||
|         expression& value(); |         expression& value(); | ||||||
|  |  | ||||||
|         virtual ~cast_expression() override; |         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: |     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; |         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 |     class call_statement : public statement | ||||||
| @@ -662,11 +663,11 @@ namespace boot | |||||||
|     template<typename T> |     template<typename T> | ||||||
|     class number_literal : public literal |     class number_literal : public literal | ||||||
|     { |     { | ||||||
|         T m_value; |  | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|  |         T value; | ||||||
|  |  | ||||||
|         number_literal(const struct position position, const 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); |             visitor->visit(this); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const T& number() const |  | ||||||
|         { |  | ||||||
|             return m_value; |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class defer_statement : public statement |     class defer_statement : public statement | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ namespace gcc | |||||||
|         std::shared_ptr<boot::symbol_table<tree>> symbol_map; |         std::shared_ptr<boot::symbol_table<tree>> symbol_map; | ||||||
|  |  | ||||||
|         tree build_label_decl(const char *name, location_t loc); |         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(); |         void enter_scope(); | ||||||
|         tree leave_scope(); |         tree leave_scope(); | ||||||
| @@ -53,9 +53,12 @@ namespace gcc | |||||||
|                 tree_code operator_code, tree left, tree right); |                 tree_code operator_code, tree left, tree right); | ||||||
|         tree build_comparison_operation(boot::binary_expression *expression, |         tree build_comparison_operation(boot::binary_expression *expression, | ||||||
|                 tree_code operator_code, tree left, tree right); |                 tree_code operator_code, tree left, tree right); | ||||||
|         tree build_logic_operation(boot::binary_expression *expression, |         tree build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right); | ||||||
|                 tree_code operator_code, tree left, tree right); |  | ||||||
|         tree build_equality_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<boot::expression *>& arguments); | ||||||
|  |         void build_record_call(location_t call_location, | ||||||
|  |                 tree symbol, const std::vector<boot::expression *>& arguments); | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|         generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table); |         generic_visitor(std::shared_ptr<boot::symbol_table<tree>> symbol_table); | ||||||
| @@ -64,7 +67,7 @@ namespace gcc | |||||||
|         void visit(boot::procedure_definition *definition) override; |         void visit(boot::procedure_definition *definition) override; | ||||||
|         void visit(boot::call_expression *expression) override; |         void visit(boot::call_expression *expression) override; | ||||||
|         void visit(boot::cast_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<std::int32_t> *literal) override; |         void visit(boot::number_literal<std::int32_t> *literal) override; | ||||||
|         void visit(boot::number_literal<std::uint32_t> *literal) override; |         void visit(boot::number_literal<std::uint32_t> *literal) override; | ||||||
|         void visit(boot::number_literal<double> *literal) override; |         void visit(boot::number_literal<double> *literal) override; | ||||||
|   | |||||||
| @@ -39,14 +39,26 @@ namespace gcc | |||||||
|     bool is_array_type(tree type); |     bool is_array_type(tree type); | ||||||
|     bool is_procedure_type(tree type); |     bool is_procedure_type(tree type); | ||||||
|     bool is_void_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 lhs Left hand value. | ||||||
|      * \param rhs Right hand value. |      * \param rhs Right hand value. | ||||||
|      * \return Whether rhs can be assigned to lhs. |      * \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 append_statement(tree statement_tree); | ||||||
|     void defer(tree statement_tree); |     void defer(tree statement_tree); | ||||||
|   | |||||||
							
								
								
									
										91
									
								
								source.elna
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								source.elna
									
									
									
									
									
								
							| @@ -63,46 +63,46 @@ const | |||||||
|  |  | ||||||
| type | type | ||||||
|   Position* = record |   Position* = record | ||||||
|     line: Word; |     line: Word | ||||||
| 	column: Word | 	column: Word | ||||||
|   end |   end | ||||||
|   Location* = record |   Location* = record | ||||||
|     first: Position; |     first: Position | ||||||
| 	last: Position | 	last: Position | ||||||
|   end |   end | ||||||
|   SourceCode = record |   SourceCode = record | ||||||
|     position: Position; |     position: Position | ||||||
| 	text: String | 	text: String | ||||||
|   end |   end | ||||||
|   TokenValue* = union |   TokenValue* = union | ||||||
|     int_value: Int; |     int_value: Int | ||||||
|     string_value: pointer to Char; |     string_value: pointer to Char | ||||||
|     string: String; |     string: String | ||||||
| 	boolean_value: Bool; | 	boolean_value: Bool | ||||||
| 	char_value: Char | 	char_value: Char | ||||||
|   end |   end | ||||||
|   Token* = record |   Token* = record | ||||||
|     kind: Int; |     kind: Int | ||||||
|     value: TokenValue; |     value: TokenValue | ||||||
| 	location: Location | 	location: Location | ||||||
|   end |   end | ||||||
|   FILE* = record |   FILE* = record | ||||||
|     dummy: Int |     dummy: Int | ||||||
|   end |   end | ||||||
|   CommandLine* = record |   CommandLine* = record | ||||||
|     input: pointer to Char; |     input: pointer to Char | ||||||
| 	tokenize: Bool; | 	tokenize: Bool | ||||||
| 	syntax_tree: Bool | 	syntax_tree: Bool | ||||||
|   end |   end | ||||||
|   Literal* = record |   Literal* = record | ||||||
|     value: Int |     value: Int | ||||||
|   end |   end | ||||||
|   ConstantDefinition* = record |   ConstantDefinition* = record | ||||||
|     name: pointer to Char; |     name: pointer to Char | ||||||
|     body: pointer to Literal |     body: pointer to Literal | ||||||
|   end |   end | ||||||
|   ConstantPart* = record |   ConstantPart* = record | ||||||
|     elements: pointer to pointer to ConstantDefinition; |     elements: pointer to pointer to ConstantDefinition | ||||||
| 	count: Word | 	count: Word | ||||||
|   end |   end | ||||||
|   Program* = record |   Program* = record | ||||||
| @@ -148,12 +148,12 @@ end | |||||||
|  |  | ||||||
| proc write_s(value: String); | proc write_s(value: String); | ||||||
| begin | begin | ||||||
|   write(0, value.ptr, value.length) |   write(0, cast(value.ptr: pointer to Byte), cast(value.length: Int)) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_z(value: pointer to Char); | proc write_z(value: pointer to Char); | ||||||
| begin | begin | ||||||
|   write(0, value, strlen(value)) |   write(0, cast(value: pointer to Byte), cast(strlen(value): Int)) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_b(value: Bool); | proc write_b(value: Bool); | ||||||
| @@ -167,7 +167,7 @@ end | |||||||
|  |  | ||||||
| proc write_c(value: Char); | proc write_c(value: Char); | ||||||
| begin | begin | ||||||
|   write(0, @value, 1) |   write(0, cast(@value: pointer to Byte), 1) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc write_i(value: Int); | proc write_i(value: Int); | ||||||
| @@ -184,7 +184,7 @@ begin | |||||||
|     digit := value % 10; |     digit := value % 10; | ||||||
| 	value := 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 | 	n := n - 1u | ||||||
|   end; |   end; | ||||||
|   while n < 10u do |   while n < 10u do | ||||||
| @@ -195,17 +195,17 @@ end | |||||||
|  |  | ||||||
| proc write_u(value: Word); | proc write_u(value: Word); | ||||||
| begin | begin | ||||||
|   write_i(value) |   write_i(cast(value: Int)) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc is_digit(c: Char) -> Bool; | proc is_digit(c: Char) -> Bool; | ||||||
| begin | 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 | end | ||||||
|  |  | ||||||
| proc is_alpha(c: Char) -> Bool; | proc is_alpha(c: Char) -> Bool; | ||||||
| begin | 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 | end | ||||||
|  |  | ||||||
| proc is_alnum(c: Char) -> Bool; | proc is_alnum(c: Char) -> Bool; | ||||||
| @@ -232,7 +232,7 @@ proc string_dup(origin: String) -> String; | |||||||
| var | var | ||||||
|   copy: pointer to Char; |   copy: pointer to Char; | ||||||
| begin | begin | ||||||
|   copy := cast(malloc(origin.length) as pointer to Char); |   copy := cast(malloc(origin.length): pointer to Char); | ||||||
|   strncpy(copy, origin.ptr, origin.length); |   strncpy(copy, origin.ptr, origin.length); | ||||||
|  |  | ||||||
|   return String(copy, origin.length) |   return String(copy, origin.length) | ||||||
| @@ -246,9 +246,7 @@ proc make_position() -> Position; | |||||||
| var | var | ||||||
|   result: Position; |   result: Position; | ||||||
| begin | begin | ||||||
|   result.line := 1u; |   return Position(1u, 1u) | ||||||
|   result.column := 1u; |  | ||||||
|   return result |  | ||||||
| end | end | ||||||
|  |  | ||||||
| proc read_source(filename: pointer to Char, result: pointer to String) -> Bool; | proc read_source(filename: pointer to Char, result: pointer to String) -> Bool; | ||||||
| @@ -274,12 +272,12 @@ begin | |||||||
|   end; |   end; | ||||||
|   rewind(input_file); |   rewind(input_file); | ||||||
|  |  | ||||||
|   input := malloc(source_size); |   input := malloc(cast(source_size: Word)); | ||||||
|   if fread(input, source_size, 1, input_file) <> 1u then |   if fread(input, cast(source_size: Word), 1u, input_file) <> 1u then | ||||||
|     return false |     return false | ||||||
|   end; |   end; | ||||||
|   result^.length := cast(source_size as Word); |   result^.length := cast(source_size: Word); | ||||||
|   result^.ptr := cast(input as pointer to Char); |   result^.ptr := cast(input: pointer to Char); | ||||||
|  |  | ||||||
|   return true |   return true | ||||||
| end | end | ||||||
| @@ -373,12 +371,12 @@ begin | |||||||
|   while source_code^.text.length > 1u do |   while source_code^.text.length > 1u do | ||||||
|     if source_code^.text[1u] = '*' and source_code^.text[2u] = ')' then |     if source_code^.text[1u] = '*' and source_code^.text[2u] = ')' then | ||||||
| 	  source_code^ := advance_source(source_code^, 2u); | 	  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 | 	  return true | ||||||
| 	end; | 	end; | ||||||
|     content_length := content_length + 1u; |     content_length := content_length + 1u; | ||||||
| 	source_code^ := advance_source(source_code^, 1) | 	source_code^ := advance_source(source_code^, 1u) | ||||||
|   end; |   end; | ||||||
|  |  | ||||||
|   return false |   return false | ||||||
| @@ -413,8 +411,8 @@ begin | |||||||
|   if token_end^ <> '\"' then |   if token_end^ <> '\"' then | ||||||
|     return input |     return input | ||||||
|   end; |   end; | ||||||
|   token_length := cast(token_end - input as Word); |   token_length := cast(token_end - input: Word); | ||||||
|   current_token^.value.string_value := cast(calloc(token_length, 1) as pointer to Char); |   current_token^.value.string_value := cast(calloc(token_length, 1u): pointer to Char); | ||||||
|  |  | ||||||
|   is_valid := true; |   is_valid := true; | ||||||
|   constructed_string := current_token^.value.string_value; |   constructed_string := current_token^.value.string_value; | ||||||
| @@ -565,7 +563,7 @@ begin | |||||||
| 	  write_s("u>") | 	  write_s("u>") | ||||||
| 	elsif current_token^.kind = TOKEN_CHARACTER then | 	elsif current_token^.kind = TOKEN_CHARACTER then | ||||||
| 	  write_c('<'); | 	  write_c('<'); | ||||||
|       write_i(current_token^.value.char_value); |       write_i(cast(current_token^.value.char_value: Int)); | ||||||
| 	  write_s("c>") | 	  write_s("c>") | ||||||
| 	elsif current_token^.kind = TOKEN_STRING then | 	elsif current_token^.kind = TOKEN_STRING then | ||||||
| 	  write_s("\"...\"") | 	  write_s("\"...\"") | ||||||
| @@ -671,7 +669,7 @@ begin | |||||||
|   source_code := skip_spaces(source_code); |   source_code := skip_spaces(source_code); | ||||||
|  |  | ||||||
|   while source_code.text.length <> 0u do |   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^; |     current_token := tokens + tokens_size^; | ||||||
| 	first_char := source_code.text[1u]; | 	first_char := source_code.text[1u]; | ||||||
|  |  | ||||||
| @@ -681,7 +679,7 @@ begin | |||||||
| 	elsif is_digit(first_char) then | 	elsif is_digit(first_char) then | ||||||
| 	  token_end := nil; | 	  token_end := nil; | ||||||
| 	  current_token^.value.int_value := strtol(source_code.text.ptr, @token_end, 10); | 	  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 | 	  if token_end^ = 'u' then | ||||||
| 	    current_token^.kind := TOKEN_WORD; | 	    current_token^.kind := TOKEN_WORD; | ||||||
| @@ -712,7 +710,7 @@ begin | |||||||
| 	  source_code := advance_source(source_code, 1u) | 	  source_code := advance_source(source_code, 1u) | ||||||
| 	elsif first_char = '\'' then | 	elsif first_char = '\'' then | ||||||
| 	  token_end := lex_character(source_code.text.ptr + 1, current_token); | 	  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 | 	  if token_end^ = '\'' then | ||||||
| 	  	current_token^.kind := TOKEN_CHARACTER; | 	  	current_token^.kind := TOKEN_CHARACTER; | ||||||
| @@ -725,7 +723,7 @@ begin | |||||||
|  |  | ||||||
|       if token_end^ = '"' then |       if token_end^ = '"' then | ||||||
| 		current_token^.kind := TOKEN_STRING; | 		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) | 	    source_code := advance_source(source_code, token_length + 1u) | ||||||
| 	  end | 	  end | ||||||
| 	elsif first_char = '[' then | 	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; | proc parse_literal(tokens: pointer to pointer to Token, tokens_size: pointer to Word) -> pointer to Literal; | ||||||
| begin | begin | ||||||
|   return cast(calloc(1, sizeof(Literal)) as pointer to Literal) |   return cast(calloc(1u, Literal.size): pointer to Literal) | ||||||
| end | end | ||||||
|  |  | ||||||
| proc parse_constant_definition(tokens: pointer to pointer to Token, | 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 | var | ||||||
|   result: pointer to ConstantDefinition; |   result: pointer to ConstantDefinition; | ||||||
| begin | 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); |   strcpy(result^.name, tokens^^.value.string_value); | ||||||
|  |  | ||||||
|   tokens^ := tokens^ + 2u; |   tokens^ := tokens^ + 2u; | ||||||
| @@ -855,7 +853,7 @@ var | |||||||
|   result: pointer to Program, |   result: pointer to Program, | ||||||
|   current_constant: pointer to pointer to ConstantDefinition; |   current_constant: pointer to pointer to ConstantDefinition; | ||||||
| begin | 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.elements := nil; | ||||||
|   result^.constants.count := 0u; |   result^.constants.count := 0u; | ||||||
| @@ -866,8 +864,11 @@ begin | |||||||
|  |  | ||||||
| 	while tokens_size^ > 0u and tokens^^.kind = TOKEN_IDENTIFIER do | 	while tokens_size^ > 0u and tokens^^.kind = TOKEN_IDENTIFIER do | ||||||
| 	  result^.constants.elements := cast( | 	  result^.constants.elements := cast( | ||||||
| 	      reallocarray(result^.constants.elements, result^.constants.count + 1u, sizeof(pointer to ConstantDefinition)) | 	      reallocarray( | ||||||
| 		  as pointer to pointer to ConstantDefinition); | 		  	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; |       current_constant := result^.constants.elements + result^.constants.count; | ||||||
|  |  | ||||||
| 	  result^.constants.count := result^.constants.count + 1u; | 	  result^.constants.count := result^.constants.count + 1u; | ||||||
| @@ -887,7 +888,7 @@ var | |||||||
|   result: pointer to CommandLine; |   result: pointer to CommandLine; | ||||||
| begin | begin | ||||||
|   i := 1; |   i := 1; | ||||||
|   result := cast(malloc(sizeof(CommandLine)) as pointer to CommandLine); |   result := cast(malloc(CommandLine.size): pointer to CommandLine); | ||||||
|   result^.tokenize := false; |   result^.tokenize := false; | ||||||
|   result^.syntax_tree := false; |   result^.syntax_tree := false; | ||||||
|   result^.input := nil; |   result^.input := nil; | ||||||
| @@ -950,5 +951,5 @@ begin | |||||||
| end | end | ||||||
|  |  | ||||||
| begin | begin | ||||||
|   exit(process(count, parameters)) |   exit(process(cast(count: Int), cast(parameters: pointer to pointer to Char))) | ||||||
| end. | end. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user