diff --git a/README.md b/README.md index e0f9b5d..6903e26 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ program = [ "type" type_definitions ";" ] [ variable_part ] compound_statement "."; -procedure_definition = "proc" ident formal_parameter_list ";" block ";"; +procedure_definition = "proc" ident formal_parameter_list ";" ( block | "extern" ) ";"; block = [ constant_part ] [ variable_part ] diff --git a/example.elna b/example.elna index c2b216c..d56148f 100644 --- a/example.elna +++ b/example.elna @@ -119,6 +119,8 @@ begin writei(x) end; +proc exit(code: Int); extern; + begin test_primitive(); test_string(); @@ -129,5 +131,7 @@ begin test_if(); test_not(); test_param(8, 7); - test_const_char() + test_const_char(); + + exit(0) end. diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 988c82f..6e6bfe8 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -132,12 +132,14 @@ namespace gcc enter_scope(); - for (const auto& definition : program->value_definitions) + for (const auto definition : program->value_definitions) { definition->accept(this); } - program->body().accept(this); - + for (const auto body_statement : program->body) + { + body_statement->accept(this); + } append_to_statement_list(return_stmt, &this->current_statements); tree_symbol_mapping mapping = leave_scope(); @@ -155,53 +157,64 @@ namespace gcc void generic_visitor::visit(source::procedure_definition *definition) { - std::vector parameter_types(definition->parameters().size()); + std::vector parameter_types(definition->parameters.size()); - for (std::size_t i = 0; i < definition->parameters().size(); ++i) + for (std::size_t i = 0; i < definition->parameters.size(); ++i) { - parameter_types[i] = build_type(definition->parameters().at(i)->type()); + parameter_types[i] = build_type(definition->parameters.at(i)->type()); } tree declaration_type = build_function_type_array(void_type_node, - definition->parameters().size(), parameter_types.data()); + 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)); - tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, - NULL_TREE, TREE_TYPE(TREE_TYPE(this->main_fndecl))); - DECL_CONTEXT(resdecl) = this->main_fndecl; - DECL_RESULT(this->main_fndecl) = resdecl; - - enter_scope(); - - gcc::tree_chain argument_chain; - for (std::size_t i = 0; i < definition->parameters().size(); ++i) + if (definition->body() != nullptr) { - auto parameter = definition->parameters().at(i); + tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, + NULL_TREE, TREE_TYPE(TREE_TYPE(this->main_fndecl))); + DECL_CONTEXT(resdecl) = this->main_fndecl; + DECL_RESULT(this->main_fndecl) = resdecl; + + enter_scope(); + } + gcc::tree_chain argument_chain; + for (std::size_t i = 0; i < definition->parameters.size(); ++i) + { + auto parameter = definition->parameters.at(i); tree declaration_tree = build_decl(get_location(¶meter->position()), PARM_DECL, get_identifier(parameter->identifier().c_str()), parameter_types[i]); DECL_CONTEXT(declaration_tree) = this->main_fndecl; DECL_ARG_TYPE(declaration_tree) = parameter_types[i]; - this->symbol_map->enter(parameter->identifier(), source::make_info(declaration_tree)); + if (definition->body() != nullptr) + { + this->symbol_map->enter(parameter->identifier(), source::make_info(declaration_tree)); + } argument_chain.append(declaration_tree); } DECL_ARGUMENTS(this->main_fndecl) = argument_chain.head(); - definition->body().accept(this); - tree_symbol_mapping mapping = leave_scope(); + if (definition->body() != nullptr) + { + definition->body()->accept(this); + tree_symbol_mapping mapping = leave_scope(); - BLOCK_SUPERCONTEXT(mapping.block()) = this->main_fndecl; - DECL_INITIAL(this->main_fndecl) = mapping.block(); - DECL_SAVED_TREE(this->main_fndecl) = mapping.bind_expression(); + BLOCK_SUPERCONTEXT(mapping.block()) = this->main_fndecl; + DECL_INITIAL(this->main_fndecl) = mapping.block(); + DECL_SAVED_TREE(this->main_fndecl) = mapping.bind_expression(); - DECL_EXTERNAL(this->main_fndecl) = 0; - DECL_PRESERVE_P(this->main_fndecl) = 1; + DECL_EXTERNAL(this->main_fndecl) = 0; + DECL_PRESERVE_P(this->main_fndecl) = 1; - gimplify_function_tree(this->main_fndecl); + gimplify_function_tree(this->main_fndecl); - cgraph_node::finalize_function(this->main_fndecl, true); + cgraph_node::finalize_function(this->main_fndecl, true); + } + else + { + DECL_EXTERNAL(this->main_fndecl) = 1; + } } void generic_visitor::enter_scope() diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index 99ad8cc..dd99e53 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -386,21 +386,21 @@ namespace source */ class procedure_definition : public definition { - block *m_body; - std::vector m_parameters; + block *m_body{ nullptr }; public: + std::vector parameters; + /** * \param position Source code position. * \param identifier Procedure name. * \param body Procedure body. */ procedure_definition(const struct position position, const std::string& identifier, - block *body); + block *body = nullptr); virtual void accept(parser_visitor *visitor) override; - block& body(); - std::vector& parameters(); + block *body(); virtual ~procedure_definition() override; }; @@ -603,17 +603,14 @@ namespace source class block : public node { - statement *m_body; - public: std::vector value_definitions; + std::vector body; block(const struct position position, std::vector&& value_definitions, - statement *body); + std::vector&& body); virtual void accept(parser_visitor *visitor) override; - statement& body(); - virtual ~block() override; }; @@ -623,7 +620,7 @@ namespace source std::vector type_definitions; program(const struct position position, std::vector&& type_definitions, - std::vector&& value_definitions, statement *body); + std::vector&& value_definitions, std::vector&& body); virtual void accept(parser_visitor *visitor) override; virtual ~program() override; diff --git a/source/ast.cc b/source/ast.cc index 26d8480..fdbe984 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -18,11 +18,14 @@ namespace source void empty_visitor::visit(procedure_definition *definition) { - for (auto parameter : definition->parameters()) + for (auto parameter : definition->parameters) { parameter->accept(this); } - definition->body().accept(this); + if (definition->body() != nullptr) + { + definition->body()->accept(this); + } } void empty_visitor::visit(type_definition *definition) @@ -65,11 +68,14 @@ namespace source void empty_visitor::visit(block *block) { - for (const auto& definition : block->value_definitions) + for (const auto definition : block->value_definitions) { definition->accept(this); } - block->body().accept(this); + for (const auto body_statement : block->body) + { + body_statement->accept(this); + } } void empty_visitor::visit(program *program) @@ -407,20 +413,18 @@ namespace source visitor->visit(this); } - block& procedure_definition::body() + block *procedure_definition::body() { - return *m_body; - } - - std::vector& procedure_definition::parameters() - { - return m_parameters; + return m_body; } procedure_definition::~procedure_definition() { - delete m_body; - for (auto parameter : m_parameters) + if (m_body != nullptr) + { + delete m_body; + } + for (auto parameter : parameters) { delete parameter; } @@ -448,8 +452,8 @@ namespace source } block::block(const struct position position, std::vector&& value_definitions, - statement *body) - : node(position), m_body(std::move(body)), value_definitions(std::move(value_definitions)) + std::vector&& body) + : node(position), value_definitions(std::move(value_definitions)), body(std::move(body)) { } @@ -458,24 +462,22 @@ namespace source visitor->visit(this); } - statement& block::body() - { - return *m_body; - } - block::~block() { - for (auto definition : value_definitions) + for (auto definition : this->value_definitions) { delete definition; } - delete m_body; + for (auto body_statement : this->body) + { + delete body_statement; + } } program::program(const struct position position, std::vector&& type_definitions, - std::vector&& value_definitions, statement *body) - : block(position, std::move(value_definitions), body), + std::vector&& value_definitions, std::vector&& body) + : block(position, std::move(value_definitions), std::move(body)), type_definitions(std::move(type_definitions)) { } diff --git a/source/lexer.ll b/source/lexer.ll index c429c12..6f5c397 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -55,6 +55,9 @@ begin { end { return yy::parser::make_END_BLOCK(this->location); } +extern { + return yy::parser::make_EXTERN(this->location); + } const { return yy::parser::make_CONST(this->location); } diff --git a/source/parser.yy b/source/parser.yy index 65db0aa..57aaf5a 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -64,7 +64,7 @@ %token BOOLEAN %token IF WHILE DO %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD -%token BEGIN_BLOCK END_BLOCK +%token BEGIN_BLOCK END_BLOCK EXTERN %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA %token AND OR NOT %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS @@ -100,7 +100,7 @@ %type >> field_list; %% program: - type_part constant_part procedure_part variable_part compound_statement DOT + type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT { std::vector definitions($1.size() + $3.size()); std::vector::iterator definition = definitions.begin(); @@ -124,11 +124,11 @@ program: *value_definition++ = variable; } auto tree = new elna::source::program(elna::source::position{}, - std::move(definitions), std::move(value_definitions), std::move($5)); + std::move(definitions), std::move(value_definitions), std::move($6)); driver.tree.reset(tree); } -block: constant_part variable_part statement +block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK { std::vector definitions($1.size() + $2.size()); std::vector::iterator definition = definitions.begin(); @@ -142,15 +142,21 @@ block: constant_part variable_part statement *definition++ = variable; } $$ = new elna::source::block(elna::source::position{}, - std::move(definitions), std::move($3)); - }; + std::move(definitions), std::move($4)); + } 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); - }; + std::swap($$->parameters, $3); + } + | PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON + { + $$ = new elna::source::procedure_definition(elna::source::position{}, + std::move($2)); + std::swap($$->parameters, $3); + } procedure_definitions: procedure_definition procedure_definitions {