diff --git a/boot/ast.cc b/boot/ast.cc index 0ac0b81..c36ffde 100644 --- a/boot/ast.cc +++ b/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&& 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&& 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&& 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, diff --git a/boot/lexer.ll b/boot/lexer.ll index 5029bf5..9827ba0 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -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); } diff --git a/boot/parser.yy b/boot/parser.yy index ea6df6f..90657d9 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -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 literal; +%type > case_labels; +%type switch_case; +%type > switch_cases; %type constant_definition; %type > constant_part constant_definitions; %type > variable_declarations variable_part variable_declaration; %type type_expression; %type > type_expressions; %type traits_expression; -%type expression operand qualident; +%type expression operand simple_expression; +%type qualident; %type unary_expression; %type binary_expression; %type > expressions actual_parameter_list; %type designator_expression; -%type assign_statement; %type call_expression; %type while_statement; %type if_statement; @@ -154,9 +160,9 @@ along with GCC; see the file COPYING3. If not see optional_fields required_fields formal_parameters; %type > elsif_then_statements elsif_do_statements; %type cast_expression; -%type defer_statement; %type > identifier_definition; %type >> identifier_definitions; +%type > 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 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: diff --git a/boot/semantic.cc b/boot/semantic.cc index 6c9f456..ad2e9d6 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -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 result_type = std::make_shared(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(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 *) + void declaration_visitor::visit(literal *literal) { + this->current_literal = literal->value; } - void declaration_visitor::visit(literal *) + void declaration_visitor::visit(literal *literal) { + this->current_literal = literal->value; } - void declaration_visitor::visit(literal *) + void declaration_visitor::visit(literal *literal) { + this->current_literal = literal->value; } - void declaration_visitor::visit(literal *) + void declaration_visitor::visit(literal *literal) { + this->current_literal = literal->value; } - void declaration_visitor::visit(literal *) + void declaration_visitor::visit(literal *literal) { + this->current_literal = literal->value; } - void declaration_visitor::visit(literal *) + void declaration_visitor::visit(literal *literal) { + this->current_literal = literal->value; } - void declaration_visitor::visit(literal *) + void declaration_visitor::visit(literal *literal) { + this->current_literal = literal->value; } } diff --git a/boot/symbol.cc b/boot/symbol.cc index 643ea4e..9712935 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -58,6 +58,11 @@ namespace elna::boot { } + type::type(std::shared_ptr 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(other.procedure); break; + case type_tag::enumeration: + new (&enumeration) std::shared_ptr(other.enumeration); + break; } } @@ -121,6 +129,9 @@ namespace elna::boot case type_tag::procedure: new (&procedure) std::shared_ptr(std::move(other.procedure)); break; + case type_tag::enumeration: + new (&enumeration) std::shared_ptr(std::move(other.enumeration)); + break; } } @@ -178,6 +189,9 @@ namespace elna::boot case type_tag::procedure: this->procedure.~shared_ptr(); break; + case type_tag::enumeration: + this->enumeration.~shared_ptr(); + break; } } @@ -223,6 +237,12 @@ namespace elna::boot return tag == type_tag::procedure ? this->procedure : nullptr; } + template<> + std::shared_ptr type::get() 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& members) + : members(members) + { + } + info::~info() { } @@ -287,6 +312,11 @@ namespace elna::boot return std::static_pointer_cast(shared_from_this()); } + constant_info::constant_info(const variant& symbol) + : symbol(symbol) + { + } + std::shared_ptr builtin_symbol_table() { auto result = std::make_shared(); diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index ea92ece..ddcbf15 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -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 "<>"; diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index ff13659..ed68304 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -57,6 +57,10 @@ namespace elna::gcc { return make_node(UNION_TYPE); } + else if (auto reference = type.get()) + { + return make_node(ENUMERAL_TYPE); + } else if (auto reference = type.get()) { 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; + } } diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 635e4b5..a2d7b5a 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -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; + } } diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 65a3f5b..c5d2c76 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -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 members; + + enumeration_type_expression(const struct position, std::vector&& 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 *is_int() = 0; - virtual literal *is_word() = 0; - virtual literal *is_float() = 0; - virtual literal *is_bool() = 0; - virtual literal *is_char() = 0; - virtual literal *is_nil() = 0; - virtual literal *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 labels; + std::vector statements; + }; + + class case_statement : public statement + { + expression *m_condition; + + public: + const std::vector cases; + + case_statement(const struct position position, expression *condition, std::vector&& cases); + void accept(parser_visitor *visitor) override; + expression& condition(); + }; + class designator_expression : public expression { public: @@ -635,90 +662,6 @@ namespace elna::boot { } - literal *is_int() override - { - if (std::is_same::value) - { - return reinterpret_cast *>(this); - } - else - { - return nullptr; - } - } - - literal *is_word() override - { - if (std::is_same::value) - { - return reinterpret_cast *>(this); - } - else - { - return nullptr; - } - } - - literal *is_float() override - { - if (std::is_same::value) - { - return reinterpret_cast *>(this); - } - else - { - return nullptr; - } - } - - literal *is_bool() override - { - if (std::is_same::value) - { - return reinterpret_cast *>(this); - } - else - { - return nullptr; - } - } - - literal *is_char() override - { - if (std::is_same::value) - { - return reinterpret_cast *>(this); - } - else - { - return nullptr; - } - } - - literal *is_nil() override - { - if (std::is_same::value) - { - return reinterpret_cast *>(this); - } - else - { - return nullptr; - } - } - - literal *is_string() override - { - if (std::is_same::value) - { - return reinterpret_cast *>(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 statements; + const std::vector statements; - defer_statement(const struct position position); + defer_statement(const struct position position, std::vector&& statements); void accept(parser_visitor *visitor) override; defer_statement *is_defer() override; diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index 76de3dd..a74b9b6 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -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 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 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 *) override; - void visit(literal *) override; - void visit(literal *) override; - void visit(literal *) override; - void visit(literal *) override; - void visit(literal *) override; - void visit(literal *) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; + void visit(literal *literal) override; }; } diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 45629c8..ba48e17 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -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; std::shared_ptr array; std::shared_ptr procedure; + std::shared_ptr enumeration; }; void copy(const type& other); @@ -72,6 +75,7 @@ namespace elna::boot explicit type(std::shared_ptr pointer); explicit type(std::shared_ptr array); explicit type(std::shared_ptr procedure); + explicit type(std::shared_ptr 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 members; + + explicit enumeration_type(const std::vector& members); + }; + class type_info; class procedure_info; + class constant_info; class info : public std::enable_shared_from_this { @@ -174,6 +186,17 @@ namespace elna::boot std::shared_ptr is_procedure() override; }; + class constant_info : public info + { + public: + using variant = typename + std::variant; + + const variant symbol; + + explicit constant_info(const variant& symbol); + }; + /** * Symbol table. */ diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index dca60bb..c2f13da 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -47,7 +47,6 @@ namespace elna::gcc std::unordered_map 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& 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; }; } diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 4f026e6..223fe52 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -33,7 +33,6 @@ namespace elna::gcc { using symbol_table = boot::symbol_map; - 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); } diff --git a/source.elna b/source.elna index 695b0e1..efbc560 100644 --- a/source.elna +++ b/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