diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index ec1b8b5..fda487f 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -40,10 +40,18 @@ namespace gcc { return "pointer"; } - else if (is_array_type(type)) + else if (TREE_CODE(type) == ARRAY_TYPE) { return "array"; } + else if (TREE_CODE(type) == RECORD_TYPE) + { + return "record"; + } + else if (TREE_CODE(type) == UNION_TYPE) + { + return "union"; + } else { return "<>"; diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index b8a2cb2..1f0c3d7 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -20,7 +20,7 @@ namespace gcc this->symbol_map = symbol_table; } - void generic_visitor::visit(source::call_statement *statement) + void generic_visitor::visit(source::call_expression *statement) { auto symbol = this->symbol_map->lookup(statement->name()); @@ -87,7 +87,8 @@ namespace gcc } else if (symbol) { - tree fndecl_type = build_function_type(void_type_node, TYPE_ARG_TYPES(symbol->payload)); + tree return_type = TREE_TYPE(TREE_TYPE(symbol->payload)); + tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(symbol->payload)); tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol->payload); std::vector arguments(statement->arguments().size()); @@ -97,10 +98,17 @@ namespace gcc arguments[i] = this->current_expression; } tree stmt = build_call_array_loc(get_location(&statement->position()), - void_type_node, printf_fn, arguments.size(), arguments.data()); + return_type, printf_fn, arguments.size(), arguments.data()); - append_to_statement_list(stmt, &this->current_statements); - this->current_expression = NULL_TREE; + if (return_type == void_type_node) + { + append_to_statement_list(stmt, &this->current_statements); + this->current_expression = NULL_TREE; + } + else + { + this->current_expression = stmt; + } } else { @@ -126,9 +134,6 @@ namespace gcc tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); DECL_CONTEXT(resdecl) = this->main_fndecl; DECL_RESULT(this->main_fndecl) = resdecl; - tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(main_fndecl), - build_int_cst_type(integer_type_node, 0)); - tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); enter_scope(); @@ -140,6 +145,9 @@ namespace gcc { body_statement->accept(this); } + tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(main_fndecl), + build_int_cst_type(integer_type_node, 0)); + tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); append_to_statement_list(return_stmt, &this->current_statements); tree_symbol_mapping mapping = leave_scope(); @@ -163,15 +171,17 @@ namespace gcc { parameter_types[i] = build_type(definition->parameters.at(i)->type()); } - tree declaration_type = build_function_type_array(void_type_node, + tree return_type = definition->return_type() == nullptr + ? void_type_node + : build_type(*definition->return_type()); + tree declaration_type = build_function_type_array(return_type, definition->parameters.size(), parameter_types.data()); this->main_fndecl = build_fn_decl(definition->identifier().c_str(), declaration_type); this->symbol_map->enter(definition->identifier(), source::make_info(this->main_fndecl)); if (definition->body() != nullptr) { - tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, - NULL_TREE, TREE_TYPE(TREE_TYPE(this->main_fndecl))); + tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, return_type); DECL_CONTEXT(resdecl) = this->main_fndecl; DECL_RESULT(this->main_fndecl) = resdecl; @@ -454,7 +464,7 @@ namespace gcc 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->enter(definition->identifier(), source::make_info(definition_tree)); + auto result = this->symbol_map->enter(definition->identifier(), source::make_info(tree_type)); if (result) { @@ -477,31 +487,11 @@ namespace gcc { if (source::basic_type_expression *basic_type = type.is_basic()) { - if (basic_type->base_name() == "Int") - { - return integer_type_node; - } - else if (basic_type->base_name() == "Bool") - { - return boolean_type_node; - } - else if (basic_type->base_name() == "Float") - { - return double_type_node; - } - else if (basic_type->base_name() == "Char") - { - return elna_char_type_node; - } - else if (basic_type->base_name() == "String") - { - return elna_string_type_node; - } auto symbol = this->symbol_map->lookup(basic_type->base_name()); - if (symbol) + if (symbol && TYPE_P(symbol->payload)) { - return TREE_TYPE(symbol->payload); + return symbol->payload; } error_at(get_location(&basic_type->position()), "type '%s' not declared", basic_type->base_name().c_str()); @@ -844,5 +834,26 @@ namespace gcc this->current_expression = NULL_TREE; } + + void generic_visitor::visit(source::expression_statement *statement) + { + statement->body().accept(this); + } + + void generic_visitor::visit(source::return_statement *statement) + { + source::expression *return_expression = statement->return_expression(); + + if (return_expression == nullptr) + { + return; + } + return_expression->accept(this); + + tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(main_fndecl), + this->current_expression); + tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); + append_to_statement_list(return_stmt, &this->current_statements); + } } } diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 6cac5ee..a4c3156 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -28,12 +28,6 @@ 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; @@ -76,7 +70,16 @@ namespace gcc std::shared_ptr> builtin_symbol_table() { - return std::make_shared>(); + std::shared_ptr> initial_table = + std::make_shared>(); + + initial_table->enter("Int", source::make_info(integer_type_node)); + initial_table->enter("Bool", source::make_info(boolean_type_node)); + initial_table->enter("Float", source::make_info(double_type_node)); + initial_table->enter("Char", source::make_info(elna_char_type_node)); + initial_table->enter("String", source::make_info(elna_string_type_node)); + + return initial_table; } } } diff --git a/gcc/elna1.cc b/gcc/elna1.cc index 4d36b6f..51d76e7 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -100,7 +100,7 @@ static void elna_parse_file(const char *filename) } else { - elna::gcc::generic_visitor generic_visitor; + elna::gcc::generic_visitor generic_visitor{ elna::gcc::builtin_symbol_table() }; generic_visitor.visit(driver.tree.get()); } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 905d376..ea280dd 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -39,7 +39,7 @@ namespace gcc void visit(source::program *program) override; void visit(source::procedure_definition *definition) override; - void visit(source::call_statement *statement) override; + void visit(source::call_expression *statement) override; void visit(source::number_literal *literal) override; void visit(source::number_literal *literal) override; void visit(source::number_literal *boolean) override; @@ -57,6 +57,8 @@ namespace gcc void visit(source::assign_statement *statement) override; void visit(source::if_statement *statement) override; void visit(source::while_statement *statement) override; + void visit(source::expression_statement *statement) override; + void visit(source::return_statement *statement) override; }; } } diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 64f5e31..59d9c88 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -6,6 +6,8 @@ #include "tree.h" #include "tree.h" +#include "elna/source/symbol.h" + enum elna_tree_index { ELNA_TI_CHAR_TYPE, @@ -25,7 +27,6 @@ namespace gcc void init_ttree(); bool is_pointer_type(tree type); bool is_string_type(tree type); - bool is_array_type(tree type); class tree_chain_base { @@ -58,6 +59,6 @@ namespace gcc tree block(); }; - std::shared_ptr> builtin_symbol_table(); + std::shared_ptr> builtin_symbol_table(); } } diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index d363aa9..3c2c62a 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -39,11 +39,13 @@ namespace source class constant_definition; class procedure_definition; class type_definition; - class call_statement; + class call_expression; class compound_statement; class assign_statement; class if_statement; class while_statement; + class return_statement; + class expression_statement; class block; class program; class binary_expression; @@ -71,11 +73,13 @@ namespace source 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(call_expression *) = 0; + virtual void visit(expression_statement *) = 0; virtual void visit(compound_statement *) = 0; virtual void visit(assign_statement *) = 0; virtual void visit(if_statement *) = 0; virtual void visit(while_statement *) = 0; + virtual void visit(return_statement *) = 0; virtual void visit(block *) = 0; virtual void visit(program *) = 0; virtual void visit(binary_expression *) = 0; @@ -105,11 +109,13 @@ namespace source 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(call_expression *statement) override; + virtual void visit(expression_statement *statement) override; virtual void visit(compound_statement *statement) override; virtual void visit(assign_statement *statement) override; virtual void visit(if_statement *) override; virtual void visit(while_statement *) override; + virtual void visit(return_statement *) override; virtual void visit(block *block) override; virtual void visit(program *program) override; virtual void visit(binary_expression *expression) override; @@ -403,6 +409,7 @@ namespace source */ class procedure_definition : public definition { + type_expression *m_return_type{ nullptr }; block *m_body{ nullptr }; public: @@ -411,12 +418,16 @@ namespace source /** * \param position Source code position. * \param identifier Procedure name. + * \param parameters Procedure formal parameters. + * \param return_type Return type if any. * \param body Procedure body. */ procedure_definition(const struct position position, const std::string& identifier, - block *body = nullptr); + std::vector&& parameters, + type_expression *return_type = nullptr, block *body = nullptr); virtual void accept(parser_visitor *visitor) override; + type_expression *return_type(); block *body(); virtual ~procedure_definition() override; @@ -439,7 +450,7 @@ namespace source /** * Call statement. */ - class call_statement : public statement + class call_expression : public expression { std::string m_name; std::vector m_arguments; @@ -449,16 +460,29 @@ namespace source * \param position Source code position. * \param name Callable's name. */ - call_statement(const struct position position, const std::string& name); + call_expression(const struct position position, const std::string& name); virtual void accept(parser_visitor *visitor) override; std::string& name(); std::vector& arguments(); - virtual ~call_statement() override; + virtual ~call_expression() override; }; - class compound_statement : public statement + class expression_statement : public statement + { + expression *m_body; + + public: + expression_statement(const struct position position, expression *body); + virtual void accept(parser_visitor *visitor) override; + + expression& body(); + + virtual ~expression_statement() override; + }; + + class compound_statement : public node { public: std::vector statements; @@ -469,6 +493,19 @@ namespace source virtual ~compound_statement() override; }; + class return_statement : public statement + { + expression *m_return_expression{ nullptr }; + + public: + return_statement(const struct position position, expression *return_expression); + virtual void accept(parser_visitor *visitor) override; + + expression *return_expression(); + + virtual ~return_statement() override; + }; + class designator_expression : public expression { public: diff --git a/source/ast.cc b/source/ast.cc index 07d6837..820c553 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -33,7 +33,7 @@ namespace source definition->body().accept(this); } - void empty_visitor::visit(call_statement *statement) + void empty_visitor::visit(call_expression *statement) { for (auto& argument : statement->arguments()) { @@ -41,6 +41,11 @@ namespace source } } + void empty_visitor::visit(expression_statement *statement) + { + statement->body().accept(this); + } + void empty_visitor::visit(compound_statement *statement) { for (const auto nested_statement : statement->statements) @@ -66,6 +71,16 @@ namespace source statement->body().accept(this); } + void empty_visitor::visit(return_statement *statement) + { + expression *return_expression = statement->return_expression(); + + if (return_expression != nullptr) + { + return_expression->accept(this); + } + } + void empty_visitor::visit(block *block) { for (const auto definition : block->value_definitions) @@ -433,8 +448,8 @@ namespace source } procedure_definition::procedure_definition(const struct position position, const std::string& identifier, - block *body) - : definition(position, identifier), m_body(body) + std::vector&& parameters, type_expression *return_type, block *body) + : definition(position, identifier), m_return_type(return_type), m_body(body), parameters(std::move(parameters)) { } @@ -448,6 +463,11 @@ namespace source return m_body; } + type_expression *procedure_definition::return_type() + { + return m_return_type; + } + procedure_definition::~procedure_definition() { if (m_body != nullptr) @@ -768,27 +788,27 @@ namespace source delete m_operand; } - call_statement::call_statement(const struct position position, const std::string& name) - : statement(position), m_name(name) + call_expression::call_expression(const struct position position, const std::string& name) + : expression(position), m_name(name) { } - void call_statement::accept(parser_visitor *visitor) + void call_expression::accept(parser_visitor *visitor) { visitor->visit(this); } - std::string& call_statement::name() + std::string& call_expression::name() { return m_name; } - std::vector& call_statement::arguments() + std::vector& call_expression::arguments() { return m_arguments; } - call_statement::~call_statement() + call_expression::~call_expression() { for (auto argument : m_arguments) { @@ -796,8 +816,28 @@ namespace source } } + expression_statement::expression_statement(const struct position position, expression *body) + : statement(position), m_body(body) + { + } + + void expression_statement::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + expression& expression_statement::body() + { + return *m_body; + } + + expression_statement::~expression_statement() + { + delete m_body; + } + compound_statement::compound_statement(const struct position position, std::vector&& statements) - : statement(position), statements(std::move(statements)) + : node(position), statements(std::move(statements)) { } @@ -814,6 +854,29 @@ namespace source } } + return_statement::return_statement(const struct position position, expression *return_expression) + : statement(position), m_return_expression(return_expression) + { + } + + void return_statement::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + expression *return_statement::return_expression() + { + return m_return_expression; + } + + return_statement::~return_statement() + { + if (m_return_expression != nullptr) + { + delete m_return_expression; + } + } + void assign_statement::accept(parser_visitor *visitor) { visitor->visit(this); diff --git a/source/lexer.ll b/source/lexer.ll index 75c1925..9bbe55d 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -100,6 +100,9 @@ or { not { return yy::parser::make_NOT(this->location); } +return { + return yy::parser::make_RETURN(this->location); + } [A-Za-z_][A-Za-z0-9_]* { return yy::parser::make_IDENTIFIER(yytext, this->location); } diff --git a/source/parser.yy b/source/parser.yy index 06582bc..af6b388 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -62,7 +62,7 @@ %token CHARACTER "character" %token STRING "string" %token BOOLEAN -%token IF WHILE DO THEN ELSE +%token IF WHILE DO THEN ELSE RETURN %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 @@ -82,9 +82,10 @@ %type > expressions actual_parameter_list; %type designator_expression; %type assign_statement; -%type call_statement; +%type call_expression; %type while_statement; %type if_statement; +%type return_statement; %type statement; %type > statements optional_statements; %type procedure_definition; @@ -144,14 +145,22 @@ procedure_definition: PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON { $$ = new elna::source::procedure_definition(elna::source::position{}, - std::move($2), $5); - std::swap($$->parameters, $3); + $2, std::move($3), nullptr, $5); } | PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON { $$ = new elna::source::procedure_definition(elna::source::position{}, - std::move($2)); - std::swap($$->parameters, $3); + $2, std::move($3), nullptr, nullptr); + } + | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON + { + $$ = new elna::source::procedure_definition(elna::source::position{}, + $2, std::move($3), $5, $7); + } + | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON + { + $$ = new elna::source::procedure_definition(elna::source::position{}, + $2, std::move($3), $5, nullptr); } procedure_definitions: procedure_definition procedure_definitions @@ -167,9 +176,9 @@ assign_statement: designator_expression ASSIGNMENT expression { $$ = new elna::source::assign_statement(elna::source::make_position(@1), $1, $3); } -call_statement: IDENTIFIER actual_parameter_list +call_expression: IDENTIFIER actual_parameter_list { - $$ = new elna::source::call_statement(elna::source::make_position(@1), $1); + $$ = new elna::source::call_expression(elna::source::make_position(@1), $1); std::swap($$->arguments(), $2); } while_statement: WHILE expression DO optional_statements END_BLOCK @@ -189,6 +198,11 @@ if_statement: 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); } +return_statement: + RETURN expression + { + $$ = new elna::source::return_statement(elna::source::make_position(@1), $2); + } literal: INTEGER { @@ -282,6 +296,7 @@ expression: $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'o'); } | logical_operand { $$ = $1; } + | call_expression { $$ = $1; } expressions: expression COMMA expressions { @@ -308,9 +323,10 @@ designator_expression: } statement: assign_statement { $$ = $1; } - | call_statement { $$ = $1; } | while_statement { $$ = $1; } | if_statement { $$ = $1; } + | return_statement { $$ = $1; } + | expression { $$ = new elna::source::expression_statement(elna::source::make_position(@1), $1); } statements: statement SEMICOLON statements {