Implement enumeration type
This commit is contained in:
		
							
								
								
									
										67
									
								
								boot/ast.cc
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								boot/ast.cc
									
									
									
									
									
								
							| @@ -103,7 +103,7 @@ namespace elna::boot | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     primitive_type_expression *type_expression::is_primitive() | ||||
|     named_type_expression *type_expression::is_named() | ||||
|     { | ||||
|         return nullptr; | ||||
|     } | ||||
| @@ -133,17 +133,22 @@ namespace elna::boot | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     primitive_type_expression::primitive_type_expression(const struct position position, const std::string& name) | ||||
|     enumeration_type_expression *type_expression::is_enumeration() | ||||
|     { | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     named_type_expression::named_type_expression(const struct position position, const std::string& name) | ||||
|         : type_expression(position), name(name) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void primitive_type_expression::accept(parser_visitor *visitor) | ||||
|     void named_type_expression::accept(parser_visitor *visitor) | ||||
|     { | ||||
|         visitor->visit(this); | ||||
|     } | ||||
|  | ||||
|     primitive_type_expression *primitive_type_expression::is_primitive() | ||||
|     named_type_expression *named_type_expression::is_named() | ||||
|     { | ||||
|         return this; | ||||
|     } | ||||
| @@ -312,6 +317,26 @@ namespace elna::boot | ||||
|         visitor->visit(this); | ||||
|     } | ||||
|  | ||||
|     procedure_type_expression *procedure_type_expression::is_procedure() | ||||
|     { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     enumeration_type_expression::enumeration_type_expression(const struct position position, std::vector<std::string>&& members) | ||||
|         : type_expression(position), members(members) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void enumeration_type_expression::accept(parser_visitor *visitor) | ||||
|     { | ||||
|         visitor->visit(this); | ||||
|     } | ||||
|  | ||||
|     enumeration_type_expression *enumeration_type_expression::is_enumeration() | ||||
|     { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     procedure_definition::procedure_definition(const struct position position, const std::string& identifier, | ||||
|             const bool exported, procedure_type_expression *heading, block *body) | ||||
|         : definition(position, identifier, exported), m_heading(heading), body(body) | ||||
| @@ -323,11 +348,6 @@ namespace elna::boot | ||||
|         visitor->visit(this); | ||||
|     } | ||||
|  | ||||
|     procedure_type_expression *procedure_type_expression::is_procedure() | ||||
|     { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     procedure_type_expression& procedure_definition::heading() | ||||
|     { | ||||
|         return *m_heading; | ||||
| @@ -417,8 +437,8 @@ namespace elna::boot | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     defer_statement::defer_statement(const struct position position) | ||||
|         : node(position) | ||||
|     defer_statement::defer_statement(const struct position position, std::vector<statement *>&& statements) | ||||
|         : node(position), statements(std::move(statements)) | ||||
|     { | ||||
|     } | ||||
|  | ||||
| @@ -754,7 +774,7 @@ namespace elna::boot | ||||
|     } | ||||
|  | ||||
|     return_statement::return_statement(const struct position position, expression *return_expression) | ||||
|         : node(position), m_return_expression(return_expression) | ||||
|         : node(position), return_expression(return_expression) | ||||
|     { | ||||
|     } | ||||
|  | ||||
| @@ -768,14 +788,25 @@ namespace elna::boot | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     expression *return_statement::return_expression() | ||||
|     { | ||||
|         return m_return_expression; | ||||
|     } | ||||
|  | ||||
|     return_statement::~return_statement() | ||||
|     { | ||||
|         delete m_return_expression; | ||||
|         delete this->return_expression; | ||||
|     } | ||||
|  | ||||
|     case_statement::case_statement(const struct position position, | ||||
|             expression *condition, std::vector<switch_case>&& cases) | ||||
|         : node(position), m_condition(condition), cases(std::move(cases)) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void case_statement::accept(parser_visitor *visitor) | ||||
|     { | ||||
|         visitor->visit(this); | ||||
|     } | ||||
|  | ||||
|     expression& case_statement::condition() | ||||
|     { | ||||
|         return *m_condition; | ||||
|     } | ||||
|  | ||||
|     assign_statement::assign_statement(const struct position position, designator_expression *lvalue, | ||||
|   | ||||
| @@ -113,9 +113,12 @@ nil                     { | ||||
| xor                     { | ||||
|                             return yy::parser::make_XOR(this->location); | ||||
|                         } | ||||
| \|                      { | ||||
| or                     { | ||||
|                             return yy::parser::make_OR(this->location); | ||||
|                         } | ||||
| \|                      { | ||||
|                             return yy::parser::make_PIPE(this->location); | ||||
|                         } | ||||
| \~                      { | ||||
|                             return yy::parser::make_NOT(this->location); | ||||
|                         } | ||||
| @@ -128,6 +131,12 @@ cast                    { | ||||
| defer                   { | ||||
|                             return yy::parser::make_DEFER(this->location); | ||||
|                         } | ||||
| case                    { | ||||
|                             return yy::parser::make_CASE(this->location); | ||||
|                         } | ||||
| of                      { | ||||
|                             return yy::parser::make_OF(this->location); | ||||
|                         } | ||||
| [A-Za-z_][A-Za-z0-9_]*  { | ||||
|                             return yy::parser::make_IDENTIFIER(yytext, this->location); | ||||
|                         } | ||||
|   | ||||
| @@ -111,31 +111,37 @@ along with GCC; see the file COPYING3.  If not see | ||||
|     BEGIN_BLOCK "begin" | ||||
|     END_BLOCK "end" | ||||
|     DEFER "defer" | ||||
| %token OR "|" AND "&" XOR "xor" | ||||
|     CASE "case" | ||||
|     OF "of" | ||||
|     PIPE "|" | ||||
| %token OR "or" AND "&" XOR "xor" | ||||
|     EQUALS "=" NOT_EQUAL "<>" LESS_THAN "<" GREATER_THAN ">" LESS_EQUAL "<=" GREATER_EQUAL ">=" | ||||
|     SHIFT_LEFT "<<" SHIFT_RIGHT ">>" | ||||
|     PLUS "+" MINUS "-" | ||||
|     MULTIPLICATION "*" DIVISION "/" REMAINDER "%" | ||||
|  | ||||
| %left "|" "&" "xor" | ||||
| %left "or" "&" "xor" | ||||
| %left "=" "<>" "<" ">" "<=" ">=" | ||||
| %left "<<" ">>" | ||||
| %left "+" "-" | ||||
| %left "*" "/" "%" | ||||
|  | ||||
| %type <elna::boot::literal_expression *> literal; | ||||
| %type <std::vector<elna::boot::literal_expression *>> case_labels; | ||||
| %type <elna::boot::switch_case> switch_case; | ||||
| %type <std::vector<elna::boot::switch_case>> switch_cases; | ||||
| %type <elna::boot::constant_definition *> constant_definition; | ||||
| %type <std::vector<elna::boot::constant_definition *>> constant_part constant_definitions; | ||||
| %type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part variable_declaration; | ||||
| %type <elna::boot::type_expression *> type_expression; | ||||
| %type <std::vector<elna::boot::type_expression *>> type_expressions; | ||||
| %type <elna::boot::traits_expression *> traits_expression; | ||||
| %type <elna::boot::expression *> expression operand qualident; | ||||
| %type <elna::boot::expression *> expression operand simple_expression; | ||||
| %type <elna::boot::field_access_expression *> qualident; | ||||
| %type <elna::boot::unary_expression *> unary_expression; | ||||
| %type <elna::boot::binary_expression *> binary_expression; | ||||
| %type <std::vector<elna::boot::expression *>> expressions actual_parameter_list; | ||||
| %type <elna::boot::designator_expression *> designator_expression; | ||||
| %type <elna::boot::assign_statement *> assign_statement; | ||||
| %type <elna::boot::procedure_call*> call_expression; | ||||
| %type <elna::boot::while_statement *> while_statement; | ||||
| %type <elna::boot::if_statement *> if_statement; | ||||
| @@ -154,9 +160,9 @@ along with GCC; see the file COPYING3.  If not see | ||||
|     optional_fields required_fields formal_parameters; | ||||
| %type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements; | ||||
| %type <elna::boot::cast_expression *> cast_expression; | ||||
| %type <elna::boot::defer_statement *> defer_statement; | ||||
| %type <std::pair<std::string, bool>> identifier_definition; | ||||
| %type <std::vector<std::pair<std::string, bool>>> identifier_definitions; | ||||
| %type <std::vector<std::string>> identifiers; | ||||
| %% | ||||
| program: | ||||
|     constant_part type_part variable_part procedure_part "begin" statements "end" "." | ||||
| @@ -230,10 +236,6 @@ procedure_definitions: | ||||
| procedure_part: | ||||
|     /* no procedure definitions */ {} | ||||
|     | procedure_definitions { std::swap($$, $1); } | ||||
| assign_statement: designator_expression ":=" expression | ||||
|         { | ||||
|             $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); | ||||
|         } | ||||
| call_expression: designator_expression actual_parameter_list | ||||
|         { | ||||
|             $$ = new boot::procedure_call(boot::make_position(@1), $1); | ||||
| @@ -293,11 +295,6 @@ return_statement: | ||||
|         { | ||||
|             $$ = new boot::return_statement(boot::make_position(@1)); | ||||
|         } | ||||
| defer_statement: DEFER statements "end" | ||||
|         { | ||||
|             $$ = new boot::defer_statement(boot::make_position(@1)); | ||||
|             std::swap($2, $$->statements); | ||||
|         } | ||||
| literal: | ||||
|     INTEGER | ||||
|         { | ||||
| @@ -333,7 +330,7 @@ traits_expression: | ||||
|             $$ = new boot::traits_expression(boot::make_position(@1), $1); | ||||
|             std::swap($3, $$->parameters); | ||||
|         } | ||||
| qualident: | ||||
| simple_expression: | ||||
|     literal { $$ = $1; } | ||||
|     | designator_expression { $$ = $1; } | ||||
|     | traits_expression { $$ = $1; } | ||||
| @@ -342,7 +339,7 @@ qualident: | ||||
|     | "(" expression ")" { $$ = $2; } | ||||
| operand: | ||||
|     unary_expression { $$ = $1; } | ||||
|     | qualident { $$ = $1; } | ||||
|     | simple_expression { $$ = $1; } | ||||
| expression: | ||||
|     binary_expression { $$ = $1; } | ||||
|     | operand { $$ = $1; } | ||||
| @@ -396,7 +393,7 @@ binary_expression: | ||||
|         { | ||||
|             $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::conjunction); | ||||
|         } | ||||
|     | expression "|" expression | ||||
|     | expression "or" expression | ||||
|         { | ||||
|             $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::disjunction); | ||||
|         } | ||||
| @@ -441,15 +438,12 @@ type_expressions: | ||||
|         } | ||||
|     | type_expression { $$.push_back($1); } | ||||
| designator_expression: | ||||
|     qualident "[" expression "]" | ||||
|     simple_expression "[" expression "]" | ||||
|         { | ||||
|             $$ = new boot::array_access_expression(boot::make_position(@2), $1, $3); | ||||
|         } | ||||
|     | qualident "." IDENTIFIER | ||||
|         { | ||||
|             $$ = new boot::field_access_expression(boot::make_position(@2), $1, $3); | ||||
|         } | ||||
|     | qualident "^" | ||||
|     | qualident  { $$ = $1; } | ||||
|     | simple_expression "^" | ||||
|         { | ||||
|             $$ = new boot::dereference_expression(boot::make_position(@1), $1); | ||||
|         } | ||||
| @@ -457,13 +451,37 @@ designator_expression: | ||||
|         { | ||||
|             $$ = new boot::variable_expression(boot::make_position(@1), $1); | ||||
|         } | ||||
| qualident: simple_expression "." IDENTIFIER | ||||
|         { | ||||
|             $$ = new boot::field_access_expression(boot::make_position(@2), $1, $3); | ||||
|         } | ||||
| statement: | ||||
|     assign_statement { $$ = $1; } | ||||
|     designator_expression ":=" expression | ||||
|         { | ||||
|             $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); | ||||
|         } | ||||
|     | while_statement { $$ = $1; } | ||||
|     | if_statement { $$ = $1; } | ||||
|     | return_statement { $$ = $1; } | ||||
|     | call_expression { $$ = $1; } | ||||
|     | defer_statement { $$ = $1; } | ||||
|     | DEFER statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } | ||||
|     | CASE expression "of" switch_cases "end" | ||||
|         { $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4)); } | ||||
| switch_case: case_labels ":" statements { $$ = { .labels = std::move($1), .statements = std::move($3) }; } | ||||
| switch_cases: | ||||
|     switch_case "|" switch_cases | ||||
|         { | ||||
|             std::swap($$, $3); | ||||
|             $$.emplace($$.cbegin(), $1); | ||||
|         } | ||||
|     | switch_case { $$.push_back($1); } | ||||
| case_labels: | ||||
|     literal "," case_labels | ||||
|         { | ||||
|             std::swap($$, $3); | ||||
|             $$.emplace($$.cbegin(), $1); | ||||
|         } | ||||
|     | literal { $$.push_back($1); } | ||||
| statements: | ||||
|     statement ";" statements | ||||
|         { | ||||
| @@ -507,10 +525,21 @@ type_expression: | ||||
|             std::swap(result->parameters, $3); | ||||
|             $$ = result; | ||||
|         } | ||||
|     | "(" identifiers ")" | ||||
|         { | ||||
|             $$ = new boot::enumeration_type_expression(boot::make_position(@1), std::move($2)); | ||||
|         } | ||||
|     | IDENTIFIER | ||||
|         { | ||||
|             $$ = new boot::primitive_type_expression(boot::make_position(@1), $1); | ||||
|             $$ = new boot::named_type_expression(boot::make_position(@1), $1); | ||||
|         } | ||||
| identifiers: | ||||
|     IDENTIFIER "," identifiers | ||||
|         { | ||||
|             std::swap($$, $3); | ||||
|             $$.emplace($$.cbegin(), std::move($1)); | ||||
|         } | ||||
|     | IDENTIFIER { $$.emplace_back(std::move($1)); } | ||||
| variable_declaration: identifier_definitions ":" type_expression | ||||
|         { | ||||
|             std::shared_ptr<boot::type_expression> shared_type{ $3 }; | ||||
| @@ -561,16 +590,14 @@ type_definitions: | ||||
| type_part: | ||||
|     /* no type definitions */ {} | ||||
|     | "type" type_definitions { std::swap($$, $2); } | ||||
| formal_parameter: IDENTIFIER ":" type_expression | ||||
|         { | ||||
|             $$ = std::make_pair($1, $3); | ||||
|         } | ||||
| formal_parameter: | ||||
|     IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } | ||||
| formal_parameters: | ||||
|     /* no formal parameters */ {} | ||||
|     | formal_parameter "," formal_parameters | ||||
|         { | ||||
|             std::swap($$, $3); | ||||
|             $$.emplace($$.cbegin(), $1); | ||||
|             $$.emplace($$.cbegin(), std::move($1)); | ||||
|         } | ||||
|     | formal_parameter { $$.emplace_back(std::move($1)); } | ||||
| actual_parameter_list: | ||||
|   | ||||
| @@ -114,7 +114,7 @@ namespace elna::boot | ||||
|         unresolved_declaration->reference = this->current_type; | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(primitive_type_expression *type_expression) | ||||
|     void declaration_visitor::visit(named_type_expression *type_expression) | ||||
|     { | ||||
|         auto unresolved_alias = this->unresolved.find(type_expression->name); | ||||
|  | ||||
| @@ -177,13 +177,23 @@ namespace elna::boot | ||||
|         this->current_type = type(result_type); | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(enumeration_type_expression *type_expression) | ||||
|     { | ||||
|         std::shared_ptr<enumeration_type> result_type = std::make_shared<enumeration_type>(type_expression->members); | ||||
|  | ||||
|         this->current_type = type(result_type); | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(variable_declaration *declaration) | ||||
|     { | ||||
|         declaration->variable_type().accept(this); | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(constant_definition *) | ||||
|     void declaration_visitor::visit(constant_definition *definition) | ||||
|     { | ||||
|         definition->body().accept(this); | ||||
|  | ||||
|         this->symbols->enter(definition->identifier, std::make_shared<constant_info>(this->current_literal)); | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(procedure_definition *definition) | ||||
| @@ -249,9 +259,9 @@ namespace elna::boot | ||||
|  | ||||
|     void declaration_visitor::visit(return_statement *statement) | ||||
|     { | ||||
|         if (statement->return_expression() != nullptr) | ||||
|         if (statement->return_expression != nullptr) | ||||
|         { | ||||
|             statement->return_expression()->accept(this); | ||||
|             statement->return_expression->accept(this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -263,6 +273,22 @@ namespace elna::boot | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(case_statement *statement) | ||||
|     { | ||||
|         statement->condition().accept(this); | ||||
|         for (const switch_case& case_block : statement->cases) | ||||
|         { | ||||
|             for (literal_expression *const case_label : case_block.labels) | ||||
|             { | ||||
|                 case_label->accept(this); | ||||
|             } | ||||
|             for (struct statement *const statement : case_block.statements) | ||||
|             { | ||||
|                 statement->accept(this); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(procedure_call *call) | ||||
|     { | ||||
|         call->callable().accept(this); | ||||
| @@ -333,31 +359,38 @@ namespace elna::boot | ||||
|         expression->base().accept(this); | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(literal<std::int32_t> *) | ||||
|     void declaration_visitor::visit(literal<std::int32_t> *literal) | ||||
|     { | ||||
|         this->current_literal = literal->value; | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(literal<std::uint32_t> *) | ||||
|     void declaration_visitor::visit(literal<std::uint32_t> *literal) | ||||
|     { | ||||
|         this->current_literal = literal->value; | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(literal<double> *) | ||||
|     void declaration_visitor::visit(literal<double> *literal) | ||||
|     { | ||||
|         this->current_literal = literal->value; | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(literal<bool> *) | ||||
|     void declaration_visitor::visit(literal<bool> *literal) | ||||
|     { | ||||
|         this->current_literal = literal->value; | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(literal<unsigned char> *) | ||||
|     void declaration_visitor::visit(literal<unsigned char> *literal) | ||||
|     { | ||||
|         this->current_literal = literal->value; | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(literal<std::nullptr_t> *) | ||||
|     void declaration_visitor::visit(literal<std::nullptr_t> *literal) | ||||
|     { | ||||
|         this->current_literal = literal->value; | ||||
|     } | ||||
|  | ||||
|     void declaration_visitor::visit(literal<std::string> *) | ||||
|     void declaration_visitor::visit(literal<std::string> *literal) | ||||
|     { | ||||
|         this->current_literal = literal->value; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -58,6 +58,11 @@ namespace elna::boot | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     type::type(std::shared_ptr<enumeration_type> enumeration) | ||||
|         : tag(type_tag::enumeration), enumeration(enumeration) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void type::copy(const type& other) | ||||
|     { | ||||
|         switch (other.tag) | ||||
| @@ -85,6 +90,9 @@ namespace elna::boot | ||||
|         case type_tag::procedure: | ||||
|             new (&procedure) std::shared_ptr<procedure_type>(other.procedure); | ||||
|             break; | ||||
|         case type_tag::enumeration: | ||||
|             new (&enumeration) std::shared_ptr<enumeration_type>(other.enumeration); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -121,6 +129,9 @@ namespace elna::boot | ||||
|         case type_tag::procedure: | ||||
|             new (&procedure) std::shared_ptr<procedure_type>(std::move(other.procedure)); | ||||
|             break; | ||||
|         case type_tag::enumeration: | ||||
|             new (&enumeration) std::shared_ptr<enumeration_type>(std::move(other.enumeration)); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -178,6 +189,9 @@ namespace elna::boot | ||||
|         case type_tag::procedure: | ||||
|             this->procedure.~shared_ptr<procedure_type>(); | ||||
|             break; | ||||
|         case type_tag::enumeration: | ||||
|             this->enumeration.~shared_ptr<enumeration_type>(); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -223,6 +237,12 @@ namespace elna::boot | ||||
|         return tag == type_tag::procedure ? this->procedure : nullptr; | ||||
|     } | ||||
|  | ||||
|     template<> | ||||
|     std::shared_ptr<enumeration_type> type::get<enumeration_type>() const | ||||
|     { | ||||
|         return tag == type_tag::enumeration ? this->enumeration : nullptr; | ||||
|     } | ||||
|  | ||||
|     bool type::empty() const | ||||
|     { | ||||
|         return tag == type_tag::empty; | ||||
| @@ -253,6 +273,11 @@ namespace elna::boot | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     enumeration_type::enumeration_type(const std::vector<std::string>& members) | ||||
|         : members(members) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     info::~info() | ||||
|     { | ||||
|     } | ||||
| @@ -287,6 +312,11 @@ namespace elna::boot | ||||
|         return std::static_pointer_cast<procedure_info>(shared_from_this()); | ||||
|     } | ||||
|  | ||||
|     constant_info::constant_info(const variant& symbol) | ||||
|         : symbol(symbol) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     std::shared_ptr<symbol_table> builtin_symbol_table() | ||||
|     { | ||||
|         auto result = std::make_shared<symbol_table>(); | ||||
|   | ||||
| @@ -78,7 +78,7 @@ namespace elna::gcc | ||||
|         { | ||||
|             return "()"; | ||||
|         } | ||||
|         else if (is_pointer_type(unqualified_type)) | ||||
|         else if (POINTER_TYPE_P(unqualified_type)) | ||||
|         { | ||||
|             tree pointer_target_type = TREE_TYPE(type); | ||||
|  | ||||
| @@ -129,6 +129,10 @@ namespace elna::gcc | ||||
|         { | ||||
|             return print_aggregate_name(unqualified_type, "union"); | ||||
|         } | ||||
|         else if (TREE_CODE(type) == ENUMERAL_TYPE) | ||||
|         { | ||||
|             return print_aggregate_name(unqualified_type, "enumeration"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return "<<unknown-type>>"; | ||||
|   | ||||
| @@ -57,6 +57,10 @@ namespace elna::gcc | ||||
|         { | ||||
|             return make_node(UNION_TYPE); | ||||
|         } | ||||
|         else if (auto reference = type.get<boot::enumeration_type>()) | ||||
|         { | ||||
|             return make_node(ENUMERAL_TYPE); | ||||
|         } | ||||
|         else if (auto reference = type.get<boot::pointer_type>()) | ||||
|         { | ||||
|             return build_global_pointer_type(get_inner_alias(reference->base, symbols, unresolved, path)); | ||||
| @@ -227,7 +231,7 @@ namespace elna::gcc | ||||
|                     build_global_pointer_type(expression_type), this->current_expression); | ||||
|             build_procedure_call(call_location, this->current_expression, call->arguments); | ||||
|         } | ||||
|         else if (is_pointer_type(expression_type) && TREE_CODE(TREE_TYPE(expression_type)) == FUNCTION_TYPE) | ||||
|         else if (POINTER_TYPE_P(expression_type) && TREE_CODE(TREE_TYPE(expression_type)) == FUNCTION_TYPE) | ||||
|         { | ||||
|             build_procedure_call(call_location, this->current_expression, call->arguments); | ||||
|         } | ||||
| @@ -247,8 +251,7 @@ namespace elna::gcc | ||||
|         expression->value().accept(this); | ||||
|         tree cast_source = TREE_TYPE(this->current_expression); | ||||
|  | ||||
|         if ((is_primitive_type(cast_target) || is_pointer_type(cast_target)) | ||||
|                 && (is_primitive_type(cast_source) || is_pointer_type(cast_source))) | ||||
|         if (is_castable_type(cast_target) && (is_castable_type(cast_source))) | ||||
|         { | ||||
|             this->current_expression = build1_loc(get_location(&expression->position()), CONVERT_EXPR, | ||||
|                     cast_target, this->current_expression); | ||||
| @@ -303,7 +306,8 @@ namespace elna::gcc | ||||
|         for (boot::constant_definition *const constant : program->constants) | ||||
|         { | ||||
|             constant->accept(this); | ||||
|         } for (boot::type_definition *const type : program->types) | ||||
|         } | ||||
|         for (boot::type_definition *const type : program->types) | ||||
|         { | ||||
|             type->accept(this); | ||||
|         } | ||||
| @@ -514,7 +518,7 @@ namespace elna::gcc | ||||
|     tree generic_visitor::build_comparison_operation(boot::binary_expression *expression, | ||||
|             tree_code operator_code, tree left, tree right) | ||||
|     { | ||||
|         return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || is_pointer_type(TREE_TYPE(left)), | ||||
|         return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || POINTER_TYPE_P(TREE_TYPE(left)), | ||||
|                 expression, operator_code, left, right, elna_bool_type_node); | ||||
|     } | ||||
|  | ||||
| @@ -624,7 +628,7 @@ namespace elna::gcc | ||||
|  | ||||
|         location_t expression_location = get_location(&expression->position()); | ||||
|  | ||||
|         if ((is_pointer_type(left_type) || is_pointer_type(right_type)) | ||||
|         if ((POINTER_TYPE_P(left_type) || POINTER_TYPE_P(right_type)) | ||||
|                 && (expression->operation() == boot::binary_operator::sum | ||||
|                     || expression->operation() == boot::binary_operator::subtraction)) | ||||
|         { | ||||
| @@ -867,7 +871,7 @@ namespace elna::gcc | ||||
|                 get_identifier(declaration->identifier.c_str()), this->current_expression); | ||||
|         bool result = this->symbols->enter(declaration->identifier, declaration_tree); | ||||
|  | ||||
|         if (is_pointer_type(this->current_expression)) | ||||
|         if (POINTER_TYPE_P(this->current_expression)) | ||||
|         { | ||||
|             DECL_INITIAL(declaration_tree) = elna_pointer_nil_node; | ||||
|         } | ||||
| @@ -976,7 +980,7 @@ namespace elna::gcc | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         else if (!is_integral_type(this->current_expression)) | ||||
|         else if (!is_integral_type(this->current_expression) && TREE_CODE(this->current_expression) != ENUMERAL_TYPE) | ||||
|         { | ||||
|             error_at(get_location(&trait->position()), "Type '%s' does not support trait '%s'", | ||||
|                     print_type(this->current_expression).c_str(), trait->name.c_str()); | ||||
| @@ -1030,7 +1034,7 @@ namespace elna::gcc | ||||
|                 return; | ||||
|             } | ||||
|             trait->parameters.front()->accept(this); | ||||
|             auto field_type = trait->parameters.at(1)->is_primitive(); | ||||
|             auto field_type = trait->parameters.at(1)->is_named(); | ||||
|  | ||||
|             if (field_type == nullptr) | ||||
|             { | ||||
| @@ -1076,6 +1080,21 @@ namespace elna::gcc | ||||
|             this->current_expression = build1(ADDR_EXPR, | ||||
|                     build_qualified_type(ptr_type, TYPE_QUAL_CONST), this->current_expression); | ||||
|         } | ||||
|         else if (TREE_CODE(aggregate_type) == ENUMERAL_TYPE) | ||||
|         { | ||||
|             tree iterator{ NULL_TREE }; | ||||
|  | ||||
|             for (iterator = TYPE_VALUES(aggregate_type); iterator != NULL_TREE; iterator = TREE_CHAIN(iterator)) | ||||
|             { | ||||
|                 if (IDENTIFIER_POINTER(TREE_PURPOSE(iterator)) == expression->field()) | ||||
|                 { | ||||
|                     this->current_expression = TREE_VALUE(iterator); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             this->current_expression = error_mark_node; | ||||
|             error_at(expression_location, "Unknown enumeration member '%s'", expression->field().c_str()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             tree field_declaration = find_field_by_name(expression_location, | ||||
| @@ -1096,7 +1115,7 @@ namespace elna::gcc | ||||
|         location_t expression_location = get_location(&expression->position()); | ||||
|         tree expression_type = TREE_TYPE(this->current_expression); | ||||
|  | ||||
|         if (is_pointer_type(expression_type)) | ||||
|         if (POINTER_TYPE_P(expression_type)) | ||||
|         { | ||||
|             this->current_expression = build1_loc(expression_location, INDIRECT_REF, | ||||
|                     TREE_TYPE(expression_type), this->current_expression); | ||||
| @@ -1201,16 +1220,6 @@ namespace elna::gcc | ||||
|         append_statement(else_label_expr); | ||||
|     } | ||||
|  | ||||
|     tree generic_visitor::build_label_decl(const char *name, location_t loc) | ||||
|     { | ||||
|         auto label_decl = build_decl(loc, | ||||
|                 LABEL_DECL, get_identifier(name), void_type_node); | ||||
|  | ||||
|         DECL_CONTEXT(label_decl) = current_function_decl; | ||||
|  | ||||
|         return label_decl; | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::while_statement *statement) | ||||
|     { | ||||
|         auto prerequisite_location = get_location(&statement->body().prerequisite().position()); | ||||
| @@ -1245,7 +1254,7 @@ namespace elna::gcc | ||||
|  | ||||
|     void generic_visitor::visit(boot::return_statement *statement) | ||||
|     { | ||||
|         boot::expression *return_expression = statement->return_expression(); | ||||
|         boot::expression *return_expression = statement->return_expression; | ||||
|         location_t statement_position = get_location(&statement->position()); | ||||
|         tree set_result{ NULL_TREE }; | ||||
|         tree return_type = TREE_TYPE(TREE_TYPE(current_function_decl)); | ||||
| @@ -1285,7 +1294,7 @@ namespace elna::gcc | ||||
|         this->current_expression = NULL_TREE; | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::primitive_type_expression *type) | ||||
|     void generic_visitor::visit(boot::named_type_expression *type) | ||||
|     { | ||||
|         auto looked_up = this->unresolved.find(type->name); | ||||
|         tree symbol; | ||||
| @@ -1362,10 +1371,85 @@ namespace elna::gcc | ||||
|         this->current_expression = build_global_pointer_type(procedure_type_node); | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::enumeration_type_expression *type) | ||||
|     { | ||||
|         tree composite_type_node = this->current_expression == NULL_TREE | ||||
|             ? make_node(ENUMERAL_TYPE) | ||||
|             : this->current_expression; | ||||
|         location_t enum_location = get_location(&type->position()); | ||||
|         const tree base_type = integer_type_node; | ||||
|  | ||||
|         TREE_TYPE(composite_type_node) = base_type; | ||||
|         ENUM_IS_SCOPED(composite_type_node) = 1; | ||||
|  | ||||
|         tree *pp = &TYPE_VALUES(composite_type_node); | ||||
|         std::size_t order{ 1 }; | ||||
|  | ||||
|         for (const std::string& member : type->members) | ||||
|         { | ||||
|             tree member_name = get_identifier(member.c_str()); | ||||
|             tree member_declaration = build_decl(enum_location, CONST_DECL, member_name, composite_type_node); | ||||
|  | ||||
|             DECL_CONTEXT(member_declaration) = composite_type_node; | ||||
|             DECL_INITIAL(member_declaration) = build_int_cst_type(composite_type_node, order++); | ||||
|             TREE_CONSTANT(member_declaration) = 1; | ||||
|             TREE_READONLY(member_declaration) = 1; | ||||
|  | ||||
|             TYPE_MAX_VALUE(composite_type_node) = DECL_INITIAL(member_declaration); | ||||
|  | ||||
|             *pp = build_tree_list(member_name, member_declaration); | ||||
|             pp = &TREE_CHAIN(*pp); | ||||
|         } | ||||
|         TYPE_MIN_VALUE(composite_type_node) = DECL_INITIAL(TREE_VALUE(TYPE_VALUES(composite_type_node))); | ||||
|         TYPE_UNSIGNED(composite_type_node) = TYPE_UNSIGNED(base_type); | ||||
|         SET_TYPE_ALIGN(composite_type_node, TYPE_ALIGN(base_type)); | ||||
|         TYPE_SIZE(composite_type_node) = NULL_TREE; | ||||
|         TYPE_PRECISION(composite_type_node) = TYPE_PRECISION(base_type); | ||||
|  | ||||
|         layout_type(composite_type_node); | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::defer_statement *statement) | ||||
|     { | ||||
|         enter_scope(); | ||||
|         visit_statements(statement->statements); | ||||
|         defer(leave_scope()); | ||||
|     } | ||||
|  | ||||
|     void generic_visitor::visit(boot::case_statement *statement) | ||||
|     { | ||||
|         statement->condition().accept(this); | ||||
|  | ||||
|         tree condition_expression = this->current_expression; | ||||
|         tree end_label_declaration = create_artificial_label(UNKNOWN_LOCATION); | ||||
|         tree switch_statements = alloc_stmt_list(); | ||||
|  | ||||
|         for (const boot::switch_case& case_block : statement->cases) | ||||
|         { | ||||
|             for (boot::literal_expression *const case_label : case_block.labels) | ||||
|             { | ||||
|                 case_label->accept(this); | ||||
|                 tree case_label_declaration = create_artificial_label(get_location(&case_label->position())); | ||||
|                 tree case_expression = build_case_label(this->current_expression, NULL_TREE, case_label_declaration); | ||||
|  | ||||
|                 append_to_statement_list(case_expression, &switch_statements); | ||||
|             } | ||||
|             enter_scope(); | ||||
|             visit_statements(case_block.statements); | ||||
|             append_to_statement_list(leave_scope(), &switch_statements); | ||||
|             tree goto_end = fold_build1(GOTO_EXPR, void_type_node, end_label_declaration); | ||||
|  | ||||
|             append_to_statement_list(goto_end, &switch_statements); | ||||
|             TREE_USED(end_label_declaration) = 1; | ||||
|         } | ||||
|         tree switch_expression = build2(SWITCH_EXPR, TREE_TYPE(condition_expression), | ||||
|                 condition_expression, switch_statements); | ||||
|  | ||||
|         append_statement(switch_expression); | ||||
|  | ||||
|         tree end_label_expression = build1(LABEL_EXPR, void_type_node, end_label_declaration); | ||||
|         append_statement(end_label_expression); | ||||
|  | ||||
|         this->current_expression = NULL_TREE; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -26,12 +26,6 @@ along with GCC; see the file COPYING3.  If not see | ||||
|  | ||||
| namespace elna::gcc | ||||
| { | ||||
|     bool is_pointer_type(tree type) | ||||
|     { | ||||
|         gcc_assert(TYPE_P(type)); | ||||
|         return TREE_CODE(type) == POINTER_TYPE; | ||||
|     } | ||||
|  | ||||
|     bool is_integral_type(tree type) | ||||
|     { | ||||
|         gcc_assert(TYPE_P(type)); | ||||
| @@ -62,10 +56,12 @@ namespace elna::gcc | ||||
|         return type == NULL_TREE || type == void_type_node; | ||||
|     } | ||||
|  | ||||
|     bool is_aggregate_type(tree type) | ||||
|     bool is_castable_type(tree type) | ||||
|     { | ||||
|         gcc_assert(TYPE_P(type)); | ||||
|         return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE; | ||||
|         auto code = TREE_CODE(type); | ||||
|  | ||||
|         return is_primitive_type(type) || POINTER_TYPE_P(type) || code == ENUMERAL_TYPE; | ||||
|     } | ||||
|  | ||||
|     bool are_compatible_pointers(tree lhs_type, tree rhs) | ||||
| @@ -73,8 +69,8 @@ namespace elna::gcc | ||||
|         gcc_assert(TYPE_P(lhs_type)); | ||||
|         tree rhs_type = TREE_TYPE(rhs); | ||||
|  | ||||
|         return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node) | ||||
|             || (is_pointer_type(lhs_type) && lhs_type == rhs_type); | ||||
|         return (POINTER_TYPE_P(lhs_type) && rhs == elna_pointer_nil_node) | ||||
|             || (POINTER_TYPE_P(lhs_type) && lhs_type == rhs_type); | ||||
|     } | ||||
|  | ||||
|     tree prepare_rvalue(tree rvalue) | ||||
| @@ -152,12 +148,12 @@ namespace elna::gcc | ||||
|             tree pointer{ NULL_TREE }; | ||||
|             tree offset{ NULL_TREE }; | ||||
|  | ||||
|             if (is_pointer_type(left_type) && is_integral_type(right_type)) | ||||
|             if (POINTER_TYPE_P(left_type) && is_integral_type(right_type)) | ||||
|             { | ||||
|                 pointer = left; | ||||
|                 offset = right; | ||||
|             } | ||||
|             else if (is_integral_type(left_type) && is_pointer_type(right_type)) | ||||
|             else if (is_integral_type(left_type) && POINTER_TYPE_P(right_type)) | ||||
|             { | ||||
|                 pointer = right; | ||||
|                 offset = left; | ||||
| @@ -175,7 +171,7 @@ namespace elna::gcc | ||||
|         } | ||||
|         else if (binary_operator == boot::binary_operator::subtraction) | ||||
|         { | ||||
|             if (is_pointer_type(left_type) && is_integral_type(right_type)) | ||||
|             if (POINTER_TYPE_P(left_type) && is_integral_type(right_type)) | ||||
|             { | ||||
|                 tree pointer_type = left_type; | ||||
|                 tree offset_type = right_type; | ||||
| @@ -187,7 +183,7 @@ namespace elna::gcc | ||||
|                 convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression); | ||||
|                 return fold_build2(POINTER_PLUS_EXPR, pointer_type, left, convert_expression); | ||||
|             } | ||||
|             else if (is_pointer_type(left_type) && is_pointer_type(right_type) && left_type == right_type) | ||||
|             else if (POINTER_TYPE_P(left_type) && POINTER_TYPE_P(right_type) && left_type == right_type) | ||||
|             { | ||||
|                 return fold_build2(POINTER_DIFF_EXPR, ssizetype, left, right); | ||||
|             } | ||||
| @@ -224,9 +220,9 @@ namespace elna::gcc | ||||
|         } | ||||
|         tree field_declaration = TYPE_FIELDS(type); | ||||
|  | ||||
|         if (!is_aggregate_type(type)) | ||||
|         if (!RECORD_OR_UNION_TYPE_P(type)) | ||||
|         { | ||||
|             error_at(expression_location, "type '%s' does not have a field named '%s'", | ||||
|             error_at(expression_location, "Type '%s' does not have a field named '%s'", | ||||
|                     print_type(type).c_str(), field_name.c_str()); | ||||
|             return error_mark_node; | ||||
|         } | ||||
| @@ -243,7 +239,7 @@ namespace elna::gcc | ||||
|         } | ||||
|         if (field_declaration == NULL_TREE) | ||||
|         { | ||||
|             error_at(expression_location, "record type does not have a field named '%s'", field_name.c_str()); | ||||
|             error_at(expression_location, "Aggregate type does not have a field '%s'", field_name.c_str()); | ||||
|             return error_mark_node; | ||||
|         } | ||||
|         return field_declaration; | ||||
| @@ -253,4 +249,13 @@ namespace elna::gcc | ||||
|     { | ||||
|         return build_pointer_type_for_mode(type, VOIDmode, true); | ||||
|     } | ||||
|  | ||||
|     tree build_label_decl(const char *name, location_t loc) | ||||
|     { | ||||
|         auto label_decl = build_decl(loc, LABEL_DECL, get_identifier(name), void_type_node); | ||||
|  | ||||
|         DECL_CONTEXT(label_decl) = current_function_decl; | ||||
|  | ||||
|         return label_decl; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -62,17 +62,19 @@ namespace elna::boot | ||||
|     class if_statement; | ||||
|     class while_statement; | ||||
|     class return_statement; | ||||
|     class case_statement; | ||||
|     class traits_expression; | ||||
|     class block; | ||||
|     class program; | ||||
|     class binary_expression; | ||||
|     class unary_expression; | ||||
|     class primitive_type_expression; | ||||
|     class named_type_expression; | ||||
|     class array_type_expression; | ||||
|     class pointer_type_expression; | ||||
|     class record_type_expression; | ||||
|     class union_type_expression; | ||||
|     class procedure_type_expression; | ||||
|     class enumeration_type_expression; | ||||
|     class variable_expression; | ||||
|     class array_access_expression; | ||||
|     class field_access_expression; | ||||
| @@ -100,16 +102,18 @@ namespace elna::boot | ||||
|         virtual void visit(while_statement *) = 0; | ||||
|         virtual void visit(return_statement *) = 0; | ||||
|         virtual void visit(defer_statement *) = 0; | ||||
|         virtual void visit(case_statement *) = 0; | ||||
|         virtual void visit(block *) = 0; | ||||
|         virtual void visit(program *) = 0; | ||||
|         virtual void visit(binary_expression *) = 0; | ||||
|         virtual void visit(unary_expression *) = 0; | ||||
|         virtual void visit(primitive_type_expression *) = 0; | ||||
|         virtual void visit(named_type_expression *) = 0; | ||||
|         virtual void visit(array_type_expression *) = 0; | ||||
|         virtual void visit(pointer_type_expression *) = 0; | ||||
|         virtual void visit(record_type_expression *) = 0; | ||||
|         virtual void visit(union_type_expression *) = 0; | ||||
|         virtual void visit(procedure_type_expression *) = 0; | ||||
|         virtual void visit(enumeration_type_expression *) = 0; | ||||
|         virtual void visit(variable_expression *) = 0; | ||||
|         virtual void visit(array_access_expression *) = 0; | ||||
|         virtual void visit(field_access_expression *) = 0; | ||||
| @@ -188,28 +192,29 @@ namespace elna::boot | ||||
|     class type_expression : public node | ||||
|     { | ||||
|     public: | ||||
|         virtual primitive_type_expression *is_primitive(); | ||||
|         virtual named_type_expression *is_named(); | ||||
|         virtual array_type_expression *is_array(); | ||||
|         virtual pointer_type_expression *is_pointer(); | ||||
|         virtual record_type_expression *is_record(); | ||||
|         virtual union_type_expression *is_union(); | ||||
|         virtual procedure_type_expression *is_procedure(); | ||||
|         virtual enumeration_type_expression *is_enumeration(); | ||||
|  | ||||
|     protected: | ||||
|         type_expression(const struct position position); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Expression defining a basic type. | ||||
|      * Expression refering to a type by its name. | ||||
|      */ | ||||
|     class primitive_type_expression : public type_expression | ||||
|     class named_type_expression : public type_expression | ||||
|     { | ||||
|     public: | ||||
|         const std::string name; | ||||
|  | ||||
|         primitive_type_expression(const struct position position, const std::string& name); | ||||
|         named_type_expression(const struct position position, const std::string& name); | ||||
|         void accept(parser_visitor *visitor) override; | ||||
|         primitive_type_expression *is_primitive() override; | ||||
|         named_type_expression *is_named() override; | ||||
|     }; | ||||
|  | ||||
|     class array_type_expression : public type_expression | ||||
| @@ -269,6 +274,20 @@ namespace elna::boot | ||||
|         union_type_expression *is_union() override; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Enumeration type. | ||||
|      */ | ||||
|     class enumeration_type_expression : public type_expression | ||||
|     { | ||||
|     public: | ||||
|         const std::vector<std::string> members; | ||||
|  | ||||
|         enumeration_type_expression(const struct position, std::vector<std::string>&& members); | ||||
|  | ||||
|         void accept(parser_visitor *visitor) override; | ||||
|         enumeration_type_expression *is_enumeration() override; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Variable declaration. | ||||
|      */ | ||||
| @@ -291,14 +310,6 @@ namespace elna::boot | ||||
|     class literal_expression : public expression | ||||
|     { | ||||
|     public: | ||||
|         virtual literal<std::int32_t> *is_int() = 0; | ||||
|         virtual literal<std::uint32_t> *is_word() = 0; | ||||
|         virtual literal<double> *is_float() = 0; | ||||
|         virtual literal<bool> *is_bool() = 0; | ||||
|         virtual literal<unsigned char> *is_char() = 0; | ||||
|         virtual literal<std::nullptr_t> *is_nil() = 0; | ||||
|         virtual literal<std::string> *is_string() = 0; | ||||
|  | ||||
|         literal_expression *is_literal() override; | ||||
|  | ||||
|     protected: | ||||
| @@ -428,18 +439,34 @@ namespace elna::boot | ||||
|  | ||||
|     class return_statement : public statement | ||||
|     { | ||||
|         expression *m_return_expression{ nullptr }; | ||||
|  | ||||
|     public: | ||||
|         expression *const return_expression{ nullptr }; | ||||
|  | ||||
|         return_statement(const struct position position, expression *return_expression = nullptr); | ||||
|         void accept(parser_visitor *visitor) override; | ||||
|         virtual return_statement *is_return() override; | ||||
|  | ||||
|         expression *return_expression(); | ||||
|  | ||||
|         virtual ~return_statement() override; | ||||
|     }; | ||||
|  | ||||
|     struct switch_case | ||||
|     { | ||||
|         std::vector<literal_expression *> labels; | ||||
|         std::vector<statement *> statements; | ||||
|     }; | ||||
|  | ||||
|     class case_statement : public statement | ||||
|     { | ||||
|         expression *m_condition; | ||||
|  | ||||
|     public: | ||||
|         const std::vector<switch_case> cases; | ||||
|  | ||||
|         case_statement(const struct position position, expression *condition, std::vector<switch_case>&& cases); | ||||
|         void accept(parser_visitor *visitor) override; | ||||
|         expression& condition(); | ||||
|     }; | ||||
|  | ||||
|     class designator_expression : public expression | ||||
|     { | ||||
|     public: | ||||
| @@ -635,90 +662,6 @@ namespace elna::boot | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         literal<std::int32_t> *is_int() override | ||||
|         { | ||||
|             if (std::is_same<T, std::int32_t>::value) | ||||
|             { | ||||
|                 return reinterpret_cast<literal<std::int32_t> *>(this); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         literal<std::uint32_t> *is_word() override | ||||
|         { | ||||
|             if (std::is_same<T, std::uint32_t>::value) | ||||
|             { | ||||
|                 return reinterpret_cast<literal<std::uint32_t> *>(this); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         literal<double> *is_float() override | ||||
|         { | ||||
|             if (std::is_same<T, double>::value) | ||||
|             { | ||||
|                 return reinterpret_cast<literal<double> *>(this); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         literal<bool> *is_bool() override | ||||
|         { | ||||
|             if (std::is_same<T, bool>::value) | ||||
|             { | ||||
|                 return reinterpret_cast<literal<bool> *>(this); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         literal<unsigned char> *is_char() override | ||||
|         { | ||||
|             if (std::is_same<T, unsigned char>::value) | ||||
|             { | ||||
|                 return reinterpret_cast<literal<unsigned char> *>(this); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         literal<std::nullptr_t> *is_nil() override | ||||
|         { | ||||
|             if (std::is_same<T, std::nullptr_t>::value) | ||||
|             { | ||||
|                 return reinterpret_cast<literal<std::nullptr_t> *>(this); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         literal<std::string> *is_string() override | ||||
|         { | ||||
|             if (std::is_same<T, std::string>::value) | ||||
|             { | ||||
|                 return reinterpret_cast<literal<std::string> *>(this); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return nullptr; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void accept(parser_visitor *visitor) override | ||||
|         { | ||||
|             visitor->visit(this); | ||||
| @@ -728,9 +671,9 @@ namespace elna::boot | ||||
|     class defer_statement : public statement | ||||
|     { | ||||
|     public: | ||||
|         std::vector<statement *> statements; | ||||
|         const std::vector<statement *> statements; | ||||
|  | ||||
|         defer_statement(const struct position position); | ||||
|         defer_statement(const struct position position, std::vector<statement *>&& statements); | ||||
|         void accept(parser_visitor *visitor) override; | ||||
|         defer_statement *is_defer() override; | ||||
|  | ||||
|   | ||||
| @@ -49,6 +49,8 @@ namespace elna::boot | ||||
|     class declaration_visitor final : public parser_visitor, public error_container | ||||
|     { | ||||
|         type current_type; | ||||
|         constant_info::variant current_literal; | ||||
|  | ||||
|         std::shared_ptr<symbol_table> symbols; | ||||
|  | ||||
|         procedure_type build_procedure(procedure_type_expression& type_expression); | ||||
| @@ -58,7 +60,7 @@ namespace elna::boot | ||||
|  | ||||
|         explicit declaration_visitor(const char *path, std::shared_ptr<symbol_table> symbols); | ||||
|  | ||||
|         void visit(primitive_type_expression *type_expression) override; | ||||
|         void visit(named_type_expression *type_expression) override; | ||||
|         void visit(array_type_expression *type_expression) override; | ||||
|         void visit(pointer_type_expression *type_expression) override; | ||||
|         void visit(program *program) override; | ||||
| @@ -66,15 +68,17 @@ namespace elna::boot | ||||
|         void visit(record_type_expression *type_expression) override; | ||||
|         void visit(union_type_expression *type_expression) override; | ||||
|         void visit(procedure_type_expression *type_expression) override; | ||||
|         void visit(enumeration_type_expression *type_expression) override; | ||||
|  | ||||
|         void visit(variable_declaration *declaration) override; | ||||
|         void visit(constant_definition *) override; | ||||
|         void visit(constant_definition *definition) override; | ||||
|         void visit(procedure_definition *definition) override; | ||||
|         void visit(assign_statement *statement) override; | ||||
|         void visit(if_statement *statement) override; | ||||
|         void visit(while_statement *statement) override; | ||||
|         void visit(return_statement *statement) override; | ||||
|         void visit(defer_statement *statement) override; | ||||
|         void visit(case_statement *statement) override; | ||||
|         void visit(procedure_call *call) override; | ||||
|         void visit(block *block) override; | ||||
|         void visit(cast_expression *expression) override; | ||||
| @@ -85,12 +89,12 @@ namespace elna::boot | ||||
|         void visit(array_access_expression *expression) override; | ||||
|         void visit(field_access_expression *expression) override; | ||||
|         void visit(dereference_expression *expression) override; | ||||
|         void visit(literal<std::int32_t> *) override; | ||||
|         void visit(literal<std::uint32_t> *) override; | ||||
|         void visit(literal<double> *) override; | ||||
|         void visit(literal<bool> *) override; | ||||
|         void visit(literal<unsigned char> *) override; | ||||
|         void visit(literal<std::nullptr_t> *) override; | ||||
|         void visit(literal<std::string> *) override; | ||||
|         void visit(literal<std::int32_t> *literal) override; | ||||
|         void visit(literal<std::uint32_t> *literal) override; | ||||
|         void visit(literal<double> *literal) override; | ||||
|         void visit(literal<bool> *literal) override; | ||||
|         void visit(literal<unsigned char> *literal) override; | ||||
|         void visit(literal<std::nullptr_t> *literal) override; | ||||
|         void visit(literal<std::string> *literal) override; | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -34,6 +34,7 @@ namespace elna::boot | ||||
|     class pointer_type; | ||||
|     class array_type; | ||||
|     class procedure_type; | ||||
|     class enumeration_type; | ||||
|  | ||||
|     class type | ||||
|     { | ||||
| @@ -46,7 +47,8 @@ namespace elna::boot | ||||
|             _union, | ||||
|             pointer, | ||||
|             array, | ||||
|             procedure | ||||
|             procedure, | ||||
|             enumeration | ||||
|         }; | ||||
|         type_tag tag{ type_tag::empty }; | ||||
|         union | ||||
| @@ -58,6 +60,7 @@ namespace elna::boot | ||||
|             std::shared_ptr<pointer_type> pointer; | ||||
|             std::shared_ptr<array_type> array; | ||||
|             std::shared_ptr<procedure_type> procedure; | ||||
|             std::shared_ptr<enumeration_type> enumeration; | ||||
|         }; | ||||
|  | ||||
|         void copy(const type& other); | ||||
| @@ -72,6 +75,7 @@ namespace elna::boot | ||||
|         explicit type(std::shared_ptr<pointer_type> pointer); | ||||
|         explicit type(std::shared_ptr<array_type> array); | ||||
|         explicit type(std::shared_ptr<procedure_type> procedure); | ||||
|         explicit type(std::shared_ptr<enumeration_type> enumeration); | ||||
|  | ||||
|         type(const type& other); | ||||
|         type& operator=(const type& other); | ||||
| @@ -141,8 +145,16 @@ namespace elna::boot | ||||
|         procedure_type(return_t return_type = return_t()); | ||||
|     }; | ||||
|  | ||||
|     struct enumeration_type | ||||
|     { | ||||
|         std::vector<std::string> members; | ||||
|  | ||||
|         explicit enumeration_type(const std::vector<std::string>& members); | ||||
|     }; | ||||
|  | ||||
|     class type_info; | ||||
|     class procedure_info; | ||||
|     class constant_info; | ||||
|  | ||||
|     class info : public std::enable_shared_from_this<info> | ||||
|     { | ||||
| @@ -174,6 +186,17 @@ namespace elna::boot | ||||
|         std::shared_ptr<procedure_info> is_procedure() override; | ||||
|     }; | ||||
|  | ||||
|     class constant_info : public info | ||||
|     { | ||||
|     public: | ||||
|         using variant = typename | ||||
|             std::variant<std::int32_t, std::uint32_t, double, bool, unsigned char, std::nullptr_t, std::string>; | ||||
|  | ||||
|         const variant symbol; | ||||
|  | ||||
|         explicit constant_info(const variant& symbol); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Symbol table. | ||||
|      */ | ||||
|   | ||||
| @@ -47,7 +47,6 @@ namespace elna::gcc | ||||
|         std::unordered_map<std::string, tree> unresolved; | ||||
|  | ||||
|         void declare_procedure(boot::procedure_definition *const definition); | ||||
|         tree build_label_decl(const char *name, location_t loc); | ||||
|         tree build_procedure_type(boot::procedure_type_expression& type); | ||||
|         void build_composite_type(const std::vector<boot::field_declaration>& fields, | ||||
|                 tree composite_type_node); | ||||
| @@ -101,13 +100,15 @@ namespace elna::gcc | ||||
|         void visit(boot::assign_statement *statement) override; | ||||
|         void visit(boot::if_statement *statement) override; | ||||
|         void visit(boot::while_statement *statement) override; | ||||
|         void visit(boot::primitive_type_expression *type) override; | ||||
|         void visit(boot::named_type_expression *type) override; | ||||
|         void visit(boot::array_type_expression *type) override; | ||||
|         void visit(boot::pointer_type_expression *type) override; | ||||
|         void visit(boot::record_type_expression *type) override; | ||||
|         void visit(boot::union_type_expression *type) override; | ||||
|         void visit(boot::procedure_type_expression *type) override; | ||||
|         void visit(boot::enumeration_type_expression *type) override; | ||||
|         void visit(boot::return_statement *statement) override; | ||||
|         void visit(boot::defer_statement *statement) override; | ||||
|         void visit(boot::case_statement *statement) override; | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -33,7 +33,6 @@ namespace elna::gcc | ||||
| { | ||||
|     using symbol_table = boot::symbol_map<tree, tree, NULL_TREE>; | ||||
|  | ||||
|     bool is_pointer_type(tree type); | ||||
|     bool is_integral_type(tree type); | ||||
|     bool is_numeric_type(tree type); | ||||
|     bool is_primitive_type(tree type); | ||||
| @@ -42,9 +41,9 @@ namespace elna::gcc | ||||
|  | ||||
|     /** | ||||
|      * \param type The type to evaluate. | ||||
|      * \return Whether the given type is record or union. | ||||
|      * \return Whether this type can be converted to another type. | ||||
|      */ | ||||
|     bool is_aggregate_type(tree type); | ||||
|     bool is_castable_type(tree type); | ||||
|  | ||||
|     /** | ||||
|      * \param lhs Left hand value. | ||||
| @@ -82,4 +81,5 @@ namespace elna::gcc | ||||
|     tree build_field(location_t location, tree record_type, const std::string name, tree type); | ||||
|     tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name); | ||||
|     tree build_global_pointer_type(tree type); | ||||
|     tree build_label_decl(const char *name, location_t loc); | ||||
| } | ||||
|   | ||||
							
								
								
									
										392
									
								
								source.elna
									
									
									
									
									
								
							
							
						
						
									
										392
									
								
								source.elna
									
									
									
									
									
								
							| @@ -3,67 +3,69 @@ const | ||||
|   SEEK_CUR* = 1; | ||||
|   SEEK_END* = 2; | ||||
|  | ||||
|   TOKEN_IDENTIFIER* = 1; | ||||
|   TOKEN_IF* = 2; | ||||
|   TOKEN_THEN* = 3; | ||||
|   TOKEN_ELSE* = 4; | ||||
|   TOKEN_ELSIF* = 5; | ||||
|   TOKEN_WHILE* = 6; | ||||
|   TOKEN_DO* = 7; | ||||
|   TOKEN_PROC* = 8; | ||||
|   TOKEN_BEGIN* = 9; | ||||
|   TOKEN_END* = 10; | ||||
|   TOKEN_EXTERN* = 11; | ||||
|   TOKEN_CONST* = 12; | ||||
|   TOKEN_VAR* = 13; | ||||
|   TOKEN_ARRAY* = 14; | ||||
|   TOKEN_OF* = 15; | ||||
|   TOKEN_TYPE* = 16; | ||||
|   TOKEN_RECORD* = 17; | ||||
|   TOKEN_UNION* = 18; | ||||
|   TOKEN_POINTER* = 19; | ||||
|   TOKEN_TO* = 20; | ||||
|   TOKEN_BOOLEAN* = 21; | ||||
|   TOKEN_NIL* = 22; | ||||
|   TOKEN_AND* = 23; | ||||
|   TOKEN_OR* = 24; | ||||
|   TOKEN_NOT* = 25; | ||||
|   TOKEN_RETURN* = 26; | ||||
|   TOKEN_CAST* = 27; | ||||
|   TOKEN_SHIFT_LEFT* = 28; | ||||
|   TOKEN_SHIFT_RIGHT* = 29; | ||||
|   TOKEN_LEFT_PAREN* = 30; | ||||
|   TOKEN_RIGHT_PAREN* = 31; | ||||
|   TOKEN_LEFT_SQUARE* = 32; | ||||
|   TOKEN_RIGHT_SQUARE* = 33; | ||||
|   TOKEN_GREATER_EQUAL* = 34; | ||||
|   TOKEN_LESS_EQUAL* = 35; | ||||
|   TOKEN_GREATER_THAN* = 36; | ||||
|   TOKEN_LESS_THAN* = 37; | ||||
|   TOKEN_NOT_EQUAL* = 38; | ||||
|   TOKEN_EQUAL* = 39; | ||||
|   TOKEN_SEMICOLON* = 40; | ||||
|   TOKEN_DOT* = 41; | ||||
|   TOKEN_COMMA* = 42; | ||||
|   TOKEN_PLUS* = 43; | ||||
|   TOKEN_MINUS* = 44; | ||||
|   TOKEN_MULTIPLICATION* = 45; | ||||
|   TOKEN_DIVISION* = 46; | ||||
|   TOKEN_REMAINDER* = 47; | ||||
|   TOKEN_ASSIGNMENT* = 48; | ||||
|   TOKEN_COLON* = 49; | ||||
|   TOKEN_HAT* = 50; | ||||
|   TOKEN_AT* = 51; | ||||
|   TOKEN_COMMENT* = 52; | ||||
|   TOKEN_INTEGER* = 53; | ||||
|   TOKEN_WORD* = 54; | ||||
|   TOKEN_CHARACTER* = 55; | ||||
|   TOKEN_STRING* = 56; | ||||
|   TOKEN_DEFER* = 57; | ||||
|   TOKEN_EXCLAMATION* = 58; | ||||
|   TOKEN_ARROW = 59; | ||||
|  | ||||
| type | ||||
|   TokenKind* = ( | ||||
|     unknown, | ||||
|     identifier, | ||||
|     _if, | ||||
|     _then, | ||||
|     _else, | ||||
|     _elsif, | ||||
|     _while, | ||||
|     _do, | ||||
|     _proc, | ||||
|     _begin, | ||||
|     _end, | ||||
|     _extern, | ||||
|     _const, | ||||
|     _var, | ||||
|     array, | ||||
|     _of, | ||||
|     _type, | ||||
|     _record, | ||||
|     _union, | ||||
|     pointer, | ||||
|     to, | ||||
|     boolean, | ||||
|     _nil, | ||||
|     and, | ||||
|     _or, | ||||
|     not, | ||||
|     _return, | ||||
|     _cast, | ||||
|     shift_left, | ||||
|     shift_right, | ||||
|     left_paren, | ||||
|     right_paren, | ||||
|     left_square, | ||||
|     right_square, | ||||
|     greater_equal, | ||||
|     less_equal, | ||||
|     greater_than, | ||||
|     less_than, | ||||
|     not_equal, | ||||
|     equal, | ||||
|     semicolon, | ||||
|     dot, | ||||
|     comma, | ||||
|     plus, | ||||
|     minus, | ||||
|     multiplication, | ||||
|     division, | ||||
|     remainder, | ||||
|     assignment, | ||||
|     colon, | ||||
|     hat, | ||||
|     at, | ||||
|     comment, | ||||
|     integer, | ||||
|     word, | ||||
|     character, | ||||
|     string, | ||||
|     _defer, | ||||
|     exclamation, | ||||
|     arrow | ||||
|   ); | ||||
|   Position* = record | ||||
|     line: Word; | ||||
| 	column: Word | ||||
| @@ -93,7 +95,7 @@ type | ||||
| 	head: proc(^Byte) -> Char | ||||
|   end; | ||||
|   Token* = record | ||||
|     kind: Int; | ||||
|     kind: TokenKind; | ||||
|     value: union | ||||
|       int_value: Int; | ||||
|       string: String; | ||||
| @@ -208,12 +210,12 @@ end | ||||
|  | ||||
| proc is_alnum(c: Char) -> Bool; | ||||
| begin | ||||
|   return is_digit(c) | is_alpha(c) | ||||
|   return is_digit(c) or is_alpha(c) | ||||
| end | ||||
|  | ||||
| proc is_space(c: Char) -> Bool; | ||||
| begin | ||||
|   return c = ' ' | c = '\n' | c = '\t' | ||||
|   return c = ' ' or c = '\n' or c = '\t' | ||||
| end | ||||
|  | ||||
| proc substring(string: String, start: Word, count: Word) -> String; | ||||
| @@ -413,7 +415,7 @@ end | ||||
|  | ||||
| proc is_ident(char: Char) -> Bool; | ||||
| begin | ||||
|   return is_alnum(char) | char = '_' | ||||
|   return is_alnum(char) or char = '_' | ||||
| end | ||||
|  | ||||
| proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer); | ||||
| @@ -516,137 +518,137 @@ begin | ||||
|   while i < tokens_size do | ||||
|     current_token := tokens + i; | ||||
|  | ||||
|     if current_token^.kind = TOKEN_IF then | ||||
|     if current_token^.kind = TokenKind._if then | ||||
| 	  write_s("IF") | ||||
|     elsif current_token^.kind = TOKEN_THEN then | ||||
|     elsif current_token^.kind = TokenKind._then then | ||||
| 	  write_s("THEN") | ||||
|     elsif current_token^.kind = TOKEN_ELSE then | ||||
|     elsif current_token^.kind = TokenKind._else then | ||||
| 	  write_s("ELSE") | ||||
|     elsif current_token^.kind = TOKEN_ELSIF then | ||||
|     elsif current_token^.kind = TokenKind._elsif then | ||||
| 	  write_s("ELSIF") | ||||
|     elsif current_token^.kind = TOKEN_WHILE then | ||||
|     elsif current_token^.kind = TokenKind._while then | ||||
| 	  write_s("WHILE") | ||||
|     elsif current_token^.kind = TOKEN_DO then | ||||
|     elsif current_token^.kind = TokenKind._do then | ||||
| 	  write_s("DO") | ||||
| 	elsif current_token^.kind = TOKEN_PROC then | ||||
| 	elsif current_token^.kind = TokenKind._proc then | ||||
| 	  write_s("PROC") | ||||
| 	elsif current_token^.kind = TOKEN_BEGIN then | ||||
| 	elsif current_token^.kind = TokenKind._begin then | ||||
| 	  write_s("BEGIN") | ||||
| 	elsif current_token^.kind = TOKEN_END then | ||||
| 	elsif current_token^.kind = TokenKind._end then | ||||
| 	  write_s("END") | ||||
|    	elsif current_token^.kind = TOKEN_EXTERN then | ||||
|    	elsif current_token^.kind = TokenKind._extern then | ||||
| 	  write_s("EXTERN") | ||||
| 	elsif current_token^.kind = TOKEN_CONST then | ||||
| 	elsif current_token^.kind = TokenKind._const then | ||||
| 	  write_s("CONST") | ||||
| 	elsif current_token^.kind = TOKEN_VAR then | ||||
| 	elsif current_token^.kind = TokenKind._var then | ||||
| 	  write_s("VAR") | ||||
|    	elsif current_token^.kind = TOKEN_ARRAY then | ||||
|    	elsif current_token^.kind = TokenKind.array then | ||||
| 	  write_s("ARRAY") | ||||
| 	elsif current_token^.kind = TOKEN_OF then | ||||
| 	elsif current_token^.kind = TokenKind._of then | ||||
| 	  write_s("OF") | ||||
| 	elsif current_token^.kind = TOKEN_TYPE then | ||||
| 	elsif current_token^.kind = TokenKind._type then | ||||
| 	  write_s("TYPE") | ||||
| 	elsif current_token^.kind = TOKEN_RECORD then | ||||
| 	elsif current_token^.kind = TokenKind._record then | ||||
| 	  write_s("RECORD") | ||||
| 	elsif current_token^.kind = TOKEN_UNION then | ||||
| 	elsif current_token^.kind = TokenKind._union then | ||||
| 	  write_s("UNION") | ||||
| 	elsif current_token^.kind = TOKEN_POINTER then | ||||
| 	elsif current_token^.kind = TokenKind.pointer then | ||||
| 	  write_s("POINTER") | ||||
| 	elsif current_token^.kind = TOKEN_TO then | ||||
| 	elsif current_token^.kind = TokenKind.to then | ||||
| 	  write_s("TO") | ||||
| 	elsif current_token^.kind = TOKEN_BOOLEAN then | ||||
| 	elsif current_token^.kind = TokenKind.boolean then | ||||
| 	  write_s("BOOLEAN<"); | ||||
| 	  write_b(current_token^.value.boolean_value); | ||||
| 	  write_c('>') | ||||
| 	elsif current_token^.kind = TOKEN_NIL then | ||||
| 	elsif current_token^.kind = TokenKind._nil then | ||||
| 	  write_s("NIL") | ||||
| 	elsif current_token^.kind = TOKEN_AND then | ||||
| 	elsif current_token^.kind = TokenKind.and then | ||||
| 	  write_s("AND") | ||||
| 	elsif current_token^.kind = TOKEN_OR then | ||||
| 	elsif current_token^.kind = TokenKind._or then | ||||
| 	  write_s("OR") | ||||
| 	elsif current_token^.kind = TOKEN_NOT then | ||||
| 	elsif current_token^.kind = TokenKind.not then | ||||
| 	  write_s("NOT") | ||||
| 	elsif current_token^.kind = TOKEN_RETURN then | ||||
| 	elsif current_token^.kind = TokenKind._return then | ||||
| 	  write_s("RETURN") | ||||
| 	elsif current_token^.kind = TOKEN_CAST then | ||||
| 	elsif current_token^.kind = TokenKind._cast then | ||||
| 	  write_s("CAST") | ||||
| 	elsif current_token^.kind = TOKEN_SHIFT_LEFT then | ||||
| 	elsif current_token^.kind = TokenKind.shift_left then | ||||
| 	  write_s("<<") | ||||
| 	elsif current_token^.kind = TOKEN_SHIFT_RIGHT then | ||||
| 	elsif current_token^.kind = TokenKind.shift_right then | ||||
| 	  write_s(">>") | ||||
| 	elsif current_token^.kind = TOKEN_IDENTIFIER then | ||||
| 	elsif current_token^.kind = TokenKind.identifier then | ||||
| 	  write_c('<'); | ||||
|       write_s(current_token^.value.string); | ||||
| 	  write_c('>') | ||||
| 	elsif current_token^.kind = TOKEN_LEFT_PAREN then | ||||
| 	elsif current_token^.kind = TokenKind.left_paren then | ||||
| 	  write_s("(") | ||||
| 	elsif current_token^.kind = TOKEN_RIGHT_PAREN then | ||||
| 	elsif current_token^.kind = TokenKind.right_paren then | ||||
| 	  write_s(")") | ||||
| 	elsif current_token^.kind = TOKEN_LEFT_SQUARE then | ||||
| 	elsif current_token^.kind = TokenKind.left_square then | ||||
| 	  write_s("[") | ||||
| 	elsif current_token^.kind = TOKEN_RIGHT_SQUARE then | ||||
| 	elsif current_token^.kind = TokenKind.right_square then | ||||
| 	  write_s("]") | ||||
| 	elsif current_token^.kind = TOKEN_GREATER_EQUAL then | ||||
| 	elsif current_token^.kind = TokenKind.greater_equal then | ||||
| 	  write_s(">=") | ||||
| 	elsif current_token^.kind = TOKEN_LESS_EQUAL then | ||||
| 	elsif current_token^.kind = TokenKind.less_equal then | ||||
| 	  write_s("<=") | ||||
| 	elsif current_token^.kind = TOKEN_GREATER_THAN then | ||||
| 	elsif current_token^.kind = TokenKind.greater_than then | ||||
| 	  write_s(">") | ||||
| 	elsif current_token^.kind = TOKEN_LESS_THAN then | ||||
| 	elsif current_token^.kind = TokenKind.less_than then | ||||
| 	  write_s("<") | ||||
| 	elsif current_token^.kind = TOKEN_EQUAL then | ||||
| 	elsif current_token^.kind = TokenKind.equal then | ||||
| 	  write_s("=") | ||||
| 	elsif current_token^.kind = TOKEN_NOT_EQUAL then | ||||
| 	elsif current_token^.kind = TokenKind.not_equal then | ||||
| 	  write_s("<>") | ||||
| 	elsif current_token^.kind = TOKEN_SEMICOLON then | ||||
| 	elsif current_token^.kind = TokenKind.semicolon then | ||||
| 	  write_c(';') | ||||
| 	elsif current_token^.kind = TOKEN_DOT then | ||||
| 	elsif current_token^.kind = TokenKind.dot then | ||||
| 	  write_c('.') | ||||
| 	elsif current_token^.kind = TOKEN_COMMA then | ||||
| 	elsif current_token^.kind = TokenKind.comma then | ||||
| 	  write_c(',') | ||||
| 	elsif current_token^.kind = TOKEN_PLUS then | ||||
| 	elsif current_token^.kind = TokenKind.plus then | ||||
| 	  write_c('+') | ||||
| 	elsif current_token^.kind = TOKEN_MINUS then | ||||
| 	elsif current_token^.kind = TokenKind.minus then | ||||
| 	  write_c('-') | ||||
| 	elsif current_token^.kind = TOKEN_MULTIPLICATION then | ||||
| 	elsif current_token^.kind = TokenKind.multiplication then | ||||
| 	  write_c('*') | ||||
| 	elsif current_token^.kind = TOKEN_DIVISION then | ||||
| 	elsif current_token^.kind = TokenKind.division then | ||||
| 	  write_c('/') | ||||
| 	elsif current_token^.kind = TOKEN_REMAINDER then | ||||
| 	elsif current_token^.kind = TokenKind.remainder then | ||||
| 	  write_c('%') | ||||
| 	elsif current_token^.kind = TOKEN_ASSIGNMENT then | ||||
| 	elsif current_token^.kind = TokenKind.assignment then | ||||
| 	  write_s(":=") | ||||
| 	elsif current_token^.kind = TOKEN_COLON then | ||||
| 	elsif current_token^.kind = TokenKind.colon then | ||||
| 	  write_c(':') | ||||
| 	elsif current_token^.kind = TOKEN_HAT then | ||||
| 	elsif current_token^.kind = TokenKind.hat then | ||||
| 	  write_c('^') | ||||
| 	elsif current_token^.kind = TOKEN_AT then | ||||
| 	elsif current_token^.kind = TokenKind.at then | ||||
| 	  write_c('@') | ||||
| 	elsif current_token^.kind = TOKEN_COMMENT then | ||||
| 	elsif current_token^.kind = TokenKind.comment then | ||||
| 	  write_s("(* COMMENT *)") | ||||
| 	elsif current_token^.kind = TOKEN_INTEGER then | ||||
| 	elsif current_token^.kind = TokenKind.integer then | ||||
| 	  write_c('<'); | ||||
|       write_i(current_token^.value.int_value); | ||||
| 	  write_c('>') | ||||
| 	elsif current_token^.kind = TOKEN_WORD then | ||||
| 	elsif current_token^.kind = TokenKind.word then | ||||
| 	  write_c('<'); | ||||
|       write_i(current_token^.value.int_value); | ||||
| 	  write_s("u>") | ||||
| 	elsif current_token^.kind = TOKEN_CHARACTER then | ||||
| 	elsif current_token^.kind = TokenKind.character then | ||||
| 	  write_c('<'); | ||||
|       write_i(cast(current_token^.value.char_value: Int)); | ||||
| 	  write_s("c>") | ||||
| 	elsif current_token^.kind = TOKEN_STRING then | ||||
| 	elsif current_token^.kind = TokenKind.string then | ||||
| 	  write_s("\"...\"") | ||||
| 	elsif current_token^.kind = TOKEN_DEFER then | ||||
| 	elsif current_token^.kind = TokenKind._defer then | ||||
| 	  write_s("DEFER") | ||||
| 	elsif current_token^.kind = TOKEN_EXCLAMATION then | ||||
| 	elsif current_token^.kind = TokenKind.exclamation then | ||||
| 	  write_c('!') | ||||
| 	elsif current_token^.kind = TOKEN_ARROW then | ||||
| 	elsif current_token^.kind = TokenKind.arrow then | ||||
| 	  write_s("->") | ||||
| 	else | ||||
| 	  write_s("UNKNOWN<"); | ||||
| 	  write_i(current_token^.kind); | ||||
| 	  write_i(cast(current_token^.kind: Int)); | ||||
| 	  write_c('>') | ||||
| 	end; | ||||
| 	write_c(' '); | ||||
| @@ -661,65 +663,65 @@ var | ||||
|   current_token: Token; | ||||
| begin | ||||
|   if "if" = token_content then | ||||
| 	current_token.kind := TOKEN_IF | ||||
| 	current_token.kind := TokenKind._if | ||||
|   elsif "then" = token_content then | ||||
| 	current_token.kind := TOKEN_THEN | ||||
| 	current_token.kind := TokenKind._then | ||||
|   elsif "else" = token_content then | ||||
| 	current_token.kind := TOKEN_ELSE | ||||
| 	current_token.kind := TokenKind._else | ||||
|   elsif "elsif" = token_content then | ||||
| 	current_token.kind := TOKEN_ELSIF | ||||
| 	current_token.kind := TokenKind._elsif | ||||
|   elsif "while" = token_content then | ||||
| 	current_token.kind := TOKEN_WHILE | ||||
| 	current_token.kind := TokenKind._while | ||||
|   elsif "do" = token_content then | ||||
| 	current_token.kind := TOKEN_DO | ||||
| 	current_token.kind := TokenKind._do | ||||
|   elsif "proc" = token_content then | ||||
| 	current_token.kind := TOKEN_PROC | ||||
| 	current_token.kind := TokenKind._proc | ||||
|   elsif "begin" = token_content then | ||||
| 	current_token.kind := TOKEN_BEGIN | ||||
| 	current_token.kind := TokenKind._begin | ||||
|   elsif "end" = token_content then | ||||
| 	current_token.kind := TOKEN_END | ||||
| 	current_token.kind := TokenKind._end | ||||
|   elsif "extern" = token_content then | ||||
| 	current_token.kind := TOKEN_EXTERN | ||||
| 	current_token.kind := TokenKind._extern | ||||
|   elsif "const" = token_content then | ||||
| 	current_token.kind := TOKEN_CONST | ||||
| 	current_token.kind := TokenKind._const | ||||
|   elsif "var" = token_content then | ||||
| 	current_token.kind := TOKEN_VAR | ||||
| 	current_token.kind := TokenKind._var | ||||
|   elsif "array" = token_content then | ||||
| 	current_token.kind := TOKEN_ARRAY | ||||
| 	current_token.kind := TokenKind.array | ||||
|   elsif "of" = token_content then | ||||
| 	current_token.kind := TOKEN_OF | ||||
| 	current_token.kind := TokenKind._of | ||||
|   elsif "type" = token_content then | ||||
| 	current_token.kind := TOKEN_TYPE | ||||
| 	current_token.kind := TokenKind._type | ||||
|   elsif "record" = token_content then | ||||
| 	current_token.kind := TOKEN_RECORD | ||||
| 	current_token.kind := TokenKind._record | ||||
|   elsif "union" = token_content then | ||||
| 	current_token.kind := TOKEN_UNION | ||||
| 	current_token.kind := TokenKind._union | ||||
|   elsif "pointer" = token_content then | ||||
| 	current_token.kind := TOKEN_POINTER | ||||
| 	current_token.kind := TokenKind.pointer | ||||
|   elsif "to" = token_content then | ||||
| 	current_token.kind := TOKEN_TO | ||||
| 	current_token.kind := TokenKind.to | ||||
|   elsif "true" = token_content then | ||||
| 	current_token.kind := TOKEN_BOOLEAN; | ||||
| 	current_token.kind := TokenKind.boolean; | ||||
| 	current_token.value.boolean_value := true | ||||
|   elsif "false" = token_content then | ||||
| 	current_token.kind := TOKEN_BOOLEAN; | ||||
| 	current_token.kind := TokenKind.boolean; | ||||
| 	current_token.value.boolean_value := false | ||||
|   elsif "nil" = token_content then | ||||
| 	current_token.kind := TOKEN_NIL | ||||
| 	current_token.kind := TokenKind._nil | ||||
|   elsif "and" = token_content then | ||||
| 	current_token.kind := TOKEN_AND | ||||
| 	current_token.kind := TokenKind.and | ||||
|   elsif "or" = token_content then | ||||
| 	current_token.kind := TOKEN_OR | ||||
| 	current_token.kind := TokenKind._or | ||||
|   elsif "not" = token_content then | ||||
| 	current_token.kind := TOKEN_NOT | ||||
| 	current_token.kind := TokenKind.not | ||||
|   elsif "return" = token_content then | ||||
| 	current_token.kind := TOKEN_RETURN | ||||
| 	current_token.kind := TokenKind._return | ||||
|   elsif "cast" = token_content then | ||||
| 	current_token.kind := TOKEN_CAST | ||||
| 	current_token.kind := TokenKind._cast | ||||
|   elsif "defer" = token_content then | ||||
| 	current_token.kind := TOKEN_DEFER | ||||
| 	current_token.kind := TokenKind._defer | ||||
|   else | ||||
| 	current_token.kind := TOKEN_IDENTIFIER; | ||||
| 	current_token.kind := TokenKind.identifier; | ||||
| 	current_token.value.string := string_dup(token_content) | ||||
|   end; | ||||
|  | ||||
| @@ -743,154 +745,154 @@ begin | ||||
|     current_token := tokens + tokens_size^; | ||||
| 	first_char := source_code_head(source_code); | ||||
|  | ||||
|     if is_alpha(first_char) | first_char = '_' then | ||||
|     if is_alpha(first_char) or first_char = '_' then | ||||
|       lex_identifier(@source_code, @token_buffer); | ||||
|       current_token^ := categorize_identifier(string_buffer_clear(@token_buffer)) | ||||
| 	elsif is_digit(first_char) then | ||||
| 	  lex_number(@source_code, @current_token^.value.int_value); | ||||
|  | ||||
| 	  if source_code_expect(@source_code, 'u') then | ||||
| 	    current_token^.kind := TOKEN_WORD; | ||||
| 	    current_token^.kind := TokenKind.word; | ||||
|         source_code_advance(@source_code) | ||||
| 	  else | ||||
| 	    current_token^.kind := TOKEN_INTEGER | ||||
| 	    current_token^.kind := TokenKind.integer | ||||
| 	  end | ||||
| 	elsif first_char = '(' then | ||||
| 	  source_code_advance(@source_code); | ||||
|  | ||||
| 	  if source_code_empty(@source_code) then | ||||
| 	    current_token^.kind := TOKEN_LEFT_PAREN | ||||
| 	    current_token^.kind := TokenKind.left_paren | ||||
| 	  elsif source_code_head(source_code) = '*' then | ||||
| 	    source_code_advance(@source_code); | ||||
|  | ||||
| 		if lex_comment(@source_code, @token_buffer) then | ||||
| 	      current_token^.value.string := string_dup(string_buffer_clear(@token_buffer)); | ||||
| 		  current_token^.kind := TOKEN_COMMENT | ||||
| 		  current_token^.kind := TokenKind.comment | ||||
| 		else | ||||
| 	      current_token^.kind := 0 | ||||
| 	      current_token^.kind := TokenKind.unknown | ||||
| 		end | ||||
| 	  else | ||||
| 	    current_token^.kind := TOKEN_LEFT_PAREN | ||||
| 	    current_token^.kind := TokenKind.left_paren | ||||
| 	  end | ||||
| 	elsif first_char = ')' then | ||||
| 	  current_token^.kind := TOKEN_RIGHT_PAREN; | ||||
| 	  current_token^.kind := TokenKind.right_paren; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '\'' then | ||||
|       source_code_advance(@source_code); | ||||
|  | ||||
| 	  if lex_character(@source_code, @current_token^.value.char_value) & source_code_expect(@source_code, '\'') then | ||||
| 	  	current_token^.kind := TOKEN_CHARACTER; | ||||
| 	  	current_token^.kind := TokenKind.character; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  else | ||||
| 	    current_token^.kind := 0 | ||||
| 	    current_token^.kind := TokenKind.unknown | ||||
| 	  end | ||||
| 	elsif first_char = '"' then | ||||
|       source_code_advance(@source_code); | ||||
| 	   | ||||
|       if lex_string(@source_code, @token_buffer) then | ||||
| 		current_token^.kind := TOKEN_STRING; | ||||
| 		current_token^.kind := TokenKind.string; | ||||
| 		current_token^.value.string := string_dup(string_buffer_clear(@token_buffer)) | ||||
| 	  else | ||||
| 	    current_token^.kind := 0 | ||||
| 	    current_token^.kind := TokenKind.unknown | ||||
| 	  end | ||||
| 	elsif first_char = '[' then | ||||
| 	  current_token^.kind := TOKEN_LEFT_SQUARE; | ||||
| 	  current_token^.kind := TokenKind.left_square; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = ']' then | ||||
| 	  current_token^.kind := TOKEN_RIGHT_SQUARE; | ||||
| 	  current_token^.kind := TokenKind.right_square; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '>' then | ||||
| 	  source_code_advance(@source_code); | ||||
|  | ||||
|       if source_code_empty(@source_code) then | ||||
| 	    current_token^.kind := TOKEN_GREATER_THAN | ||||
| 	    current_token^.kind := TokenKind.greater_than | ||||
| 	  elsif source_code_head(source_code) = '=' then | ||||
| 	    current_token^.kind := TOKEN_GREATER_EQUAL; | ||||
| 	    current_token^.kind := TokenKind.greater_equal; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  elsif source_code_head(source_code) = '>' then | ||||
| 	    current_token^.kind := TOKEN_SHIFT_RIGHT; | ||||
| 	    current_token^.kind := TokenKind.shift_right; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  else | ||||
| 	    current_token^.kind := TOKEN_GREATER_THAN | ||||
| 	    current_token^.kind := TokenKind.greater_than | ||||
| 	  end | ||||
| 	elsif first_char = '<' then | ||||
| 	  source_code_advance(@source_code); | ||||
|  | ||||
| 	  if source_code_empty(@source_code) then | ||||
| 	    current_token^.kind := TOKEN_LESS_THAN | ||||
| 	    current_token^.kind := TokenKind.less_than | ||||
| 	  elsif source_code_head(source_code) = '=' then | ||||
| 	    current_token^.kind := TOKEN_LESS_EQUAL; | ||||
| 	    current_token^.kind := TokenKind.less_equal; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  elsif source_code_head(source_code) = '<' then | ||||
| 	    current_token^.kind := TOKEN_SHIFT_LEFT; | ||||
| 	    current_token^.kind := TokenKind.shift_left; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  elsif source_code_head(source_code) = '>' then | ||||
| 	    current_token^.kind := TOKEN_NOT_EQUAL; | ||||
| 	    current_token^.kind := TokenKind.not_equal; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  else | ||||
| 	    current_token^.kind := TOKEN_LESS_THAN | ||||
| 	    current_token^.kind := TokenKind.less_than | ||||
| 	  end | ||||
| 	elsif first_char = '=' then | ||||
| 	  current_token^.kind := TOKEN_EQUAL; | ||||
| 	  current_token^.kind := TokenKind.equal; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = ';' then | ||||
| 	  current_token^.kind := TOKEN_SEMICOLON; | ||||
| 	  current_token^.kind := TokenKind.semicolon; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '.' then | ||||
| 	  current_token^.kind := TOKEN_DOT; | ||||
| 	  current_token^.kind := TokenKind.dot; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = ',' then | ||||
| 	  current_token^.kind := TOKEN_COMMA; | ||||
| 	  current_token^.kind := TokenKind.comma; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '+' then | ||||
| 	  current_token^.kind := TOKEN_PLUS; | ||||
| 	  current_token^.kind := TokenKind.plus; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '-' then | ||||
| 	  source_code_advance(@source_code); | ||||
|  | ||||
|       if source_code_empty(@source_code) then | ||||
| 	    current_token^.kind := TOKEN_MINUS | ||||
| 	    current_token^.kind := TokenKind.minus | ||||
| 	  elsif source_code_head(source_code) = '>' then | ||||
| 	    current_token^.kind := TOKEN_ARROW; | ||||
| 	    current_token^.kind := TokenKind.arrow; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  else | ||||
| 	    current_token^.kind := TOKEN_MINUS | ||||
| 	    current_token^.kind := TokenKind.minus | ||||
| 	  end | ||||
| 	elsif first_char = '*' then | ||||
| 	  current_token^.kind := TOKEN_MULTIPLICATION; | ||||
| 	  current_token^.kind := TokenKind.multiplication; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '/' then | ||||
| 	  current_token^.kind := TOKEN_DIVISION; | ||||
| 	  current_token^.kind := TokenKind.division; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '%' then | ||||
| 	  current_token^.kind := TOKEN_REMAINDER; | ||||
| 	  current_token^.kind := TokenKind.remainder; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = ':' then | ||||
| 	  source_code_advance(@source_code); | ||||
|  | ||||
| 	  if source_code_empty(@source_code) then | ||||
| 	    current_token^.kind := TOKEN_COLON | ||||
| 	    current_token^.kind := TokenKind.colon | ||||
| 	  elsif source_code_head(source_code) = '=' then | ||||
| 	    current_token^.kind := TOKEN_ASSIGNMENT; | ||||
| 	    current_token^.kind := TokenKind.assignment; | ||||
| 	    source_code_advance(@source_code) | ||||
| 	  else | ||||
| 	    current_token^.kind := TOKEN_COLON | ||||
| 	    current_token^.kind := TokenKind.colon | ||||
| 	  end | ||||
| 	elsif first_char = '^' then | ||||
| 	  current_token^.kind := TOKEN_HAT; | ||||
| 	  current_token^.kind := TokenKind.hat; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '@' then | ||||
| 	  current_token^.kind := TOKEN_AT; | ||||
| 	  current_token^.kind := TokenKind.at; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	elsif first_char = '!' then | ||||
| 	  current_token^.kind := TOKEN_EXCLAMATION; | ||||
| 	  current_token^.kind := TokenKind.exclamation; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	else | ||||
| 	  current_token^.kind := 0; | ||||
| 	  current_token^.kind := TokenKind.unknown; | ||||
| 	  source_code_advance(@source_code) | ||||
| 	end; | ||||
|  | ||||
| 	if current_token^.kind <> 0 then | ||||
| 	if current_token^.kind <> TokenKind.unknown then | ||||
|       tokens_size^ := tokens_size^ + 1u; | ||||
|       skip_spaces(@source_code) | ||||
| 	else | ||||
|   | ||||
		Reference in New Issue
	
	Block a user