diff --git a/README.md b/README.md index 6903e26..ac33bce 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ program = [ "type" type_definitions ";" ] [ constant_part ] { procedure_definition } [ variable_part ] - compound_statement "."; + "begin" [ statement_list ] "end" "."; procedure_definition = "proc" ident formal_parameter_list ";" ( block | "extern" ) ";"; @@ -45,14 +45,18 @@ block = [ constant_part ] constant_part = "const" ident "=" integer { "," ident "=" integer } ";"; variable_part = "var" variable_declarations ";"; -statement = compound_statement - | ident ":=" expression +statement = ident ":=" expression | ident actual_parameter_list - | "while" condition "do" statement - | "if" expression "then" statement [ else statement ]; + | while_do + | if_then_else; + + +while_do = "while" condition "do" [ statement_list ] "end"; +if_then_else = "if" expression + "then" [ statement_list ] + [ else statement_list ] "end"; statement_list = statement {";" statement }; -compound_statement = "begin" [ statement_list ] "end"; condition = "odd" expression | expression ("="|"#"|"<"|"<="|">"|">=") expression; @@ -86,8 +90,9 @@ variable_declarations = variable_declaration { ";" variable_declaration }; variable_declaration = ident ":" type_expression; type_expression = "array" integer "of" type_expression - | "^" type_expression + | "pointer" "to" type_expression | "record" field_list "end" + | "union" field_list "end" | ident; field_list = field_declaration { ";" field_declaration }; diff --git a/example.elna b/example.elna index d56148f..9526d90 100644 --- a/example.elna +++ b/example.elna @@ -3,6 +3,10 @@ type R = record x: Int; y: Int + end, + U = union + a: Int; + b: Int end; proc test_string(); @@ -25,14 +29,13 @@ begin x := 0; while x < 2 do - begin writei(a[x]); x := x + 1 end end; proc test_pointer(); -var x: Int, p: ^Int; +var x: Int, p: pointer to Int; begin x := 5; p := @x; @@ -55,6 +58,17 @@ begin writei(r.y) end; +proc test_union(); +var u: U; +begin + writei(""); + writei("Test union:"); + + u.a := 9; + + writei(u.b) +end; + proc test_primitive(); var c: Char, z: Float; begin @@ -89,6 +103,7 @@ begin writei("Test if: True") else writei("Test if: False") + end end; proc test_not(); @@ -101,6 +116,7 @@ begin writei("Test not true.") else writei("Test not false") + end end; proc test_param(d: Int, e: Int); @@ -132,6 +148,7 @@ begin test_not(); test_param(8, 7); test_const_char(); + test_union(); exit(0) end. diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 6e6bfe8..b8a2cb2 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -15,9 +15,9 @@ namespace elna { namespace gcc { - generic_visitor::generic_visitor() + generic_visitor::generic_visitor(std::shared_ptr> symbol_table) { - this->symbol_map = std::make_shared>(); + this->symbol_map = symbol_table; } void generic_visitor::visit(source::call_statement *statement) @@ -270,7 +270,7 @@ namespace gcc this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str()); } - void generic_visitor::build_binarary_operation(bool condition, source::binary_expression *expression, + void generic_visitor::build_binary_operation(bool condition, source::binary_expression *expression, tree_code operator_code, tree left, tree right, tree target_type) { auto expression_location = get_location(&expression->position()); @@ -354,7 +354,7 @@ namespace gcc } if (operator_code != ERROR_MARK) // An arithmetic operation. { - build_binarary_operation(left_type == integer_type_node || left_type == double_type_node, + build_binary_operation(left_type == integer_type_node || left_type == double_type_node, expression, operator_code, left, right, target_type); return; } @@ -373,7 +373,7 @@ namespace gcc } if (operator_code != ERROR_MARK) // A logical operation. { - build_binarary_operation(left_type == boolean_type_node, + build_binary_operation(left_type == boolean_type_node, expression, operator_code, left, right, target_type); return; } @@ -538,7 +538,7 @@ namespace gcc tree record_type_node = make_node(RECORD_TYPE); tree_chain record_chain; - for (auto& field : record_type->fields()) + for (auto& field : record_type->fields) { if (field_names.find(field.first) != field_names.cend()) { @@ -564,6 +564,38 @@ namespace gcc return record_type_node; } + else if (source::union_type_expression *union_type = type.is_union()) + { + std::set field_names; + tree union_type_node = make_node(UNION_TYPE); + tree_chain union_chain; + + for (auto& field : union_type->fields) + { + if (field_names.find(field.first) != field_names.cend()) + { + error_at(get_location(&field.second->position()), "repeated field name"); + return error_mark_node; + } + field_names.insert(field.first); + + tree field_type = build_type(*field.second); + if (field_type == NULL_TREE || field_type == error_mark_node) + { + return field_type; + } + tree field_declaration = build_decl(get_location(&field.second->position()), + FIELD_DECL, get_identifier(field.first.c_str()), field_type); + TREE_ADDRESSABLE(field_declaration) = 1; + DECL_CONTEXT(field_declaration) = union_type_node; + + union_chain.append(field_declaration); + } + TYPE_FIELDS(union_type_node) = union_chain.head(); + layout_type(union_type_node); + + return union_type_node; + } return NULL_TREE; } diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 3e91f74..6cac5ee 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -34,12 +34,6 @@ namespace gcc return TREE_CODE(type) == ARRAY_TYPE; } - bool is_record_type(tree type) - { - gcc_assert(TYPE_P(type)); - return TREE_CODE(type) == RECORD_TYPE; - } - tree tree_chain_base::head() { return first; @@ -79,5 +73,10 @@ namespace gcc { return m_block; } + + std::shared_ptr> builtin_symbol_table() + { + return std::make_shared>(); + } } } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 96d6856..905d376 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -31,11 +31,11 @@ namespace gcc void enter_scope(); tree_symbol_mapping leave_scope(); - void build_binarary_operation(bool condition, source::binary_expression *expression, + void build_binary_operation(bool condition, source::binary_expression *expression, tree_code operator_code, tree left, tree right, tree target_type); public: - generic_visitor(); + generic_visitor(std::shared_ptr> symbol_table); void visit(source::program *program) override; void visit(source::procedure_definition *definition) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index a4ecdd5..64f5e31 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -26,7 +26,6 @@ namespace gcc bool is_pointer_type(tree type); bool is_string_type(tree type); bool is_array_type(tree type); - bool is_record_type(tree type); class tree_chain_base { @@ -58,5 +57,7 @@ namespace gcc tree bind_expression(); tree block(); }; + + std::shared_ptr> builtin_symbol_table(); } } diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index dd99e53..d363aa9 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -52,6 +52,7 @@ namespace source class array_type_expression; class pointer_type_expression; class record_type_expression; + class union_type_expression; class variable_expression; class array_access_expression; class field_access_expression; @@ -83,6 +84,7 @@ namespace source 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(variable_expression *) = 0; virtual void visit(array_access_expression *) = 0; virtual void visit(field_access_expression *is_field_access) = 0; @@ -116,6 +118,7 @@ namespace source virtual void visit(array_type_expression *expression) override; virtual void visit(pointer_type_expression *) override; virtual void visit(record_type_expression *expression) override; + virtual void visit(union_type_expression *expression) override; virtual void visit(variable_expression *) override; virtual void visit(array_access_expression *expression) override; virtual void visit(field_access_expression *expression) override; @@ -253,6 +256,7 @@ namespace source virtual array_type_expression *is_array(); virtual pointer_type_expression *is_pointer(); virtual record_type_expression *is_record(); + virtual union_type_expression *is_union(); protected: type_expression(const struct position position); @@ -310,23 +314,36 @@ namespace source virtual ~pointer_type_expression() override; }; - class record_type_expression final : public type_expression + using field_t = std::pair; + using fields_t = std::vector; + + class composite_type_expression : public type_expression + { + protected: + composite_type_expression(const struct position position, fields_t&& fields); + + public: + fields_t fields; + + virtual ~composite_type_expression() override; + }; + + class record_type_expression final : public composite_type_expression { public: - using field_t = std::pair; - using fields_t = std::vector; - record_type_expression(const struct position position, fields_t&& fields); + virtual void accept(parser_visitor *visitor) override; - - fields_t& fields(); - record_type_expression *is_record() override; + }; - virtual ~record_type_expression() override; + class union_type_expression final : public composite_type_expression + { + public: + union_type_expression(const struct position position, fields_t&& fields); - private: - fields_t m_fields; + virtual void accept(parser_visitor *visitor) override; + union_type_expression *is_union() override; }; /** @@ -443,13 +460,11 @@ namespace source class compound_statement : public statement { - std::vector m_statements; - public: - explicit compound_statement(const struct position position); - virtual void accept(parser_visitor *visitor) override; + std::vector statements; - std::vector& statements(); + compound_statement(const struct position position, std::vector&& statements); + virtual void accept(parser_visitor *visitor) override; virtual ~compound_statement() override; }; @@ -556,8 +571,8 @@ namespace source class if_statement : public statement { expression *m_prerequisite; - statement *m_body; - statement *m_alternative; + compound_statement *m_body; + compound_statement *m_alternative; public: /** @@ -567,12 +582,12 @@ namespace source * \param alternative Statement executed if the condition is not met. */ if_statement(const struct position position, expression *prerequisite, - statement *body, statement *alternative = nullptr); + compound_statement *body, compound_statement *alternative = nullptr); virtual void accept(parser_visitor *visitor) override; expression& prerequisite(); - statement& body(); - statement *alternative(); + compound_statement& body(); + compound_statement *alternative(); virtual ~if_statement() override; }; @@ -583,7 +598,7 @@ namespace source class while_statement : public statement { expression *m_prerequisite; - statement *m_body; + compound_statement *m_body; public: /** @@ -592,11 +607,11 @@ namespace source * \param body Statement executed while the condition is met. */ while_statement(const struct position position, expression *prerequisite, - statement *body); + compound_statement *body); virtual void accept(parser_visitor *visitor) override; expression& prerequisite(); - statement& body(); + compound_statement& body(); virtual ~while_statement() override; }; diff --git a/source/ast.cc b/source/ast.cc index fdbe984..07d6837 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -43,7 +43,7 @@ namespace source void empty_visitor::visit(compound_statement *statement) { - for (auto& nested_statement : statement->statements()) + for (const auto nested_statement : statement->statements) { nested_statement->accept(this); } @@ -114,7 +114,15 @@ namespace source void empty_visitor::visit(record_type_expression *expression) { - for (auto& field : expression->fields()) + for (auto& field : expression->fields) + { + field.second->accept(this); + } + } + + void empty_visitor::visit(union_type_expression *expression) + { + for (auto& field : expression->fields) { field.second->accept(this); } @@ -244,6 +252,11 @@ namespace source return nullptr; } + union_type_expression *type_expression::is_union() + { + return nullptr; + } + pointer_type_expression *type_expression::is_pointer() { return nullptr; @@ -321,9 +334,23 @@ namespace source delete m_base; } + composite_type_expression::composite_type_expression(const struct position position, + fields_t&& fields) + : type_expression(position), fields(std::move(fields)) + { + } + + composite_type_expression::~composite_type_expression() + { + for (auto& field_declaration : fields) + { + delete field_declaration.second; + } + } + record_type_expression::record_type_expression(const struct position position, - record_type_expression::fields_t&& fields) - : type_expression(position), m_fields(std::move(fields)) + fields_t&& fields) + : composite_type_expression(position, std::move(fields)) { } @@ -332,22 +359,25 @@ namespace source visitor->visit(this); } - record_type_expression::fields_t& record_type_expression::fields() - { - return m_fields; - } - record_type_expression *record_type_expression::is_record() { return this; } - record_type_expression::~record_type_expression() + union_type_expression::union_type_expression(const struct position position, + fields_t&& fields) + : composite_type_expression(position, std::move(fields)) { - for (auto& field_declaration : fields()) - { - delete field_declaration.second; - } + } + + union_type_expression *union_type_expression::is_union() + { + return this; + } + + void union_type_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); } variable_declaration::variable_declaration(const struct position position, const std::string& identifier, @@ -766,8 +796,8 @@ namespace source } } - compound_statement::compound_statement(const struct position position) - : statement(position) + compound_statement::compound_statement(const struct position position, std::vector&& statements) + : statement(position), statements(std::move(statements)) { } @@ -776,14 +806,9 @@ namespace source visitor->visit(this); } - std::vector& compound_statement::statements() - { - return m_statements; - } - compound_statement::~compound_statement() { - for (auto statement : m_statements) + for (auto statement : statements) { delete statement; } @@ -836,7 +861,7 @@ namespace source } if_statement::if_statement(const struct position position, expression *prerequisite, - statement *body, statement *alternative) + compound_statement *body, compound_statement *alternative) : statement(position), m_prerequisite(prerequisite), m_body(body), m_alternative(alternative) { @@ -852,12 +877,12 @@ namespace source return *m_prerequisite; } - statement& if_statement::body() + compound_statement& if_statement::body() { return *m_body; } - statement *if_statement::alternative() + compound_statement *if_statement::alternative() { return m_alternative; } @@ -874,7 +899,7 @@ namespace source } while_statement::while_statement(const struct position position, expression *prerequisite, - statement *body) + compound_statement *body) : statement(position), m_prerequisite(prerequisite), m_body(body) { } @@ -889,7 +914,7 @@ namespace source return *m_prerequisite; } - statement& while_statement::body() + compound_statement& while_statement::body() { return *m_body; } diff --git a/source/lexer.ll b/source/lexer.ll index 6f5c397..75c1925 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -76,6 +76,15 @@ type { record { return yy::parser::make_RECORD(this->location); } +union { + return yy::parser::make_UNION(this->location); + } +pointer { + return yy::parser::make_POINTER(this->location); + } +to { + return yy::parser::make_TO(this->location); + } true { return yy::parser::make_BOOLEAN(true, this->location); } diff --git a/source/parser.yy b/source/parser.yy index 57aaf5a..06582bc 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -62,8 +62,8 @@ %token CHARACTER "character" %token STRING "string" %token BOOLEAN -%token IF WHILE DO -%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD +%token IF WHILE DO THEN ELSE +%token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION %token BEGIN_BLOCK END_BLOCK EXTERN %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA %token AND OR NOT @@ -71,9 +71,6 @@ %token PLUS MINUS MULTIPLICATION DIVISION %token ASSIGNMENT COLON HAT AT -%precedence THEN -%precedence ELSE - %type literal; %type constant_definition; %type > constant_part constant_definitions; @@ -84,7 +81,6 @@ %type expression pointer summand factor comparand logical_operand; %type > expressions actual_parameter_list; %type designator_expression; -%type compound_statement; %type assign_statement; %type call_statement; %type while_statement; @@ -167,11 +163,6 @@ procedure_definitions: procedure_part: /* no procedure definitions */ {} | procedure_definitions { std::swap($$, $1); } -compound_statement: BEGIN_BLOCK optional_statements END_BLOCK - { - $$ = new elna::source::compound_statement(elna::source::make_position(@1)); - std::swap($$->statements(), $2); - } assign_statement: designator_expression ASSIGNMENT expression { $$ = new elna::source::assign_statement(elna::source::make_position(@1), $1, $3); @@ -181,21 +172,22 @@ call_statement: IDENTIFIER actual_parameter_list $$ = new elna::source::call_statement(elna::source::make_position(@1), $1); std::swap($$->arguments(), $2); } -while_statement: WHILE expression DO statement +while_statement: WHILE expression DO optional_statements END_BLOCK { - $$ = new elna::source::while_statement(elna::source::make_position(@1), - $2, $4); + auto body = new elna::source::compound_statement(elna::source::make_position(@3), std::move($4)); + $$ = new elna::source::while_statement(elna::source::make_position(@1), $2, body); } if_statement: - IF expression THEN statement + IF expression THEN optional_statements END_BLOCK { - $$ = new elna::source::if_statement(elna::source::make_position(@1), - $2, $4); + auto then = new elna::source::compound_statement(elna::source::make_position(@3), std::move($4)); + $$ = new elna::source::if_statement(elna::source::make_position(@1), $2, then); } - | IF expression THEN statement ELSE statement + | IF expression THEN optional_statements ELSE optional_statements END_BLOCK { - $$ = new elna::source::if_statement(elna::source::make_position(@1), - $2, $4, $6); + auto then = new elna::source::compound_statement(elna::source::make_position(@3), std::move($4)); + auto _else = new elna::source::compound_statement(elna::source::make_position(@5), std::move($6)); + $$ = new elna::source::if_statement(elna::source::make_position(@1), $2, then, _else); } literal: INTEGER @@ -315,8 +307,7 @@ designator_expression: $$ = new elna::source::variable_expression(elna::source::make_position(@1), $1); } statement: - compound_statement { $$ = $1; } - | assign_statement { $$ = $1; } + assign_statement { $$ = $1; } | call_statement { $$ = $1; } | while_statement { $$ = $1; } | if_statement { $$ = $1; } @@ -344,14 +335,18 @@ type_expression: { $$ = new elna::source::array_type_expression(elna::source::make_position(@1), $4, $2); } - | HAT type_expression + | POINTER TO type_expression { - $$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $2); + $$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $3); } | RECORD field_list END_BLOCK { $$ = new elna::source::record_type_expression(elna::source::make_position(@1), std::move($2)); } + | UNION field_list END_BLOCK + { + $$ = new elna::source::union_type_expression(elna::source::make_position(@1), std::move($2)); + } | IDENTIFIER { $$ = new elna::source::basic_type_expression(elna::source::make_position(@1), $1); @@ -359,7 +354,7 @@ type_expression: variable_declaration: IDENTIFIER COLON type_expression { $$ = new elna::source::variable_declaration(elna::source::make_position(@1), $1, $3); - }; + } variable_declarations: variable_declaration COMMA variable_declarations {