diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index e19eea5..27f60bb 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -36,6 +36,10 @@ namespace gcc { return "String"; } + else if (is_array_type(type)) + { + return "array"; + } else { return "<>"; diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 96c9435..852463a 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -282,6 +282,36 @@ namespace gcc this->current_expression = NULL_TREE; } + void generic_visitor::visit(source::type_definition *definition) + { + tree tree_type = build_type(definition->body()); + + if (tree_type == NULL_TREE) + { + return; + } + location_t definition_location = get_location(&definition->position()); + tree definition_tree = build_decl(definition_location, TYPE_DECL, + get_identifier(definition->identifier().c_str()), tree_type); + auto result = this->symbol_map.insert({ definition->identifier(), definition_tree }); + + if (result.second) + { + DECL_CONTEXT(definition_tree) = this->main_fndecl; + variable_chain.append(definition_tree); + + auto declaration_statement = build1_loc(definition_location, DECL_EXPR, + void_type_node, definition_tree); + append_to_statement_list(declaration_statement, &this->current_statements); + } + else + { + error_at(definition_location, + "type '%s' already declared in this scope", + definition->identifier().c_str()); + } + } + tree generic_visitor::build_type(source::type_expression& type) { if (source::basic_type_expression *basic_type = type.is_basic()) @@ -306,6 +336,12 @@ namespace gcc { return elna_string_type_node; } + auto symbol = this->symbol_map.find(basic_type->base_name()); + + if (symbol != this->symbol_map.end()) + { + return TREE_TYPE(symbol->second); + } } else if (source::array_type_expression *array_type = type.is_array()) { @@ -371,39 +407,47 @@ namespace gcc this->current_expression = symbol->second; } + void generic_visitor::visit(source::array_access_expression *expression) + { + expression->base().accept(this); + tree designator = this->current_expression; + + expression->index().accept(this); + tree index = this->current_expression; + + tree element_type = TREE_TYPE(TREE_TYPE(designator)); + + this->current_expression = build4_loc(get_location(&expression->position()), + ARRAY_REF, element_type, designator, index, NULL_TREE, NULL_TREE); + } + void generic_visitor::visit(source::assign_statement *statement) { - auto lvalue = this->symbol_map.find(statement->lvalue()); + statement->lvalue().accept(this); + + auto lvalue = this->current_expression; auto statement_location = get_location(&statement->position()); - if (lvalue == this->symbol_map.end()) - { - error_at(statement_location, - "variable '%s' not declared in the current scope", - statement->lvalue().c_str()); - return; - } statement->rvalue().accept(this); - if (TREE_CODE(lvalue->second) == CONST_DECL) + if (TREE_CODE(lvalue) == CONST_DECL) { error_at(statement_location, "cannot modify constant '%s'", - statement->lvalue().c_str()); + statement->lvalue().is_variable()->name().c_str()); this->current_expression = error_mark_node; return; } - if (TREE_TYPE(this->current_expression) != TREE_TYPE(lvalue->second)) + if (TREE_TYPE(this->current_expression) != TREE_TYPE(lvalue)) { error_at(statement_location, - "cannot assign value of type %s to variable '%s' of type %s", + "cannot assign value of type %s to variable of type %s", print_type(TREE_TYPE(this->current_expression)), - statement->lvalue().c_str(), - print_type(TREE_TYPE(lvalue->second))); + print_type(TREE_TYPE(lvalue))); this->current_expression = error_mark_node; return; } auto assignment = build2_loc(statement_location, MODIFY_EXPR, - void_type_node, lvalue->second, this->current_expression); + void_type_node, lvalue, this->current_expression); append_to_statement_list(assignment, &this->current_statements); this->current_expression = NULL_TREE; diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index ccdabe9..9b0be60 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -23,6 +23,12 @@ namespace gcc && TYPE_MAIN_VARIANT(TREE_TYPE(type)) == char_type_node; } + bool is_array_type(tree type) + { + gcc_assert(TYPE_P(type)); + return TREE_CODE(type) == ARRAY_TYPE; + } + tree tree_chain_base::head() { return first; diff --git a/gcc/elna1.cc b/gcc/elna1.cc index fdadfcf..4d36b6f 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -197,7 +197,7 @@ static tree elna_langhook_builtin_function(tree decl) static bool elna_langhook_global_bindings_p(void) { - gcc_unreachable(); + return false; } static tree elna_langhook_pushdecl(tree decl ATTRIBUTE_UNUSED) diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 2b29efa..83e6aa3 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -40,8 +40,10 @@ namespace gcc void visit(source::string_literal *string) override; void visit(source::binary_expression *expression) override; void visit(source::constant_definition *definition) override; + void visit(source::type_definition *definition) override; void visit(source::declaration *declaration) override; void visit(source::variable_expression *expression) override; + void visit(source::array_access_expression *expression) override; void visit(source::assign_statement *statement) override; void visit(source::if_statement *statement) override; void visit(source::while_statement *statement) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index bc39de6..031e786 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -23,6 +23,7 @@ namespace gcc { void init_ttree(); bool is_string_type(tree type); + bool is_array_type(tree type); class tree_chain_base { diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index ba2aa2b..efd573b 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -37,6 +37,7 @@ namespace source class declaration; class constant_definition; class procedure_definition; + class type_definition; class call_statement; class compound_statement; class assign_statement; @@ -49,6 +50,7 @@ namespace source class basic_type_expression; class array_type_expression; class variable_expression; + class array_access_expression; template class number_literal; class char_literal; @@ -62,6 +64,7 @@ namespace source virtual void visit(declaration *) = 0; virtual void visit(constant_definition *) = 0; virtual void visit(procedure_definition *) = 0; + virtual void visit(type_definition *) = 0; virtual void visit(call_statement *) = 0; virtual void visit(compound_statement *) = 0; virtual void visit(assign_statement *) = 0; @@ -74,6 +77,7 @@ namespace source virtual void visit(basic_type_expression *) = 0; virtual void visit(array_type_expression *) = 0; virtual void visit(variable_expression *) = 0; + virtual void visit(array_access_expression *) = 0; virtual void visit(number_literal *) = 0; virtual void visit(number_literal *) = 0; virtual void visit(number_literal *) = 0; @@ -89,6 +93,7 @@ namespace source virtual void visit(declaration *) override; virtual void visit(constant_definition *definition) override; virtual void visit(procedure_definition *definition) override; + virtual void visit(type_definition *definition) override; virtual void visit(call_statement *statement) override; virtual void visit(compound_statement *statement) override; virtual void visit(assign_statement *statement) override; @@ -99,8 +104,9 @@ namespace source virtual void visit(binary_expression *expression) override; virtual void visit(unary_expression *expression) override; virtual void visit(basic_type_expression *) override; - virtual void visit(array_type_expression *) override; + virtual void visit(array_type_expression *expression) override; virtual void visit(variable_expression *) override; + virtual void visit(array_access_expression *expression) override; virtual void visit(number_literal *) override; virtual void visit(number_literal *) override; virtual void visit(number_literal *) override; @@ -358,6 +364,20 @@ namespace source virtual ~procedure_definition() override; }; + class type_definition : public definition + { + type_expression *m_body; + + public: + type_definition(const struct position position, const std::string& identifier, + type_expression *expression); + virtual void accept(parser_visitor *visitor) override; + + type_expression& body(); + + virtual ~type_definition() override; + }; + /** * Call statement. */ @@ -393,9 +413,49 @@ namespace source virtual ~compound_statement() override; }; + class designator_expression : public expression + { + public: + virtual variable_expression *is_variable(); + virtual array_access_expression *is_array_access(); + + protected: + designator_expression(const struct position position); + }; + + class variable_expression : public designator_expression + { + std::string m_name; + + public: + variable_expression(const struct position position, const std::string& name); + virtual void accept(parser_visitor *visitor) override; + + const std::string& name() const; + + variable_expression *is_variable() override; + }; + + class array_access_expression : public designator_expression + { + designator_expression *m_base; + expression *m_index; + + public: + array_access_expression(const struct position position, designator_expression *base, expression *index); + virtual void accept(parser_visitor *visitor) override; + + designator_expression& base(); + expression& index(); + + array_access_expression *is_array_access() override; + + ~array_access_expression() override; + }; + class assign_statement : public statement { - std::string m_lvalue; + designator_expression *m_lvalue; expression *m_rvalue; public: @@ -404,11 +464,11 @@ namespace source * \param lvalue Left-hand side. * \param rvalue Assigned expression. */ - assign_statement(const struct position position, const std::string& lvalue, + assign_statement(const struct position position, designator_expression *lvalue, expression *rvalue); virtual void accept(parser_visitor *visitor) override; - std::string& lvalue(); + designator_expression& lvalue(); expression& rvalue(); virtual ~assign_statement() override; @@ -537,17 +597,6 @@ namespace source const std::string& string() const; }; - class variable_expression : public expression - { - std::string m_name; - - public: - variable_expression(const struct position position, const std::string& name); - virtual void accept(parser_visitor *visitor) override; - - const std::string& name() const; - }; - class binary_expression : public expression { expression *m_lhs; diff --git a/include/elna/source/result.h b/include/elna/source/result.h index f30938d..77eafe4 100644 --- a/include/elna/source/result.h +++ b/include/elna/source/result.h @@ -69,36 +69,5 @@ namespace source std::string what() const override; }; - - struct type_mismatch final : public error - { - /** - * Kind of the operation on the type. - */ - enum class operation - { - dereference, - argument, - arithmetic, - comparison, - condition, - assignment - }; - - /** - * \param name Given type. - * \param kind Kind of the operation on the type. - * \param path Source file name. - * \param position Operation position. - */ - type_mismatch(std::shared_ptr got, operation kind, const char *path, - const struct position position); - - std::string what() const override; - - private: - std::shared_ptr got; - operation kind; - }; } } diff --git a/source/ast.cc b/source/ast.cc index 2b5b86d..32cec0b 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -25,6 +25,11 @@ namespace source definition->body().accept(this); } + void empty_visitor::visit(type_definition *definition) + { + definition->body().accept(this); + } + void empty_visitor::visit(call_statement *statement) { for (auto& argument : statement->arguments()) @@ -91,14 +96,21 @@ namespace source { } - void empty_visitor::visit(array_type_expression *) + void empty_visitor::visit(array_type_expression *expression) { + expression->base().accept(this); } void empty_visitor::visit(variable_expression *) { } + void empty_visitor::visit(array_access_expression *expression) + { + expression->base().accept(this); + expression->index().accept(this); + } + void empty_visitor::visit(number_literal *) { } @@ -332,6 +344,27 @@ namespace source } } + type_definition::type_definition(const struct position position, const std::string& identifier, + type_expression *body) + : definition(position, identifier), m_body(body) + { + } + + void type_definition::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + type_expression& type_definition::body() + { + return *m_body; + } + + type_definition::~type_definition() + { + delete m_body; + } + block::block(const struct position position, std::vector&& definitions, std::vector&& declarations, statement *body) @@ -415,8 +448,13 @@ namespace source return m_string; } + designator_expression::designator_expression(const struct position position) + : expression(position) + { + } + variable_expression::variable_expression(const struct position position, const std::string& name) - : expression(position), m_name(name) + : designator_expression(position), m_name(name) { } @@ -430,6 +468,42 @@ namespace source return m_name; } + variable_expression *variable_expression::is_variable() + { + return this; + } + + array_access_expression::array_access_expression(const struct position position, + designator_expression *base, expression *index) + : designator_expression(position), m_base(base), m_index(index) + { + } + + void array_access_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + expression& array_access_expression::index() + { + return *m_index; + } + + designator_expression& array_access_expression::base() + { + return *m_base; + } + + array_access_expression *array_access_expression::is_array_access() + { + return this; + } + + array_access_expression::~array_access_expression() + { + delete m_base; + } + binary_expression::binary_expression(const struct position position, expression *lhs, expression *rhs, const unsigned char operation) : expression(position), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) @@ -590,15 +664,25 @@ namespace source visitor->visit(this); } - assign_statement::assign_statement(const struct position position, const std::string& lvalue, + assign_statement::assign_statement(const struct position position, designator_expression *lvalue, expression *rvalue) : statement(position), m_lvalue(lvalue), m_rvalue(rvalue) { } - std::string& assign_statement::lvalue() + variable_expression *designator_expression::is_variable() { - return m_lvalue; + return nullptr; + } + + array_access_expression *designator_expression::is_array_access() + { + return nullptr; + } + + designator_expression& assign_statement::lvalue() + { + return *m_lvalue; } expression& assign_statement::rvalue() diff --git a/source/lexer.ll b/source/lexer.ll index 16d40d2..de17ce0 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -67,6 +67,10 @@ array { of { return yy::parser::make_OF(this->location); } +type { + return yy::parser::make_TYPE(this->location); + } + true { return yy::parser::make_BOOLEAN(true, this->location); } diff --git a/source/parser.yy b/source/parser.yy index 9b5abfc..b7c11bb 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -63,7 +63,7 @@ %token STRING "string" %token BOOLEAN %token IF WHILE DO -%token CONST VAR PROCEDURE ARRAY OF +%token CONST VAR PROCEDURE ARRAY OF TYPE %token BEGIN_BLOCK END_BLOCK %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS @@ -87,6 +87,7 @@ %type expression pointer summand factor address comparand; %type > expressions actual_parameter_list; %type variable_expression; +%type designator_expression; %type compound_statement; %type assign_statement; %type call_statement; @@ -95,26 +96,31 @@ %type statement; %type > statements optional_statements; %type procedure_definition; -%type > procedure_definitions - procedure_definition_part; +%type > procedure_definitions procedure_definition_part; +%type type_definition; +%type > type_definitions type_definition_part; %type block; %% -program: constant_definition_part procedure_definition_part variable_declaration_part statement DOT +program: + type_definition_part constant_definition_part procedure_definition_part variable_declaration_part statement DOT { - std::vector definitions($1.size() + $2.size()); + std::vector definitions($1.size() + $2.size() + $3.size()); std::vector::iterator definition = definitions.begin(); - for (auto& constant : $1) + for (auto& type : $1) + { + *definition++ = type; + } + for (auto& constant : $2) { *definition++ = constant; } - for (auto& procedure : $2) + for (auto& procedure : $3) { *definition++ = procedure; } driver.tree = std::make_unique(elna::source::position{}, - std::move(definitions), std::move($3), - std::move($4)); + std::move(definitions), std::move($4), std::move($5)); } block: constant_definition_part variable_declaration_part statement { @@ -170,7 +176,7 @@ compound_statement: BEGIN_BLOCK optional_statements END_BLOCK $$ = new elna::source::compound_statement(elna::source::make_position(@1)); std::swap($$->statements(), $2); } -assign_statement: IDENTIFIER ASSIGNMENT expression +assign_statement: designator_expression ASSIGNMENT expression { $$ = new elna::source::assign_statement(elna::source::make_position(@1), $1, $3); } @@ -201,7 +207,7 @@ pointer: | boolean_literal { $$ = $1; } | character_literal { $$ = $1; } | string_literal { $$ = $1; } - | variable_expression { $$ = $1; } + | designator_expression { $$ = $1; } | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); } summand: factor { $$ = std::move($1); } @@ -280,8 +286,14 @@ expressions: $$.emplace($$.cbegin(), $1); } | expression { $$.emplace_back(std::move($1)); } -variable_expression: IDENTIFIER - { $$ = new elna::source::variable_expression(elna::source::make_position(@1), $1); } +variable_expression: + IDENTIFIER { $$ = new elna::source::variable_expression(elna::source::make_position(@1), $1); } +designator_expression: + variable_expression LEFT_SQUARE expression RIGHT_SQUARE + { + $$ = new elna::source::array_access_expression(elna::source::make_position(@1), $1, $3); + } + | variable_expression { $$ = $1; } statement: compound_statement { $$ = $1; } | assign_statement { $$ = $1; } @@ -324,9 +336,8 @@ variable_declaration_part: | VAR variable_declarations SEMICOLON { std::swap($$, $2); } constant_definition: IDENTIFIER EQUALS integer_literal { - $$ = new elna::source::constant_definition(elna::source::make_position(@1), - $1, $3); - }; + $$ = new elna::source::constant_definition(elna::source::make_position(@1), $1, $3); + } constant_definitions: constant_definition COMMA constant_definitions { @@ -336,7 +347,21 @@ constant_definitions: | constant_definition { $$.emplace_back(std::move($1)); } constant_definition_part: /* no constant definitions */ {} - | CONST constant_definitions SEMICOLON { std::swap($$, $2); }; + | CONST constant_definitions SEMICOLON { std::swap($$, $2); } +type_definition: IDENTIFIER EQUALS type_expression + { + $$ = new elna::source::type_definition(elna::source::make_position(@1), $1, $3); + } +type_definitions: + type_definition COMMA type_definitions + { + std::swap($$, $3); + $$.emplace($$.cbegin(), std::move($1)); + } + | type_definition { $$.emplace_back(std::move($1)); } +type_definition_part: + /* no type definitions */ {} + | TYPE type_definitions SEMICOLON { std::swap($$, $2); } formal_parameter_list: LEFT_PAREN RIGHT_PAREN {} | LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); } diff --git a/source/result.cc b/source/result.cc index 8bd5947..a7b493d 100644 --- a/source/result.cc +++ b/source/result.cc @@ -24,7 +24,7 @@ namespace source name_collision::name_collision(const std::string& name, const char *path, const struct position current, const struct position previous) - : error(path, current), name(name), previous(previous) + : error(path, current), previous(previous), name(name) { } @@ -32,16 +32,5 @@ namespace source { return "Name '" + name + "' was already defined"; } - - type_mismatch::type_mismatch(std::shared_ptr got, operation kind, - const char *path, const struct position position) - : error(path, position), kind(kind), got(got) - { - } - - std::string type_mismatch::what() const - { - return "Type cannot be used here."; - } } } diff --git a/source/types.cc b/source/types.cc index 356dc54..993a38c 100644 --- a/source/types.cc +++ b/source/types.cc @@ -48,7 +48,7 @@ namespace source } procedure_type::procedure_type(std::vector> arguments, const std::size_t byte_size) - : arguments(std::move(arguments)), type(byte_size) + :type(byte_size), arguments(std::move(arguments)) { }