From b6b68b25043fc4008af6c7bfb4573593a858a9de Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 3 Jul 2026 11:09:44 +0200 Subject: Rename frontend to boot(strap) --- boot/ast.cc | 1192 ++++++++++++++++++++++++++++++++++++ boot/dependency.cc | 102 +++ boot/driver.cc | 118 ++++ boot/lexer.ll | 314 ++++++++++ boot/parser.yy | 595 ++++++++++++++++++ boot/result.cc | 67 ++ boot/semantic.cc | 682 +++++++++++++++++++++ boot/symbol.cc | 427 +++++++++++++ frontend/ast.cc | 1192 ------------------------------------ frontend/dependency.cc | 102 --- frontend/driver.cc | 118 ---- frontend/lexer.ll | 314 ---------- frontend/parser.yy | 595 ------------------ frontend/result.cc | 67 -- frontend/semantic.cc | 682 --------------------- frontend/symbol.cc | 427 ------------- gcc/Make-lang.in | 6 +- gcc/elna-builtins.cc | 54 +- gcc/elna-diagnostic.cc | 6 +- gcc/elna-generic.cc | 170 ++--- gcc/elna-tree.cc | 10 +- gcc/elna1.cc | 16 +- include/elna/boot/ast.h | 800 ++++++++++++++++++++++++ include/elna/boot/dependency.h | 55 ++ include/elna/boot/driver.h | 51 ++ include/elna/boot/result.h | 124 ++++ include/elna/boot/semantic.h | 192 ++++++ include/elna/boot/symbol.h | 457 ++++++++++++++ include/elna/frontend/ast.h | 800 ------------------------ include/elna/frontend/dependency.h | 55 -- include/elna/frontend/driver.h | 51 -- include/elna/frontend/result.h | 124 ---- include/elna/frontend/semantic.h | 192 ------ include/elna/frontend/symbol.h | 457 -------------- include/elna/gcc/elna-builtins.h | 10 +- include/elna/gcc/elna-diagnostic.h | 6 +- include/elna/gcc/elna-generic.h | 92 +-- include/elna/gcc/elna-tree.h | 12 +- 38 files changed, 5367 insertions(+), 5367 deletions(-) create mode 100644 boot/ast.cc create mode 100644 boot/dependency.cc create mode 100644 boot/driver.cc create mode 100644 boot/lexer.ll create mode 100644 boot/parser.yy create mode 100644 boot/result.cc create mode 100644 boot/semantic.cc create mode 100644 boot/symbol.cc delete mode 100644 frontend/ast.cc delete mode 100644 frontend/dependency.cc delete mode 100644 frontend/driver.cc delete mode 100644 frontend/lexer.ll delete mode 100644 frontend/parser.yy delete mode 100644 frontend/result.cc delete mode 100644 frontend/semantic.cc delete mode 100644 frontend/symbol.cc create mode 100644 include/elna/boot/ast.h create mode 100644 include/elna/boot/dependency.h create mode 100644 include/elna/boot/driver.h create mode 100644 include/elna/boot/result.h create mode 100644 include/elna/boot/semantic.h create mode 100644 include/elna/boot/symbol.h delete mode 100644 include/elna/frontend/ast.h delete mode 100644 include/elna/frontend/dependency.h delete mode 100644 include/elna/frontend/driver.h delete mode 100644 include/elna/frontend/result.h delete mode 100644 include/elna/frontend/semantic.h delete mode 100644 include/elna/frontend/symbol.h diff --git a/boot/ast.cc b/boot/ast.cc new file mode 100644 index 0000000..e4c46a4 --- /dev/null +++ b/boot/ast.cc @@ -0,0 +1,1192 @@ +/* Abstract syntax tree representation. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "elna/boot/ast.h" + +namespace elna::boot +{ + void empty_visitor::not_implemented() + { + __builtin_unreachable(); + } + + void empty_visitor::visit(type_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(array_type_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(pointer_type_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(program *) + { + not_implemented(); + } + + void empty_visitor::visit(type_declaration *) + { + not_implemented(); + } + + void empty_visitor::visit(record_type_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(union_type_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(procedure_type_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(enumeration_type_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(variable_declaration *) + { + not_implemented(); + } + + void empty_visitor::visit(constant_declaration *) + { + not_implemented(); + } + + void empty_visitor::visit(procedure_declaration *) + { + not_implemented(); + } + + void empty_visitor::visit(assign_statement *) + { + not_implemented(); + } + + void empty_visitor::visit(if_statement *) + { + not_implemented(); + } + + void empty_visitor::visit(import_declaration *) + { + not_implemented(); + } + + void empty_visitor::visit(while_statement *) + { + not_implemented(); + } + + void empty_visitor::visit(return_statement *) + { + not_implemented(); + } + + void empty_visitor::visit(defer_statement *) + { + not_implemented(); + } + + void empty_visitor::visit(case_statement *) + { + not_implemented(); + } + + void empty_visitor::visit(procedure_call *) + { + not_implemented(); + } + + void empty_visitor::visit(unit *) + { + not_implemented(); + } + + void empty_visitor::visit(cast_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(traits_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(binary_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(unary_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(named_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(array_access_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(field_access_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(dereference_expression *) + { + not_implemented(); + } + + void empty_visitor::visit(literal *) + { + not_implemented(); + } + + void empty_visitor::visit(literal *) + { + not_implemented(); + } + + void empty_visitor::visit(literal *) + { + not_implemented(); + } + + void empty_visitor::visit(literal *) + { + not_implemented(); + } + + void empty_visitor::visit(literal *) + { + not_implemented(); + } + + void empty_visitor::visit(literal *) + { + not_implemented(); + } + + void empty_visitor::visit(literal *) + { + not_implemented(); + } + + node::node(const struct position position) + : source_position(position) + { + } + + node::~node() + { + } + + const struct position& node::position() const + { + return this->source_position; + } + + cast_expression *expression::is_cast() + { + return nullptr; + } + + traits_expression *expression::is_traits() + { + return nullptr; + } + + binary_expression *expression::is_binary() + { + return nullptr; + } + + unary_expression *expression::is_unary() + { + return nullptr; + } + + designator_expression *expression::is_designator() + { + return nullptr; + } + + procedure_call *expression::is_call_expression() + { + return nullptr; + } + + literal_expression *expression::is_literal() + { + return nullptr; + } + + named_expression *type_expression::is_named() + { + return nullptr; + } + + array_type_expression *type_expression::is_array() + { + return nullptr; + } + + pointer_type_expression *type_expression::is_pointer() + { + return nullptr; + } + + record_type_expression *type_expression::is_record() + { + return nullptr; + } + + union_type_expression *type_expression::is_union() + { + return nullptr; + } + + procedure_type_expression *type_expression::is_procedure() + { + return nullptr; + } + + enumeration_type_expression *type_expression::is_enumeration() + { + return nullptr; + } + + void type_expression::accept(parser_visitor *visitor) + { + if (named_expression *node = is_named()) + { + return visitor->visit(node); + } + else if (array_type_expression *node = is_array()) + { + return visitor->visit(node); + } + else if (pointer_type_expression *node = is_pointer()) + { + return visitor->visit(node); + } + else if (record_type_expression *node = is_record()) + { + return visitor->visit(node); + } + else if (union_type_expression *node = is_union()) + { + return visitor->visit(node); + } + else if (procedure_type_expression *node = is_procedure()) + { + return visitor->visit(node); + } + else if (enumeration_type_expression *node = is_enumeration()) + { + return visitor->visit(node); + } + __builtin_unreachable(); + } + + type_expression::~type_expression() + { + } + + array_type_expression::array_type_expression(const struct position position, + type_expression *base, const std::uint32_t size) + : node(position), m_base(base), size(size) + { + } + + array_type_expression::~array_type_expression() + { + delete m_base; + } + + void array_type_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + array_type_expression *array_type_expression::is_array() + { + return this; + } + + type_expression& array_type_expression::base() + { + return *m_base; + } + + pointer_type_expression::pointer_type_expression(const struct position position, + type_expression *base) + : node(position), m_base(base) + { + } + + pointer_type_expression::~pointer_type_expression() + { + delete m_base; + } + + void pointer_type_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + pointer_type_expression *pointer_type_expression::is_pointer() + { + return this; + } + + type_expression& pointer_type_expression::base() + { + return *m_base; + } + + record_type_expression::record_type_expression(const struct position position, + std::vector&& fields) + : node(position), fields(std::move(fields)) + { + } + + record_type_expression::~record_type_expression() + { + for (const field_declaration& field : this->fields) + { + delete field.second; + } + } + + void record_type_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + record_type_expression *record_type_expression::is_record() + { + return this; + } + + union_type_expression::union_type_expression(const struct position position, + std::vector&& fields) + : node(position), fields(std::move(fields)) + { + } + + union_type_expression::~union_type_expression() + { + for (const field_declaration& field : this->fields) + { + delete field.second; + } + } + + void union_type_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + union_type_expression *union_type_expression::is_union() + { + return this; + } + + variable_declaration::variable_declaration(const struct position position, + std::vector&& identifier, std::shared_ptr variable_type, + expression *body) + : node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), body(body) + { + } + + variable_declaration::variable_declaration(const struct position position, + std::vector&& identifier, std::shared_ptr variable_type, + std::monostate) + : node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), is_extern(true) + { + } + + void variable_declaration::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + bool variable_declaration::has_initializer() const + { + return this->is_extern || this->body != nullptr; + } + + type_expression& variable_declaration::variable_type() + { + return *m_variable_type; + } + + declaration::declaration(const struct position position, identifier_definition identifier) + : node(position), identifier(identifier) + { + } + + constant_declaration::constant_declaration(const struct position position, identifier_definition identifier, + expression *body) + : declaration(position, identifier), m_body(body) + { + } + + void constant_declaration::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + expression& constant_declaration::body() + { + return *m_body; + } + + constant_declaration::~constant_declaration() + { + delete m_body; + } + + procedure_type_expression::procedure_type_expression(const struct position position, return_t return_type) + : node(position), return_type(return_type) + { + } + + procedure_type_expression::~procedure_type_expression() + { + if (return_type.proper_type != nullptr) + { + delete return_type.proper_type; + } + for (const type_expression *parameter : this->parameters) + { + delete parameter; + } + } + + void procedure_type_expression::accept(parser_visitor *visitor) + { + 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) + : node(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_declaration::procedure_declaration(const struct position position, identifier_definition identifier, + procedure_type_expression *heading, block&& body) + : declaration(position, identifier), m_heading(heading), body(std::move(body)) + { + } + + procedure_declaration::procedure_declaration(const struct position position, identifier_definition identifier, + procedure_type_expression *heading) + : declaration(position, identifier), m_heading(heading), body(std::nullopt) + { + } + + void procedure_declaration::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + procedure_type_expression& procedure_declaration::heading() + { + return *m_heading; + } + + procedure_declaration::~procedure_declaration() + { + delete m_heading; + } + + type_declaration::type_declaration(const struct position position, identifier_definition identifier, + type_expression *body) + : declaration(position, identifier), m_body(body) + { + } + + type_declaration::~type_declaration() + { + delete m_body; + } + + void type_declaration::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + type_expression& type_declaration::body() + { + return *m_body; + } + + block::block(std::vector&& constants, std::vector&& variables, + std::vector&& body) + : m_variables(std::move(variables)), m_constants(std::move(constants)), m_body(std::move(body)) + { + } + + block::block(std::vector&& constants, std::vector&& variables) + : m_variables(std::move(variables)), m_constants(std::move(constants)) + { + } + + block::block(block&& that) + : m_variables(std::move(that.m_variables)), m_constants(std::move(that.m_constants)), + m_body(std::move(that.m_body)) + { + } + + block& block::operator=(block&& that) + { + std::swap(m_variables, that.m_variables); + std::swap(m_constants, that.m_constants); + std::swap(m_body, that.m_body); + + return *this; + } + + const std::vector& block::variables() + { + return m_variables; + } + + const std::vector& block::constants() + { + return m_constants; + } + + const std::vector& block::body() + { + return m_body; + } + + block::~block() + { + for (statement *body_statement : this->body()) + { + delete body_statement; + } + for (variable_declaration *variable : this->variables()) + { + delete variable; + } + for (constant_declaration *constant : this->constants()) + { + delete constant; + } + } + + unit::unit(const struct position position) + : node(position) + { + } + + void unit::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + unit::~unit() + { + for (procedure_declaration *procedure : this->procedures) + { + delete procedure; + } + for (variable_declaration *variable : this->variables) + { + delete variable; + } + for (type_declaration *type : this->types) + { + delete type; + } + for (constant_declaration *constant : this->constants) + { + delete constant; + } + for (import_declaration *declaration : this->imports) + { + delete declaration; + } + } + + program::program(const struct position position) + : unit(position) + { + } + + void program::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + program::~program() + { + for (statement *body_statement : this->body) + { + delete body_statement; + } + } + + literal_expression *literal_expression::is_literal() + { + return this; + } + + defer_statement::defer_statement(const struct position position, std::vector&& statements) + : node(position), statements(std::move(statements)) + { + } + + void defer_statement::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + defer_statement::~defer_statement() + { + for (statement *body_statement : statements) + { + delete body_statement; + } + } + + designator_expression::~designator_expression() + { + } + + designator_expression *designator_expression::is_designator() + { + return this; + } + + void designator_expression::accept(parser_visitor *visitor) + { + if (named_expression *node = is_named()) + { + return visitor->visit(node); + } + else if (array_access_expression *node = is_array_access()) + { + return visitor->visit(node); + } + else if (field_access_expression *node = is_field_access()) + { + return visitor->visit(node); + } + else if (dereference_expression *node = is_dereference()) + { + return visitor->visit(node); + } + __builtin_unreachable(); + } + + named_expression::named_expression(const struct position position, const std::string& name) + : node(position), name(name) + { + } + + void named_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + named_expression *named_expression::is_named() + { + return this; + } + + array_access_expression::array_access_expression(const struct position position, + expression *base, expression *index) + : node(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; + } + + 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_index; + delete m_base; + } + + field_access_expression::field_access_expression(const struct position position, + expression *base, const std::string& field) + : node(position), m_base(base), m_field(field) + { + } + + void field_access_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + expression& field_access_expression::base() + { + return *m_base; + } + + std::string& field_access_expression::field() + { + return m_field; + } + + field_access_expression *field_access_expression::is_field_access() + { + return this; + } + + field_access_expression::~field_access_expression() + { + delete m_base; + } + + dereference_expression::dereference_expression(const struct position position, + expression *base) + : node(position), m_base(base) + { + } + + void dereference_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + expression& dereference_expression::base() + { + return *m_base; + } + + dereference_expression *dereference_expression::is_dereference() + { + return this; + } + + dereference_expression::~dereference_expression() + { + delete m_base; + } + + binary_expression::binary_expression(const struct position position, expression *lhs, + expression *rhs, const binary_operator operation) + : node(position), m_lhs(lhs), m_rhs(rhs), m_operator(operation) + { + } + + void binary_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + binary_expression *binary_expression::is_binary() + { + return this; + } + + expression& binary_expression::lhs() + { + return *m_lhs; + } + + expression& binary_expression::rhs() + { + return *m_rhs; + } + + binary_operator binary_expression::operation() const + { + return m_operator; + } + + binary_expression::~binary_expression() + { + delete m_lhs; + delete m_rhs; + } + + unary_expression::unary_expression(const struct position position, expression *operand, + const unary_operator operation) + : node(position), m_operand(std::move(operand)), m_operator(operation) + { + } + + void unary_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + unary_expression *unary_expression::is_unary() + { + return this; + } + + expression& unary_expression::operand() + { + return *m_operand; + } + + unary_operator unary_expression::operation() const + { + return this->m_operator; + } + + unary_expression::~unary_expression() + { + delete m_operand; + } + + procedure_call::procedure_call(const struct position position, designator_expression *callable) + : node(position), m_callable(callable) + { + } + + void procedure_call::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + procedure_call *procedure_call::is_call_expression() + { + return this; + } + + designator_expression& procedure_call::callable() + { + return *m_callable; + } + + procedure_call::~procedure_call() + { + for (expression *const argument : arguments) + { + delete argument; + } + delete m_callable; + } + + cast_expression::cast_expression(const struct position position, type_expression *target, expression *value) + : node(position), m_target(target), m_value(value) + { + } + + void cast_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + cast_expression *cast_expression::is_cast() + { + return this; + } + + type_expression& cast_expression::target() + { + return *m_target; + } + + expression& cast_expression::value() + { + return *m_value; + } + + cast_expression::~cast_expression() + { + delete m_target; + delete m_value; + } + + traits_expression::traits_expression(const struct position position, const std::string& name) + : node(position), name(name) + { + } + + traits_expression::~traits_expression() + { + for (const type_expression *parameter : this->parameters) + { + delete parameter; + } + } + + void traits_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + traits_expression *traits_expression::is_traits() + { + return this; + } + + conditional_statements::conditional_statements(expression *prerequisite, std::vector&& statements) + : m_prerequisite(prerequisite), statements(std::move(statements)) + { + } + + expression& conditional_statements::prerequisite() + { + return *m_prerequisite; + } + + conditional_statements::~conditional_statements() + { + delete m_prerequisite; + for (auto statement : statements) + { + delete statement; + } + } + + return_statement::return_statement(const struct position position, expression *return_expression) + : node(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() + { + delete m_return_expression; + } + + case_statement::case_statement(const struct position position, + expression *condition, std::vector&& cases, std::vector *alternative) + : node(position), m_condition(condition), cases(std::move(cases)), alternative(alternative) + { + } + + 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, + expression *rvalue) + : node(position), m_lvalue(lvalue), m_rvalue(rvalue) + { + } + + void assign_statement::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + named_expression *designator_expression::is_named() + { + return nullptr; + } + + array_access_expression *designator_expression::is_array_access() + { + return nullptr; + } + + field_access_expression *designator_expression::is_field_access() + { + return nullptr; + } + + dereference_expression *designator_expression::is_dereference() + { + return nullptr; + } + + designator_expression& assign_statement::lvalue() + { + return *m_lvalue; + } + + expression& assign_statement::rvalue() + { + return *m_rvalue; + } + + assign_statement::~assign_statement() + { + delete m_rvalue; + } + + if_statement::if_statement(const struct position position, conditional_statements *body, + std::vector&& branches, + std::vector *alternative) + : node(position), m_body(body), branches(std::move(branches)), alternative(alternative) + { + } + + void if_statement::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + conditional_statements& if_statement::body() + { + return *m_body; + } + + if_statement::~if_statement() + { + delete m_body; + for (const auto branch : branches) + { + delete branch; + } + delete this->alternative; + } + + import_declaration::import_declaration(const struct position position, std::vector&& segments) + : node(position), segments(std::move(segments)) + { + } + + void import_declaration::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + while_statement::while_statement(const struct position position, conditional_statements *body, + std::vector&& branches) + : node(position), m_body(body), branches(std::move(branches)) + { + } + + void while_statement::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + conditional_statements& while_statement::body() + { + return *m_body; + } + + while_statement::~while_statement() + { + delete m_body; + for (const auto branch : branches) + { + delete branch; + } + } + + const char *print_binary_operator(const binary_operator operation) + { + switch (operation) + { + case binary_operator::sum: + return "+"; + case binary_operator::subtraction: + return "-"; + case binary_operator::multiplication: + return "*"; + case binary_operator::division: + return "/"; + case binary_operator::remainder: + return "%"; + case binary_operator::equals: + return "="; + case binary_operator::not_equals: + return "<>"; + case binary_operator::less: + return "<"; + case binary_operator::less_equal: + return "<="; + case binary_operator::greater: + return ">"; + case binary_operator::greater_equal: + return ">="; + case binary_operator::conjunction: + return "and"; + case binary_operator::disjunction: + return "or"; + case binary_operator::exclusive_disjunction: + return "xor"; + case binary_operator::shift_left: + return "<<"; + case binary_operator::shift_right: + return ">>"; + } + __builtin_unreachable(); + }; +} diff --git a/boot/dependency.cc b/boot/dependency.cc new file mode 100644 index 0000000..6b10611 --- /dev/null +++ b/boot/dependency.cc @@ -0,0 +1,102 @@ +/* Dependency graph analysis. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "elna/boot/dependency.h" + +#include +#include +#include + +#include "elna/boot/driver.h" +#include "elna/boot/semantic.h" +#include "parser.hh" + +namespace elna::boot +{ + dependency::dependency(const char *path) + : error_container(path) + { + } + + dependency read_source(std::istream& entry_point, const char *entry_path) + { + driver parse_driver{ entry_path }; + lexer tokenizer(entry_point); + yy::parser parser(tokenizer, parse_driver); + + dependency outcome{ entry_path }; + if (parser()) + { + std::swap(outcome.errors(), parse_driver.errors()); + return outcome; + } + else + { + std::swap(outcome.tree, parse_driver.tree); + } + declaration_visitor declaration_visitor(entry_path); + outcome.tree->accept(&declaration_visitor); + + if (!declaration_visitor.errors().empty()) + { + std::swap(outcome.errors(), declaration_visitor.errors()); + } + outcome.unresolved = declaration_visitor.unresolved; + + return outcome; + } + + error_list analyze_semantics(const char *path, std::unique_ptr& tree, symbol_bag bag) + { + name_analysis_visitor name_analyser(path, bag); + tree->accept(&name_analyser); + + if (name_analyser.has_errors()) + { + return std::move(name_analyser.errors()); + } + type_analysis_visitor type_analyzer(path, bag); + tree->accept(&type_analyzer); + + if (type_analyzer.has_errors()) + { + return std::move(type_analyzer.errors()); + } + return error_list{}; + } + + std::filesystem::path build_path(const std::vector& segments) + { + std::filesystem::path result; + std::vector::const_iterator segment_iterator = std::cbegin(segments); + + if (segment_iterator == std::cend(segments)) + { + return result; + } + result = *segment_iterator; + + ++segment_iterator; + for (; segment_iterator != std::cend(segments); ++segment_iterator) + { + result /= *segment_iterator; + } + result.replace_extension(".elna"); + + return result; + } +} diff --git a/boot/driver.cc b/boot/driver.cc new file mode 100644 index 0000000..abbf0f1 --- /dev/null +++ b/boot/driver.cc @@ -0,0 +1,118 @@ +/* Parsing driver. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "elna/boot/driver.h" + +namespace elna::boot +{ + position make_position(const yy::location& location) + { + position result; + result.line = static_cast(location.begin.line); + result.column = static_cast(location.begin.column); + + return result; + } + + syntax_error::syntax_error(const std::string& message, + const char *input_file, const yy::location& location) + : error(input_file, make_position(location)), message(message) + { + } + + std::string syntax_error::what() const + { + return message; + } + + driver::driver(const char *input_file) + : error_container(input_file) + { + } + + char escape_char(char escape) + { + switch (escape) + { + case 'n': + return '\n'; + case 't': + return '\t'; + case 'f': + return '\f'; + case 'r': + return '\r'; + case 'v': + return '\v'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '"': + return '"'; + case '0': + return '\0'; + default: + return escape_invalid_char; + } + } + + std::optional escape_string(const char *escape) + { + std::string result; + const char *current_position = escape + 1; + + while (*current_position != '\0') + { + if (*current_position == '\\' && *(current_position + 1) == 'x') + { + current_position += 2; + + std::size_t processed; + char character = static_cast(std::stoi(current_position, &processed, 16)); + if (processed == 0) + { + return std::nullopt; + } + else + { + current_position += processed - 1; + result.push_back(character); + } + } + else if (*current_position == '\\') + { + ++current_position; + + char escape = escape_char(*current_position); + if (escape == escape_invalid_char) + { + return std::nullopt; + } + result.push_back(escape); + } + else + { + result.push_back(*current_position); + } + ++current_position; + } + result.pop_back(); // Remove the terminating quote character. + + return result; + } +} diff --git a/boot/lexer.ll b/boot/lexer.ll new file mode 100644 index 0000000..fac70f0 --- /dev/null +++ b/boot/lexer.ll @@ -0,0 +1,314 @@ +/* Lexical analyzer. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +%{ +#define YY_NO_UNISTD_H +#define YY_USER_ACTION this->location.columns(yyleng); + +#include +#include "parser.hh" + +#undef YY_DECL +#define YY_DECL yy::parser::symbol_type elna::boot::lexer::lex(driver& driver) +#define yyterminate() return yy::parser::make_YYEOF(this->location) +%} + +%option c++ noyywrap never-interactive +%option yyclass="lexer" + +%x IN_COMMENT + +ID1 [A-Za-z_] +ID2 [A-Za-z0-9_] +HIGIT [0-9a-fA-F] +BIGIT [01] + +%% +%{ + this->location.step(); +%} + +{ + \*\) BEGIN(INITIAL); + [^*\n]+ ; /* Eat comment in chunks. */ + \* ; /* Eat the lone star. */ + \n+ { + this->location.lines(yyleng); + this->location.step(); + } +} +\(\* BEGIN(IN_COMMENT); +[ \t\r] { + this->location.step(); +} +\n+ { + this->location.lines(yyleng); +} +if { + return yy::parser::make_IF(this->location); +} +then { + return yy::parser::make_THEN(this->location); +} +else { + return yy::parser::make_ELSE(this->location); +} +elsif { + return yy::parser::make_ELSIF(this->location); +} +while { + return yy::parser::make_WHILE(this->location); +} +do { + return yy::parser::make_DO(this->location); +} +proc { + return yy::parser::make_PROCEDURE(this->location); +} +begin { + return yy::parser::make_BEGIN_BLOCK(this->location); + } +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); +} +var { + return yy::parser::make_VAR(this->location); +} +type { + return yy::parser::make_TYPE(this->location); +} +record { + return yy::parser::make_RECORD(this->location); +} +union { + return yy::parser::make_UNION(this->location); +} +true { + return yy::parser::make_BOOLEAN(true, this->location); +} +false { + return yy::parser::make_BOOLEAN(false, this->location); +} +nil { + return yy::parser::make_NIL(this->location); +} +\& { + return yy::parser::make_AND(this->location); +} +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); +} +return { + return yy::parser::make_RETURN(this->location); +} +import { + return yy::parser::make_IMPORT(this->location); +} +cast { + return yy::parser::make_CAST(this->location); +} +defer { + return yy::parser::make_DEFER(this->location); +} +case { + return yy::parser::make_CASE(this->location); +} +of { + return yy::parser::make_OF(this->location); +} +{ID1}{ID2}* { + return yy::parser::make_IDENTIFIER(yytext, this->location); +} +#{ID1}{ID2}* { + return yy::parser::make_TRAIT(yytext + 1, this->location); +} +[[:digit:]]+u { + unsigned long result = strtoul(yytext, NULL, 10); + + if (errno == ERANGE) + { + REJECT; + } + else + { + return yy::parser::make_WORD(result, this->location); + } +} +[[:digit:]]+ { + long result = strtol(yytext, NULL, 10); + + if (errno == ERANGE) + { + REJECT; + } + else + { + return yy::parser::make_INTEGER(result, this->location); + } +} +0[x|X]{HIGIT}+ { + unsigned long result = strtoul(yytext, NULL, 16); + + if (errno == ERANGE) + { + REJECT; + } + else + { + return yy::parser::make_WORD(result, this->location); + } +} +0[b|B]{BIGIT}+ { + unsigned long result = strtoul(yytext, NULL, 2); + + if (errno == ERANGE) + { + REJECT; + } + else + { + return yy::parser::make_WORD(result, this->location); + } +} +[[:digit:]]+\.[[:digit:]]+ { + float result = strtof(yytext, NULL); + + if (errno == ERANGE) + { + REJECT; + } + else + { + return yy::parser::make_FLOAT(result, this->location); + } +} +'[[:print:]]+' { + std::optional result = escape_string(yytext); + if (!result.has_value() || result.value().size() != 1) + { + REJECT; + } + return yy::parser::make_CHARACTER(result.value(), this->location); +} +\"[[:print:]]*\" { + std::optional result = escape_string(yytext); + if (!result.has_value()) + { + REJECT; + } + return yy::parser::make_STRING(result.value(), this->location); +} +\( { + return yy::parser::make_LEFT_PAREN(this->location); +} +\) { + return yy::parser::make_RIGHT_PAREN(this->location); +} +\[ { + return yy::parser::make_LEFT_SQUARE(this->location); +} +\] { + return yy::parser::make_RIGHT_SQUARE(this->location); +} +\<\< { + return yy::parser::make_SHIFT_LEFT(this->location); +} +\>\> { + return yy::parser::make_SHIFT_RIGHT(this->location); +} +\>= { + return yy::parser::make_GREATER_EQUAL(this->location); +} +\<= { + return yy::parser::make_LESS_EQUAL(this->location); +} +\> { + return yy::parser::make_GREATER_THAN(this->location); +} +\< { + return yy::parser::make_LESS_THAN(this->location); +} +\<\> { + return yy::parser::make_NOT_EQUAL(this->location); +} += { + return yy::parser::make_EQUALS(this->location); +} +; { + return yy::parser::make_SEMICOLON(this->location); +} +\. { + return yy::parser::make_DOT(this->location); +} +, { + return yy::parser::make_COMMA(this->location); +} +\+ { + return yy::parser::make_PLUS(this->location); +} +\-> { + return yy::parser::make_ARROW(this->location); +} +\- { + return yy::parser::make_MINUS(this->location); +} +\* { + return yy::parser::make_MULTIPLICATION(this->location); +} +\/ { + return yy::parser::make_DIVISION(this->location); +} +% { + return yy::parser::make_REMAINDER(this->location); +} +:= { + return yy::parser::make_ASSIGNMENT(this->location); +} +: { + return yy::parser::make_COLON(this->location); +} +\^ { + return yy::parser::make_HAT(this->location); +} +@ { + return yy::parser::make_AT(this->location); +} +! { + return yy::parser::make_EXCLAMATION(this->location); +} +. { + std::stringstream ss; + + ss << "Illegal character 0x" << std::hex << static_cast(yytext[0]); + driver.add_error(ss.str(), driver.input_file, this->location); +} +%% diff --git a/boot/parser.yy b/boot/parser.yy new file mode 100644 index 0000000..1a5364b --- /dev/null +++ b/boot/parser.yy @@ -0,0 +1,595 @@ +/* Syntax analyzer. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +%require "3.4" +%language "c++" + +%code { + using namespace elna; +} + +%code requires { + #include + #include + #include "elna/boot/driver.h" + + #if !defined(yyFlexLexerOnce) + #include + #endif + + namespace elna::boot + { + class lexer; + } +} + +%code provides { + namespace elna::boot + { + + class lexer: public yyFlexLexer + { + public: + yy::location location; + + lexer(std::istream& arg_yyin) + : yyFlexLexer(&arg_yyin) + { + } + + yy::parser::symbol_type lex(driver& driver); + }; + + } +} + +%define api.token.raw +%define api.token.constructor +%define api.value.type variant + +%parse-param {elna::boot::lexer& lexer} +%param {elna::boot::driver& driver} +%locations + +%header + +%code { + #define yylex lexer.lex +} +%start program; + +%token IDENTIFIER +%token TRAIT +%token INTEGER +%token WORD +%token FLOAT +%token CHARACTER +%token STRING +%token BOOLEAN +%token LEFT_PAREN "(" RIGHT_PAREN ")" LEFT_SQUARE "[" RIGHT_SQUARE "]" +%token ASSIGNMENT ":=" + ARROW "->" EXCLAMATION "!" + AT "@" HAT "^" + COLON ":" SEMICOLON ";" DOT "." COMMA "," +%token NOT "~" + CAST "cast" + NIL "nil" + CONST "const" + VAR "var" + PROCEDURE "proc" + TYPE "type" + RECORD "record" + UNION "union" + EXTERN "extern" + IF "if" + WHILE "while" + DO "do" + THEN "then" + ELSE "else" + ELSIF "elsif" + RETURN "return" + IMPORT "import" + BEGIN_BLOCK "begin" + END_BLOCK "end" + DEFER "defer" + 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 "or" "&" "xor" +%left "=" "<>" "<" ">" "<=" ">=" +%left "<<" ">>" +%left "+" "-" +%left "*" "/" "%" + +%type literal; +%type > case_labels; +%type switch_case; +%type > switch_cases; +%type constant_declaration; +%type > constant_part constant_declarations; +%type variable_declaration; +%type > variable_declarations variable_part; +%type type_expression; +%type > type_expressions; +%type traits_expression; +%type expression operand simple_expression; +%type unary_expression; +%type binary_expression; +%type > expressions actual_parameter_list; +%type designator_expression; +%type call_expression; +%type return_statement; +%type statement; +%type > required_statements optional_statements; +%type >> statement_part; +%type procedure_declaration; +%type , elna::boot::procedure_type_expression *>> procedure_heading; +%type return_declaration; +%type > procedure_part; +%type type_declaration; +%type > type_declarations type_part; +%type > block; +%type field_declaration formal_parameter; +%type >> + optional_fields required_fields formal_parameters formal_parameter_list; +%type > elsif_then_statements elsif_do_statements; +%type *> else_statements; +%type cast_expression; +%type identifier_definition; +%type > identifier_definitions; +%type > identifiers import_declaration; +%type > import_declarations import_part; +%% +program: + import_part constant_part type_part variable_part procedure_part statement_part "end" "." + { + if ($6) + { + boot::program *tree = new boot::program(boot::make_position(@1)); + std::swap(tree->body, *$6.release()); + + driver.tree.reset(tree); + } + else + { + driver.tree.reset(new boot::unit(boot::make_position(@1))); + } + std::swap(driver.tree->imports, $1); + std::swap(driver.tree->constants, $2); + std::swap(driver.tree->types , $3); + std::swap(driver.tree->variables, $4); + std::swap(driver.tree->procedures, $5); + } +block: constant_part variable_part statement_part "end" + { + if ($3) + { + $$ = std::make_unique(std::move($1), std::move($2), std::move(*$3.release())); + } + else + { + $$ = std::make_unique(std::move($1), std::move($2)); + } + } +statement_part: + /* no statements */ {} + | "begin" required_statements { $$ = std::make_unique>(std::move($2));; } + | return_statement + { + $$ = std::make_unique>(std::vector{ $1 }); + } + | "begin" required_statements ";" return_statement + { + $$ = std::make_unique>(std::move($2)); + $$->push_back($4); + } +identifier_definition: + IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; } + | IDENTIFIER { $$ = boot::identifier_definition{ $1, false }; } +identifier_definitions: + identifier_definition "," identifier_definitions + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | identifier_definition { $$.emplace_back(std::move($1)); } +return_declaration: + /* proper procedure */ {} + | "->" "!" { $$ = boot::procedure_type_expression::return_t(std::monostate{}); } + | "->" type_expression { $$ = boot::procedure_type_expression::return_t($2); } +procedure_heading: formal_parameter_list return_declaration + { + $$.second = new boot::procedure_type_expression(boot::make_position(@1), std::move($2)); + for (auto& [name, type] : $1) + { + $$.first.emplace_back(std::move(name)); + $$.second->parameters.push_back(type); + } + } +procedure_declaration: + "proc" identifier_definition procedure_heading block + { + $$ = new boot::procedure_declaration(boot::make_position(@1), std::move($2), $3.second, + std::move(*$4)); + std::swap($3.first, $$->parameter_names); + } + | "proc" identifier_definition procedure_heading "extern" + { + $$ = new boot::procedure_declaration(boot::make_position(@1), std::move($2), $3.second); + std::swap($3.first, $$->parameter_names); + } +procedure_part: + /* no procedure declarations */ {} + | procedure_declaration procedure_part + { + std::swap($$, $2); + $$.emplace($$.cbegin(), std::move($1)); + } +call_expression: designator_expression actual_parameter_list + { + $$ = new boot::procedure_call(boot::make_position(@1), $1); + std::swap($$->arguments, $2); + } +cast_expression: "cast" "(" expression ":" type_expression ")" + { $$ = new boot::cast_expression(boot::make_position(@1), $5, $3); } +elsif_do_statements: + "elsif" expression "do" optional_statements elsif_do_statements + { + boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); + std::swap($5, $$); + $$.emplace($$.begin(), branch); + } + | {} +else_statements: + "else" optional_statements { $$ = new std::vector(std::move($2)); } + | { $$ = nullptr; } +elsif_then_statements: + "elsif" expression "then" optional_statements elsif_then_statements + { + boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); + std::swap($5, $$); + $$.emplace($$.begin(), branch); + } + | {} +return_statement: "return" expression + { $$ = new boot::return_statement(boot::make_position(@1), $2); } +literal: + INTEGER { $$ = new boot::literal(boot::make_position(@1), $1); } + | WORD { $$ = new boot::literal(boot::make_position(@1), $1); } + | FLOAT { $$ = new boot::literal(boot::make_position(@1), $1); } + | BOOLEAN { $$ = new boot::literal(boot::make_position(@1), $1); } + | CHARACTER { $$ = new boot::literal(boot::make_position(@1), $1.at(0)); } + | "nil" { $$ = new boot::literal(boot::make_position(@1), nullptr); } + | STRING { $$ = new boot::literal(boot::make_position(@1), $1); } +traits_expression: + TRAIT "(" type_expressions ")" + { + $$ = new boot::traits_expression(boot::make_position(@1), $1); + std::swap($3, $$->parameters); + } +simple_expression: + literal { $$ = $1; } + | designator_expression { $$ = $1; } + | traits_expression { $$ = $1; } + | cast_expression { $$ = $1; } + | call_expression { $$ = $1; } + | "(" expression ")" { $$ = $2; } +operand: + unary_expression { $$ = $1; } + | simple_expression { $$ = $1; } +expression: + binary_expression { $$ = $1; } + | operand { $$ = $1; } +binary_expression: + expression "*" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::multiplication); + } + | expression "/" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::division); + } + | expression "%" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::remainder); + } + | expression "+" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::sum); + } + | expression "-" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::subtraction); + } + | expression "=" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::equals); + } + | expression "<>" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::not_equals); + } + | expression "<" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::less); + } + | expression ">" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater); + } + | expression "<=" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, + boot::binary_operator::less_equal); + } + | expression ">=" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::greater_equal); + } + | expression "&" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::conjunction); + } + | expression "or" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::disjunction); + } + | expression "xor" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, + boot::binary_operator::exclusive_disjunction); + } + | expression "<<" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_left); + } + | expression ">>" expression + { + $$ = new boot::binary_expression(boot::make_position(@2), $1, $3, boot::binary_operator::shift_right); + } +unary_expression: + "@" operand + { + $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::reference); + } + | "~" operand + { + $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::negation); + } + | "-" operand + { + $$ = new boot::unary_expression(boot::make_position(@1), $2, boot::unary_operator::minus); + } +expressions: + expression "," expressions + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | expression { $$.push_back($1); } +type_expressions: + type_expression "," type_expressions + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | type_expression { $$.push_back($1); } +designator_expression: + simple_expression "[" expression "]" + { $$ = new boot::array_access_expression(boot::make_position(@2), $1, $3); } + | simple_expression "." IDENTIFIER + { $$ = new boot::field_access_expression(boot::make_position(@2), $1, $3); } + | simple_expression "^" + { $$ = new boot::dereference_expression(boot::make_position(@1), $1); } + | IDENTIFIER + { $$ = new boot::named_expression(boot::make_position(@1), $1); } +statement: + designator_expression ":=" expression + { $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); } + | "while" expression "do" optional_statements elsif_do_statements "end" + { + boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4)); + $$ = new boot::while_statement(boot::make_position(@1), body, std::move($5)); + } + | "if" expression "then" optional_statements elsif_then_statements else_statements "end" + { + boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4)); + $$ = new boot::if_statement(boot::make_position(@1), then, std::move($5), $6); + } + | call_expression { $$ = $1; } + | "defer" optional_statements "end" + { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } + | "case" expression "of" switch_cases else_statements "end" + { $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4), $5); } +switch_case: case_labels ":" optional_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: + expression "," case_labels + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | expression { $$.push_back($1); } +required_statements: + required_statements ";" statement + { + std::swap($$, $1); + $$.insert($$.cend(), $3); + } + | statement { $$.push_back($1); } +optional_statements: + required_statements { std::swap($$, $1); } + | /* no statements */ {} +field_declaration: + IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } +required_fields: + field_declaration ";" required_fields + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | field_declaration { $$.emplace_back($1); } +optional_fields: + required_fields { std::swap($$, $1); } + | /* no fields */ {} +type_expression: + "[" INTEGER "]" type_expression + { + $$ = new boot::array_type_expression(boot::make_position(@1), $4, $2); + } + | "^" type_expression + { + $$ = new boot::pointer_type_expression(boot::make_position(@1), $2); + } + | "record" optional_fields "end" + { + $$ = new boot::record_type_expression(boot::make_position(@1), std::move($2)); + } + | "union" required_fields "end" + { + $$ = new boot::union_type_expression(boot::make_position(@1), std::move($2)); + } + | "proc" "(" type_expressions ")" return_declaration + { + auto result = new boot::procedure_type_expression(boot::make_position(@1), std::move($5)); + std::swap(result->parameters, $3); + $$ = result; + } + | "(" identifiers ")" + { + $$ = new boot::enumeration_type_expression(boot::make_position(@1), std::move($2)); + } + | IDENTIFIER + { + $$ = new boot::named_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 }; + $$ = new boot::variable_declaration( boot::make_position(@2), std::move($1), shared_type); + } + | identifier_definitions ":" type_expression ":=" "extern" + { + std::shared_ptr shared_type{ $3 }; + $$ = new boot::variable_declaration( boot::make_position(@2), std::move($1), shared_type, + std::monostate{}); + } + | identifier_definitions ":" type_expression ":=" expression + { + std::shared_ptr shared_type{ $3 }; + $$ = new boot::variable_declaration( boot::make_position(@2), std::move($1), shared_type, $5); + } +variable_declarations: + /* no variable declarations */ {} + | variable_declaration variable_declarations + { + std::swap($$, $2); + $$.insert(std::cbegin($$), $1); + } +variable_part: + /* no variable declarations */ {} + | "var" variable_declarations { std::swap($$, $2); } +constant_declaration: identifier_definition ":=" expression + { + $$ = new boot::constant_declaration(boot::make_position(@1), std::move($1), $3); + } +constant_declarations: + constant_declaration constant_declarations + { + std::swap($$, $2); + $$.insert(std::cbegin($$), $1); + } + | /* no constant definitions */ {} +constant_part: + /* no constant definitions */ {} + | "const" constant_declarations { std::swap($$, $2); } +import_declaration: + IDENTIFIER "." import_declaration + { + std::swap($$, $3); + $$.emplace($$.cbegin(), std::move($1)); + } + | IDENTIFIER { $$.emplace_back(std::move($1)); } +import_declarations: + import_declaration "," import_declarations + { + std::swap($$, $3); + $$.emplace($$.cbegin(), new boot::import_declaration(boot::make_position(@1), std::move($1))); + } + | import_declaration + { + $$.emplace_back(new boot::import_declaration(boot::make_position(@1), std::move($1))); + } +import_part: + /* no import declarations */ {} + | "import" import_declarations { std::swap($$, $2); } +type_declaration: identifier_definition "=" type_expression + { + $$ = new boot::type_declaration(boot::make_position(@1), std::move($1), $3); + } +type_declarations: + type_declaration type_declarations + { + std::swap($$, $2); + $$.insert($$.cbegin(), $1); + } + | /* no type definitions */ {} +type_part: + /* no type definitions */ {} + | "type" type_declarations { std::swap($$, $2); } +formal_parameter: + IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } +formal_parameter_list: + "(" ")" {} + | "(" formal_parameters ")" { std::swap($$, $2); } +formal_parameters: + formal_parameter "," formal_parameters + { + std::swap($$, $3); + $$.emplace($$.cbegin(), std::move($1)); + } + | formal_parameter { $$.emplace_back(std::move($1)); } +actual_parameter_list: + "(" ")" {} + | "(" expressions ")" { std::swap($$, $2); } +%% + +void yy::parser::error(const location_type& loc, const std::string& message) +{ + driver.add_error(message, driver.input_file, loc); +} diff --git a/boot/result.cc b/boot/result.cc new file mode 100644 index 0000000..dab82f4 --- /dev/null +++ b/boot/result.cc @@ -0,0 +1,67 @@ +/* Miscellaneous types used across stage boundaries. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "elna/boot/result.h" + +namespace elna::boot +{ + error::error(const char *path, const struct position position) + : position(position), path(path) + { + } + + std::size_t error::line() const noexcept + { + return this->position.line; + } + + std::size_t error::column() const noexcept + { + return this->position.column; + } + + error_container::error_container(const char *input_file) + : input_file(input_file) + { + } + + std::deque>& error_container::errors() + { + return m_errors; + } + + bool error_container::has_errors() const + { + return !m_errors.empty(); + } + + bool identifier_definition::operator==(const identifier_definition& that) const + { + return *this == that.name; + } + + bool identifier_definition::operator==(const std::string& that) const + { + return this->name == that; + } +} + +std::size_t std::hash::operator()( + const elna::boot::identifier_definition& key) const +{ + return std::hash{}(key.name); +} diff --git a/boot/semantic.cc b/boot/semantic.cc new file mode 100644 index 0000000..3ccc81b --- /dev/null +++ b/boot/semantic.cc @@ -0,0 +1,682 @@ +/* Name analysis. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "elna/boot/semantic.h" + +#include +#include + +namespace elna::boot +{ + undeclared_error::undeclared_error(const std::string& identifier, const char *path, const struct position position) + : error(path, position), identifier(identifier) + { + } + + std::string undeclared_error::what() const + { + return "Type '" + identifier + "' not declared"; + } + + already_declared_error::already_declared_error(const std::string& identifier, + const char *path, const struct position position) + : error(path, position), identifier(identifier) + { + } + + std::string already_declared_error::what() const + { + return "Symbol '" + identifier + "' has been already declared"; + } + + field_duplication_error::field_duplication_error(const std::string& field_name, + const char *path, const struct position position) + : error(path, position), field_name(field_name) + { + } + + std::string field_duplication_error::what() const + { + return "Repeated field name '" + field_name + "'"; + } + + cyclic_declaration_error::cyclic_declaration_error(const std::vector& cycle, + const char *path, const struct position position) + : error(path, position), cycle(cycle) + { + } + + std::string cyclic_declaration_error::what() const + { + auto segment = std::cbegin(this->cycle); + std::string message = "Type declaration forms a cycle: " + *segment; + + ++segment; + for (; segment != std::cend(this->cycle); ++segment) + { + message += " -> " + *segment; + } + return message; + } + + return_error::return_error(const std::string& identifier, const char *path, const struct position position) + : error(path, position), identifier(identifier) + { + } + + std::string return_error::what() const + { + return "Procedure '" + identifier + "' is expected to return, but does not have a return statement"; + } + + variable_initializer_error::variable_initializer_error(const char *path, const struct position position) + : error(path, position) + { + } + + std::string variable_initializer_error::what() const + { + return "Only one variable can be initialized"; + } + + type_analysis_visitor::type_analysis_visitor(const char *path, symbol_bag bag) + : error_container(path), bag(bag) + { + } + + void type_analysis_visitor::visit(program *program) + { + visit(static_cast(program)); + } + + void type_analysis_visitor::visit(procedure_declaration *definition) + { + if (definition->body.has_value() && definition->heading().return_type.proper_type != nullptr) + { + for (statement *const statement : definition->body.value().body()) + { + statement->accept(this); + } + if (!this->returns) + { + add_error(definition->identifier.name, this->input_file, definition->position()); + } + } + } + + void type_analysis_visitor::visit(assign_statement *) + { + } + + void type_analysis_visitor::visit(if_statement *) + { + } + + void type_analysis_visitor::visit(while_statement *) + { + } + + void type_analysis_visitor::visit(return_statement *) + { + this->returns = true; + } + + void type_analysis_visitor::visit(defer_statement *) + { + } + + void type_analysis_visitor::visit(case_statement *) + { + } + + void type_analysis_visitor::visit(procedure_call *) + { + } + + bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr alias, + std::vector& alias_path) + { + if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path)) + { + return false; + } + alias_path.push_back(alias->name); + + if (auto another_alias = alias->reference.get()) + { + return check_unresolved_symbol(another_alias, alias_path); + } + return true; + } + + void type_analysis_visitor::visit(unit *unit) + { + for (type_declaration *const type : unit->types) + { + type->accept(this); + } + for (procedure_declaration *const procedure : unit->procedures) + { + this->returns = false; + procedure->accept(this); + } + } + + void type_analysis_visitor::visit(type_declaration *definition) + { + std::vector alias_path; + auto unresolved_type = this->bag.lookup(definition->identifier.name)->is_type()->symbol.get(); + + if (!check_unresolved_symbol(unresolved_type, alias_path)) + { + add_error(alias_path, this->input_file, definition->position()); + } + } + + name_analysis_visitor::name_analysis_visitor(const char *path, symbol_bag bag) + : error_container(path), bag(bag) + { + } + + procedure_type name_analysis_visitor::build_procedure(procedure_type_expression& type_expression) + { + procedure_type::return_t result_return; + + if (type_expression.return_type.no_return) + { + result_return = procedure_type::return_t(std::monostate{}); + } + else if (type_expression.return_type.proper_type != nullptr) + { + type_expression.return_type.proper_type->accept(this); + result_return = procedure_type::return_t(this->current_type); + } + else + { + result_return = procedure_type::return_t(); + } + procedure_type result_type = procedure_type(result_return); + + for (struct type_expression *parameter : type_expression.parameters) + { + parameter->accept(this); + result_type.parameters.push_back(this->current_type); + } + return result_type; + } + + void name_analysis_visitor::visit(program *program) + { + visit(static_cast(program)); + + this->bag.enter(); + auto variable_type = this->bag.lookup("Int")->is_type()->symbol; + this->bag.enter("count", std::make_shared(variable_type, false)); + + variable_type = this->bag.lookup("Char")->is_type()->symbol; + variable_type = type(std::make_shared(variable_type)); + variable_type = type(std::make_shared(variable_type)); + this->bag.enter("parameters", std::make_shared(variable_type, false)); + + for (statement *const statement : program->body) + { + statement->accept(this); + } + this->bag.leave(); + } + + void name_analysis_visitor::visit(type_declaration *definition) + { + definition->body().accept(this); + auto resolved = this->bag.resolve(definition->identifier.name, this->current_type); + auto info = std::make_shared(type(resolved)); + + info->exported = definition->identifier.exported; + this->bag.enter(definition->identifier.name, info); + } + + void name_analysis_visitor::visit(type_expression *) + { + } + + void name_analysis_visitor::visit(pointer_type_expression *type_expression) + { + type_expression->base().accept(this); + this->current_type = type(std::make_shared(this->current_type)); + } + + void name_analysis_visitor::visit(array_type_expression *type_expression) + { + type_expression->base().accept(this); + auto result_type{ std::make_shared(this->current_type, type_expression->size) }; + + this->current_type = type(result_type); + } + + std::vector name_analysis_visitor::build_composite_type(const std::vector& fields) + { + std::vector result; + std::set field_names; + + for (auto& field : fields) + { + if (field_names.find(field.first) != field_names.cend()) + { + add_error(field.first, this->input_file, field.second->position()); + } + else + { + field_names.insert(field.first); + field.second->accept(this); + result.push_back(std::make_pair(field.first, this->current_type)); + } + } + return result; + } + + void name_analysis_visitor::visit(record_type_expression *type_expression) + { + auto result_type = std::make_shared(); + + result_type->fields = build_composite_type(type_expression->fields); + + this->current_type = type(result_type); + } + + void name_analysis_visitor::visit(union_type_expression *type_expression) + { + auto result_type = std::make_shared(); + + result_type->fields = build_composite_type(type_expression->fields); + + this->current_type = type(result_type); + } + + void name_analysis_visitor::visit(procedure_type_expression *type_expression) + { + std::shared_ptr result_type = + std::make_shared(std::move(build_procedure(*type_expression))); + + this->current_type = type(result_type); + } + + void name_analysis_visitor::visit(enumeration_type_expression *type_expression) + { + std::shared_ptr result_type = std::make_shared(type_expression->members); + + this->current_type = type(result_type); + } + + std::shared_ptr name_analysis_visitor::register_variable(const std::string& name, + const bool is_extern, const struct position position) + { + auto variable_symbol = std::make_shared(this->current_type, is_extern); + + if (!this->bag.enter(name, variable_symbol)) + { + add_error(name, this->input_file, position); + } + return variable_symbol; + } + + void name_analysis_visitor::visit(variable_declaration *declaration) + { + declaration->variable_type().accept(this); + + for (const auto& variable_identifier : declaration->identifiers) + { + auto variable_symbol = register_variable(variable_identifier.name, declaration->is_extern, + declaration->position()); + variable_symbol->exported = variable_identifier.exported; + } + } + + void name_analysis_visitor::visit(constant_declaration *definition) + { + definition->body().accept(this); + auto constant_symbol = std::make_shared(this->current_literal); + + constant_symbol->exported = definition->identifier.exported; + this->bag.enter(definition->identifier.name, constant_symbol); + } + + void name_analysis_visitor::visit(procedure_declaration *definition) + { + std::shared_ptr info; + auto heading = build_procedure(definition->heading()); + + if (definition->body.has_value()) + { + info = std::make_shared(heading, definition->parameter_names, this->bag.enter()); + auto name_iterator = std::cbegin(definition->parameter_names); + auto type_iterator = std::cbegin(heading.parameters); + + while (name_iterator != std::cend(definition->parameter_names) + && type_iterator != std::cend(heading.parameters)) + { + this->current_type = *type_iterator; + auto variable_symbol = register_variable(*name_iterator, false, definition->heading().position()); + variable_symbol->exported = false; + + ++name_iterator; + ++type_iterator; + } + for (constant_declaration *const constant : definition->body.value().constants()) + { + constant->accept(this); + } + for (variable_declaration *const variable : definition->body.value().variables()) + { + variable->accept(this); + } + for (statement *const statement : definition->body.value().body()) + { + statement->accept(this); + } + this->bag.leave(); + } + else + { + info = std::make_shared(heading, definition->parameter_names); + } + info->exported = definition->identifier.exported; + this->bag.enter(definition->identifier.name, info); + } + + void name_analysis_visitor::visit(assign_statement *statement) + { + statement->lvalue().accept(this); + statement->rvalue().accept(this); + } + + void name_analysis_visitor::visit(if_statement *statement) + { + statement->body().prerequisite().accept(this); + for (struct statement *const statement : statement->body().statements) + { + statement->accept(this); + } + for (const auto branch : statement->branches) + { + branch->prerequisite().accept(this); + + for (struct statement *const statement : branch->statements) + { + statement->accept(this); + } + } + if (statement->alternative != nullptr) + { + for (struct statement *const statement : *statement->alternative) + { + statement->accept(this); + } + } + } + + void name_analysis_visitor::visit(import_declaration *) + { + } + + void name_analysis_visitor::visit(while_statement *statement) + { + statement->body().prerequisite().accept(this); + for (struct statement *const statement : statement->body().statements) + { + statement->accept(this); + } + for (const auto branch : statement->branches) + { + branch->prerequisite().accept(this); + + for (struct statement *const statement : branch->statements) + { + statement->accept(this); + } + } + } + + void name_analysis_visitor::visit(return_statement *statement) + { + statement->return_expression().accept(this); + } + + void name_analysis_visitor::visit(defer_statement *statement) + { + for (struct statement *const statement : statement->statements) + { + statement->accept(this); + } + } + + void name_analysis_visitor::visit(case_statement *statement) + { + statement->condition().accept(this); + for (const switch_case& case_block : statement->cases) + { + for (expression *const case_label : case_block.labels) + { + case_label->accept(this); + } + for (struct statement *const statement : case_block.statements) + { + statement->accept(this); + } + } + if (statement->alternative != nullptr) + { + for (struct statement *const statement : *statement->alternative) + { + statement->accept(this); + } + } + } + + void name_analysis_visitor::visit(procedure_call *call) + { + call->callable().accept(this); + for (expression *const argument: call->arguments) + { + argument->accept(this); + } + } + + void name_analysis_visitor::visit(unit *unit) + { + for (type_declaration *const type : unit->types) + { + type->accept(this); + } + for (variable_declaration *const variable : unit->variables) + { + variable->accept(this); + } + for (constant_declaration *const constant : unit->constants) + { + constant->accept(this); + } + for (procedure_declaration *const procedure : unit->procedures) + { + procedure->accept(this); + } + } + + void name_analysis_visitor::visit(traits_expression *trait) + { + if (!trait->parameters.empty()) + { + trait->parameters.front()->accept(this); + trait->types.push_back(this->current_type); + } + } + + void name_analysis_visitor::visit(cast_expression *expression) + { + expression->value().accept(this); + expression->target().accept(this); + expression->expression_type = this->current_type; + } + + void name_analysis_visitor::visit(binary_expression *expression) + { + expression->lhs().accept(this); + expression->rhs().accept(this); + } + + void name_analysis_visitor::visit(unary_expression *expression) + { + expression->operand().accept(this); + } + + void name_analysis_visitor::visit(named_expression *type_expression) + { + auto unresolved_alias = this->bag.declared(type_expression->name); + + if (unresolved_alias != nullptr) + { + this->current_type = type(unresolved_alias); + } + else if (auto from_symbol_table = this->bag.lookup(type_expression->name)) + { + if (auto type_symbol = from_symbol_table->is_type()) + { + this->current_type = type_symbol->symbol; + } + } + else + { + add_error(type_expression->name, this->input_file, type_expression->position()); + this->current_type = type(); + } + } + + void name_analysis_visitor::visit(array_access_expression *expression) + { + expression->base().accept(this); + expression->index().accept(this); + } + + void name_analysis_visitor::visit(field_access_expression *expression) + { + expression->base().accept(this); + } + + void name_analysis_visitor::visit(dereference_expression *expression) + { + expression->base().accept(this); + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + void name_analysis_visitor::visit(literal *literal) + { + this->current_literal = literal->value; + } + + declaration_visitor::declaration_visitor(const char *path) + : error_container(path) + { + } + + void declaration_visitor::visit(program *program) + { + visit(static_cast(program)); + } + + void declaration_visitor::visit(import_declaration *) + { + } + + void declaration_visitor::visit(unit *unit) + { + for (import_declaration *const _import : unit->imports) + { + _import->accept(this); + } + for (type_declaration *const type : unit->types) + { + type->accept(this); + } + for (variable_declaration *const variable : unit->variables) + { + variable->accept(this); + } + for (procedure_declaration *const procedure : unit->procedures) + { + procedure->accept(this); + } + } + + void declaration_visitor::visit(type_declaration *definition) + { + const std::string& type_identifier = definition->identifier.name; + + if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second) + { + add_error(definition->identifier.name, this->input_file, + definition->position()); + } + } + + void declaration_visitor::visit(variable_declaration *declaration) + { + if (declaration->has_initializer() && declaration->identifiers.size() > 1) + { + add_error(this->input_file, declaration->position()); + } + } + + void declaration_visitor::visit(procedure_declaration *definition) + { + if (!definition->body.has_value()) + { + return; + } + for (variable_declaration *const variable : definition->body.value().variables()) + { + variable->accept(this); + } + } +} diff --git a/boot/symbol.cc b/boot/symbol.cc new file mode 100644 index 0000000..902d331 --- /dev/null +++ b/boot/symbol.cc @@ -0,0 +1,427 @@ +/* Symbol definitions. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "elna/boot/symbol.h" + +namespace elna::boot +{ + type::type() + { + } + + type::type(std::shared_ptr alias) + : tag(type_tag::alias), alias(alias) + { + } + + type::type(std::shared_ptr primitive) + : tag(type_tag::primitive), primitive(primitive) + { + } + + type::type(std::shared_ptr record) + : tag(type_tag::record), record(record) + { + } + + type::type(std::shared_ptr _union) + : tag(type_tag::_union), _union(_union) + { + } + + type::type(std::shared_ptr pointer) + : tag(type_tag::pointer), pointer(pointer) + { + } + + type::type(std::shared_ptr array) + : tag(type_tag::array), array(array) + { + } + + type::type(std::shared_ptr procedure) + : tag(type_tag::procedure), procedure(procedure) + { + } + + type::type(std::shared_ptr enumeration) + : tag(type_tag::enumeration), enumeration(enumeration) + { + } + + void type::copy(const type& other) + { + switch (other.tag) + { + case type_tag::empty: + break; + case type_tag::alias: + new (&alias) std::weak_ptr(other.alias); + break; + case type_tag::primitive: + new (&primitive) std::shared_ptr(other.primitive); + break; + case type_tag::record: + new (&record) std::shared_ptr(other.record); + break; + case type_tag::_union: + new (&_union) std::shared_ptr(other._union); + break; + case type_tag::pointer: + new (&pointer) std::shared_ptr(other.pointer); + break; + case type_tag::array: + new (&array) std::shared_ptr(other.array); + break; + case type_tag::procedure: + new (&procedure) std::shared_ptr(other.procedure); + break; + case type_tag::enumeration: + new (&enumeration) std::shared_ptr(other.enumeration); + break; + } + } + + type::type(const type& other) + : tag(other.tag) + { + copy(other); + } + + void type::move(type&& other) + { + switch (other.tag) + { + case type_tag::empty: + break; + case type_tag::alias: + new (&alias) std::weak_ptr(std::move(other.alias)); + break; + case type_tag::primitive: + new (&primitive) std::shared_ptr(std::move(other.primitive)); + break; + case type_tag::record: + new (&record) std::shared_ptr(std::move(other.record)); + break; + case type_tag::_union: + new (&_union) std::shared_ptr(std::move(other._union)); + break; + case type_tag::pointer: + new (&pointer) std::shared_ptr(std::move(other.pointer)); + break; + case type_tag::array: + new (&array) std::shared_ptr(std::move(other.array)); + break; + 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; + } + } + + type& type::operator=(const type& other) + { + this->~type(); + this->tag = other.tag; + copy(other); + return *this; + } + + type::type(type&& other) + : tag(other.tag) + { + move(std::move(other)); + } + + type& type::operator=(type&& other) + { + this->~type(); + this->tag = other.tag; + move(std::move(other)); + return *this; + } + + bool type::operator==(const std::nullptr_t&) + { + return empty(); + } + + type::~type() + { + switch (tag) + { + case type_tag::empty: + break; + case type_tag::alias: + this->alias.~weak_ptr(); + break; + case type_tag::primitive: + this->primitive.~shared_ptr(); + break; + case type_tag::record: + this->record.~shared_ptr(); + break; + case type_tag::_union: + this->_union.~shared_ptr(); + break; + case type_tag::pointer: + this->pointer.~shared_ptr(); + break; + case type_tag::array: + this->array.~shared_ptr(); + break; + case type_tag::procedure: + this->procedure.~shared_ptr(); + break; + case type_tag::enumeration: + this->enumeration.~shared_ptr(); + break; + } + } + + template<> + std::shared_ptr type::get() const + { + return tag == type_tag::alias ? this->alias.lock() : nullptr; + } + + template<> + std::shared_ptr type::get() const + { + return tag == type_tag::primitive ? this->primitive : nullptr; + } + + template<> + std::shared_ptr type::get() const + { + return tag == type_tag::record ? this->record : nullptr; + } + + template<> + std::shared_ptr type::get() const + { + return tag == type_tag::_union ? this->_union : nullptr; + } + + template<> + std::shared_ptr type::get() const + { + return tag == type_tag::pointer ? this->pointer : nullptr; + } + + template<> + std::shared_ptr type::get() const + { + return tag == type_tag::array ? this->array : nullptr; + } + + template<> + std::shared_ptr type::get() const + { + 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; + } + + alias_type::alias_type(const std::string& name) + : name(name), reference() + { + } + + pointer_type::pointer_type(type base) + : base(base) + { + } + + array_type::array_type(type base, std::uint64_t size) + : base(base), size(size) + { + } + + primitive_type::primitive_type(const std::string& identifier) + : identifier(identifier) + { + } + + procedure_type::procedure_type(return_t return_type) + : return_type(return_type) + { + } + + enumeration_type::enumeration_type(const std::vector& members) + : members(members) + { + } + + info::~info() + { + } + + std::shared_ptr info::is_type() + { + return nullptr; + } + + std::shared_ptr info::is_procedure() + { + return nullptr; + } + + std::shared_ptr info::is_constant() + { + return nullptr; + } + + std::shared_ptr info::is_variable() + { + return nullptr; + } + + type_info::type_info(const type symbol) + : symbol(symbol) + { + } + + std::shared_ptr type_info::is_type() + { + return std::static_pointer_cast(shared_from_this()); + } + + procedure_info::procedure_info(const procedure_type symbol, const std::vector names, + std::shared_ptr scope) + : symbol(symbol), names(names), scope(scope) + { + } + + std::shared_ptr procedure_info::is_procedure() + { + return std::static_pointer_cast(shared_from_this()); + } + + bool procedure_info::is_extern() const + { + return this->scope == nullptr; + } + + constant_info::constant_info(const variant& symbol) + : symbol(symbol) + { + } + + std::shared_ptr constant_info::is_constant() + { + return std::static_pointer_cast(shared_from_this()); + } + + variable_info::variable_info(const type symbol, bool is_extern) + : symbol(symbol), is_extern(is_extern) + { + } + + std::shared_ptr variable_info::is_variable() + { + return std::static_pointer_cast(shared_from_this()); + } + + std::shared_ptr builtin_symbol_table() + { + auto result = std::make_shared(); + + result->enter("Int", std::make_shared(type(std::make_shared("Int")))); + result->enter("Word", std::make_shared(type(std::make_shared("Word")))); + result->enter("Char", std::make_shared(type(std::make_shared("Char")))); + result->enter("Bool", std::make_shared(type(std::make_shared("Bool")))); + result->enter("Pointer", std::make_shared(type(std::make_shared("Pointer")))); + result->enter("Float", std::make_shared(type(std::make_shared("Float")))); + result->enter("String", std::make_shared(type(std::make_shared("String")))); + + return result; + } + + symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr global_table) + : unresolved(unresolved) + { + this->symbols = std::make_shared(global_table); + } + + std::shared_ptr symbol_bag::lookup(const std::string& name) + { + for (auto import_bag : this->imports) + { + if (auto result = import_bag->lookup(name)) + { + return result; + } + } + return this->symbols->lookup(name); + } + + bool symbol_bag::enter(const std::string& name, std::shared_ptr entry) + { + return this->symbols->enter(name, entry); + } + + std::shared_ptr symbol_bag::enter() + { + this->symbols = std::make_shared(this->symbols); + return this->symbols; + } + + void symbol_bag::enter(std::shared_ptr child) + { + this->symbols = child; + } + + std::shared_ptr symbol_bag::leave() + { + std::shared_ptr result = this->symbols; + + this->symbols = result->scope(); + return result; + } + + std::shared_ptr symbol_bag::declared(const std::string& symbol_name) + { + auto unresolved_alias = this->unresolved.find(symbol_name); + + return unresolved_alias == this->unresolved.end() ? std::shared_ptr() : unresolved_alias->second; + } + + std::shared_ptr symbol_bag::resolve(const std::string& symbol_name, type& resolution) + { + auto unresolved_declaration = this->unresolved.at(symbol_name); + + unresolved_declaration->reference = resolution; + return unresolved_declaration; + } + + void symbol_bag::add_import(const symbol_bag& bag) + { + this->imports.push_front(bag.symbols); + } +} diff --git a/frontend/ast.cc b/frontend/ast.cc deleted file mode 100644 index 9a1f96b..0000000 --- a/frontend/ast.cc +++ /dev/null @@ -1,1192 +0,0 @@ -/* Abstract syntax tree representation. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "elna/frontend/ast.h" - -namespace elna::frontend -{ - void empty_visitor::not_implemented() - { - __builtin_unreachable(); - } - - void empty_visitor::visit(type_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(array_type_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(pointer_type_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(program *) - { - not_implemented(); - } - - void empty_visitor::visit(type_declaration *) - { - not_implemented(); - } - - void empty_visitor::visit(record_type_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(union_type_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(procedure_type_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(enumeration_type_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(variable_declaration *) - { - not_implemented(); - } - - void empty_visitor::visit(constant_declaration *) - { - not_implemented(); - } - - void empty_visitor::visit(procedure_declaration *) - { - not_implemented(); - } - - void empty_visitor::visit(assign_statement *) - { - not_implemented(); - } - - void empty_visitor::visit(if_statement *) - { - not_implemented(); - } - - void empty_visitor::visit(import_declaration *) - { - not_implemented(); - } - - void empty_visitor::visit(while_statement *) - { - not_implemented(); - } - - void empty_visitor::visit(return_statement *) - { - not_implemented(); - } - - void empty_visitor::visit(defer_statement *) - { - not_implemented(); - } - - void empty_visitor::visit(case_statement *) - { - not_implemented(); - } - - void empty_visitor::visit(procedure_call *) - { - not_implemented(); - } - - void empty_visitor::visit(unit *) - { - not_implemented(); - } - - void empty_visitor::visit(cast_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(traits_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(binary_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(unary_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(named_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(array_access_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(field_access_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(dereference_expression *) - { - not_implemented(); - } - - void empty_visitor::visit(literal *) - { - not_implemented(); - } - - void empty_visitor::visit(literal *) - { - not_implemented(); - } - - void empty_visitor::visit(literal *) - { - not_implemented(); - } - - void empty_visitor::visit(literal *) - { - not_implemented(); - } - - void empty_visitor::visit(literal *) - { - not_implemented(); - } - - void empty_visitor::visit(literal *) - { - not_implemented(); - } - - void empty_visitor::visit(literal *) - { - not_implemented(); - } - - node::node(const struct position position) - : source_position(position) - { - } - - node::~node() - { - } - - const struct position& node::position() const - { - return this->source_position; - } - - cast_expression *expression::is_cast() - { - return nullptr; - } - - traits_expression *expression::is_traits() - { - return nullptr; - } - - binary_expression *expression::is_binary() - { - return nullptr; - } - - unary_expression *expression::is_unary() - { - return nullptr; - } - - designator_expression *expression::is_designator() - { - return nullptr; - } - - procedure_call *expression::is_call_expression() - { - return nullptr; - } - - literal_expression *expression::is_literal() - { - return nullptr; - } - - named_expression *type_expression::is_named() - { - return nullptr; - } - - array_type_expression *type_expression::is_array() - { - return nullptr; - } - - pointer_type_expression *type_expression::is_pointer() - { - return nullptr; - } - - record_type_expression *type_expression::is_record() - { - return nullptr; - } - - union_type_expression *type_expression::is_union() - { - return nullptr; - } - - procedure_type_expression *type_expression::is_procedure() - { - return nullptr; - } - - enumeration_type_expression *type_expression::is_enumeration() - { - return nullptr; - } - - void type_expression::accept(parser_visitor *visitor) - { - if (named_expression *node = is_named()) - { - return visitor->visit(node); - } - else if (array_type_expression *node = is_array()) - { - return visitor->visit(node); - } - else if (pointer_type_expression *node = is_pointer()) - { - return visitor->visit(node); - } - else if (record_type_expression *node = is_record()) - { - return visitor->visit(node); - } - else if (union_type_expression *node = is_union()) - { - return visitor->visit(node); - } - else if (procedure_type_expression *node = is_procedure()) - { - return visitor->visit(node); - } - else if (enumeration_type_expression *node = is_enumeration()) - { - return visitor->visit(node); - } - __builtin_unreachable(); - } - - type_expression::~type_expression() - { - } - - array_type_expression::array_type_expression(const struct position position, - type_expression *base, const std::uint32_t size) - : node(position), m_base(base), size(size) - { - } - - array_type_expression::~array_type_expression() - { - delete m_base; - } - - void array_type_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - array_type_expression *array_type_expression::is_array() - { - return this; - } - - type_expression& array_type_expression::base() - { - return *m_base; - } - - pointer_type_expression::pointer_type_expression(const struct position position, - type_expression *base) - : node(position), m_base(base) - { - } - - pointer_type_expression::~pointer_type_expression() - { - delete m_base; - } - - void pointer_type_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - pointer_type_expression *pointer_type_expression::is_pointer() - { - return this; - } - - type_expression& pointer_type_expression::base() - { - return *m_base; - } - - record_type_expression::record_type_expression(const struct position position, - std::vector&& fields) - : node(position), fields(std::move(fields)) - { - } - - record_type_expression::~record_type_expression() - { - for (const field_declaration& field : this->fields) - { - delete field.second; - } - } - - void record_type_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - record_type_expression *record_type_expression::is_record() - { - return this; - } - - union_type_expression::union_type_expression(const struct position position, - std::vector&& fields) - : node(position), fields(std::move(fields)) - { - } - - union_type_expression::~union_type_expression() - { - for (const field_declaration& field : this->fields) - { - delete field.second; - } - } - - void union_type_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - union_type_expression *union_type_expression::is_union() - { - return this; - } - - variable_declaration::variable_declaration(const struct position position, - std::vector&& identifier, std::shared_ptr variable_type, - expression *body) - : node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), body(body) - { - } - - variable_declaration::variable_declaration(const struct position position, - std::vector&& identifier, std::shared_ptr variable_type, - std::monostate) - : node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), is_extern(true) - { - } - - void variable_declaration::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - bool variable_declaration::has_initializer() const - { - return this->is_extern || this->body != nullptr; - } - - type_expression& variable_declaration::variable_type() - { - return *m_variable_type; - } - - declaration::declaration(const struct position position, identifier_definition identifier) - : node(position), identifier(identifier) - { - } - - constant_declaration::constant_declaration(const struct position position, identifier_definition identifier, - expression *body) - : declaration(position, identifier), m_body(body) - { - } - - void constant_declaration::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - expression& constant_declaration::body() - { - return *m_body; - } - - constant_declaration::~constant_declaration() - { - delete m_body; - } - - procedure_type_expression::procedure_type_expression(const struct position position, return_t return_type) - : node(position), return_type(return_type) - { - } - - procedure_type_expression::~procedure_type_expression() - { - if (return_type.proper_type != nullptr) - { - delete return_type.proper_type; - } - for (const type_expression *parameter : this->parameters) - { - delete parameter; - } - } - - void procedure_type_expression::accept(parser_visitor *visitor) - { - 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) - : node(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_declaration::procedure_declaration(const struct position position, identifier_definition identifier, - procedure_type_expression *heading, block&& body) - : declaration(position, identifier), m_heading(heading), body(std::move(body)) - { - } - - procedure_declaration::procedure_declaration(const struct position position, identifier_definition identifier, - procedure_type_expression *heading) - : declaration(position, identifier), m_heading(heading), body(std::nullopt) - { - } - - void procedure_declaration::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - procedure_type_expression& procedure_declaration::heading() - { - return *m_heading; - } - - procedure_declaration::~procedure_declaration() - { - delete m_heading; - } - - type_declaration::type_declaration(const struct position position, identifier_definition identifier, - type_expression *body) - : declaration(position, identifier), m_body(body) - { - } - - type_declaration::~type_declaration() - { - delete m_body; - } - - void type_declaration::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - type_expression& type_declaration::body() - { - return *m_body; - } - - block::block(std::vector&& constants, std::vector&& variables, - std::vector&& body) - : m_variables(std::move(variables)), m_constants(std::move(constants)), m_body(std::move(body)) - { - } - - block::block(std::vector&& constants, std::vector&& variables) - : m_variables(std::move(variables)), m_constants(std::move(constants)) - { - } - - block::block(block&& that) - : m_variables(std::move(that.m_variables)), m_constants(std::move(that.m_constants)), - m_body(std::move(that.m_body)) - { - } - - block& block::operator=(block&& that) - { - std::swap(m_variables, that.m_variables); - std::swap(m_constants, that.m_constants); - std::swap(m_body, that.m_body); - - return *this; - } - - const std::vector& block::variables() - { - return m_variables; - } - - const std::vector& block::constants() - { - return m_constants; - } - - const std::vector& block::body() - { - return m_body; - } - - block::~block() - { - for (statement *body_statement : this->body()) - { - delete body_statement; - } - for (variable_declaration *variable : this->variables()) - { - delete variable; - } - for (constant_declaration *constant : this->constants()) - { - delete constant; - } - } - - unit::unit(const struct position position) - : node(position) - { - } - - void unit::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - unit::~unit() - { - for (procedure_declaration *procedure : this->procedures) - { - delete procedure; - } - for (variable_declaration *variable : this->variables) - { - delete variable; - } - for (type_declaration *type : this->types) - { - delete type; - } - for (constant_declaration *constant : this->constants) - { - delete constant; - } - for (import_declaration *declaration : this->imports) - { - delete declaration; - } - } - - program::program(const struct position position) - : unit(position) - { - } - - void program::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - program::~program() - { - for (statement *body_statement : this->body) - { - delete body_statement; - } - } - - literal_expression *literal_expression::is_literal() - { - return this; - } - - defer_statement::defer_statement(const struct position position, std::vector&& statements) - : node(position), statements(std::move(statements)) - { - } - - void defer_statement::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - defer_statement::~defer_statement() - { - for (statement *body_statement : statements) - { - delete body_statement; - } - } - - designator_expression::~designator_expression() - { - } - - designator_expression *designator_expression::is_designator() - { - return this; - } - - void designator_expression::accept(parser_visitor *visitor) - { - if (named_expression *node = is_named()) - { - return visitor->visit(node); - } - else if (array_access_expression *node = is_array_access()) - { - return visitor->visit(node); - } - else if (field_access_expression *node = is_field_access()) - { - return visitor->visit(node); - } - else if (dereference_expression *node = is_dereference()) - { - return visitor->visit(node); - } - __builtin_unreachable(); - } - - named_expression::named_expression(const struct position position, const std::string& name) - : node(position), name(name) - { - } - - void named_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - named_expression *named_expression::is_named() - { - return this; - } - - array_access_expression::array_access_expression(const struct position position, - expression *base, expression *index) - : node(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; - } - - 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_index; - delete m_base; - } - - field_access_expression::field_access_expression(const struct position position, - expression *base, const std::string& field) - : node(position), m_base(base), m_field(field) - { - } - - void field_access_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - expression& field_access_expression::base() - { - return *m_base; - } - - std::string& field_access_expression::field() - { - return m_field; - } - - field_access_expression *field_access_expression::is_field_access() - { - return this; - } - - field_access_expression::~field_access_expression() - { - delete m_base; - } - - dereference_expression::dereference_expression(const struct position position, - expression *base) - : node(position), m_base(base) - { - } - - void dereference_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - expression& dereference_expression::base() - { - return *m_base; - } - - dereference_expression *dereference_expression::is_dereference() - { - return this; - } - - dereference_expression::~dereference_expression() - { - delete m_base; - } - - binary_expression::binary_expression(const struct position position, expression *lhs, - expression *rhs, const binary_operator operation) - : node(position), m_lhs(lhs), m_rhs(rhs), m_operator(operation) - { - } - - void binary_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - binary_expression *binary_expression::is_binary() - { - return this; - } - - expression& binary_expression::lhs() - { - return *m_lhs; - } - - expression& binary_expression::rhs() - { - return *m_rhs; - } - - binary_operator binary_expression::operation() const - { - return m_operator; - } - - binary_expression::~binary_expression() - { - delete m_lhs; - delete m_rhs; - } - - unary_expression::unary_expression(const struct position position, expression *operand, - const unary_operator operation) - : node(position), m_operand(std::move(operand)), m_operator(operation) - { - } - - void unary_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - unary_expression *unary_expression::is_unary() - { - return this; - } - - expression& unary_expression::operand() - { - return *m_operand; - } - - unary_operator unary_expression::operation() const - { - return this->m_operator; - } - - unary_expression::~unary_expression() - { - delete m_operand; - } - - procedure_call::procedure_call(const struct position position, designator_expression *callable) - : node(position), m_callable(callable) - { - } - - void procedure_call::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - procedure_call *procedure_call::is_call_expression() - { - return this; - } - - designator_expression& procedure_call::callable() - { - return *m_callable; - } - - procedure_call::~procedure_call() - { - for (expression *const argument : arguments) - { - delete argument; - } - delete m_callable; - } - - cast_expression::cast_expression(const struct position position, type_expression *target, expression *value) - : node(position), m_target(target), m_value(value) - { - } - - void cast_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - cast_expression *cast_expression::is_cast() - { - return this; - } - - type_expression& cast_expression::target() - { - return *m_target; - } - - expression& cast_expression::value() - { - return *m_value; - } - - cast_expression::~cast_expression() - { - delete m_target; - delete m_value; - } - - traits_expression::traits_expression(const struct position position, const std::string& name) - : node(position), name(name) - { - } - - traits_expression::~traits_expression() - { - for (const type_expression *parameter : this->parameters) - { - delete parameter; - } - } - - void traits_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - traits_expression *traits_expression::is_traits() - { - return this; - } - - conditional_statements::conditional_statements(expression *prerequisite, std::vector&& statements) - : m_prerequisite(prerequisite), statements(std::move(statements)) - { - } - - expression& conditional_statements::prerequisite() - { - return *m_prerequisite; - } - - conditional_statements::~conditional_statements() - { - delete m_prerequisite; - for (auto statement : statements) - { - delete statement; - } - } - - return_statement::return_statement(const struct position position, expression *return_expression) - : node(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() - { - delete m_return_expression; - } - - case_statement::case_statement(const struct position position, - expression *condition, std::vector&& cases, std::vector *alternative) - : node(position), m_condition(condition), cases(std::move(cases)), alternative(alternative) - { - } - - 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, - expression *rvalue) - : node(position), m_lvalue(lvalue), m_rvalue(rvalue) - { - } - - void assign_statement::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - named_expression *designator_expression::is_named() - { - return nullptr; - } - - array_access_expression *designator_expression::is_array_access() - { - return nullptr; - } - - field_access_expression *designator_expression::is_field_access() - { - return nullptr; - } - - dereference_expression *designator_expression::is_dereference() - { - return nullptr; - } - - designator_expression& assign_statement::lvalue() - { - return *m_lvalue; - } - - expression& assign_statement::rvalue() - { - return *m_rvalue; - } - - assign_statement::~assign_statement() - { - delete m_rvalue; - } - - if_statement::if_statement(const struct position position, conditional_statements *body, - std::vector&& branches, - std::vector *alternative) - : node(position), m_body(body), branches(std::move(branches)), alternative(alternative) - { - } - - void if_statement::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - conditional_statements& if_statement::body() - { - return *m_body; - } - - if_statement::~if_statement() - { - delete m_body; - for (const auto branch : branches) - { - delete branch; - } - delete this->alternative; - } - - import_declaration::import_declaration(const struct position position, std::vector&& segments) - : node(position), segments(std::move(segments)) - { - } - - void import_declaration::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - while_statement::while_statement(const struct position position, conditional_statements *body, - std::vector&& branches) - : node(position), m_body(body), branches(std::move(branches)) - { - } - - void while_statement::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - conditional_statements& while_statement::body() - { - return *m_body; - } - - while_statement::~while_statement() - { - delete m_body; - for (const auto branch : branches) - { - delete branch; - } - } - - const char *print_binary_operator(const binary_operator operation) - { - switch (operation) - { - case binary_operator::sum: - return "+"; - case binary_operator::subtraction: - return "-"; - case binary_operator::multiplication: - return "*"; - case binary_operator::division: - return "/"; - case binary_operator::remainder: - return "%"; - case binary_operator::equals: - return "="; - case binary_operator::not_equals: - return "<>"; - case binary_operator::less: - return "<"; - case binary_operator::less_equal: - return "<="; - case binary_operator::greater: - return ">"; - case binary_operator::greater_equal: - return ">="; - case binary_operator::conjunction: - return "and"; - case binary_operator::disjunction: - return "or"; - case binary_operator::exclusive_disjunction: - return "xor"; - case binary_operator::shift_left: - return "<<"; - case binary_operator::shift_right: - return ">>"; - } - __builtin_unreachable(); - }; -} diff --git a/frontend/dependency.cc b/frontend/dependency.cc deleted file mode 100644 index 25658f8..0000000 --- a/frontend/dependency.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* Dependency graph analysis. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "elna/frontend/dependency.h" - -#include -#include -#include - -#include "elna/frontend/driver.h" -#include "elna/frontend/semantic.h" -#include "parser.hh" - -namespace elna::frontend -{ - dependency::dependency(const char *path) - : error_container(path) - { - } - - dependency read_source(std::istream& entry_point, const char *entry_path) - { - driver parse_driver{ entry_path }; - lexer tokenizer(entry_point); - yy::parser parser(tokenizer, parse_driver); - - dependency outcome{ entry_path }; - if (parser()) - { - std::swap(outcome.errors(), parse_driver.errors()); - return outcome; - } - else - { - std::swap(outcome.tree, parse_driver.tree); - } - declaration_visitor declaration_visitor(entry_path); - outcome.tree->accept(&declaration_visitor); - - if (!declaration_visitor.errors().empty()) - { - std::swap(outcome.errors(), declaration_visitor.errors()); - } - outcome.unresolved = declaration_visitor.unresolved; - - return outcome; - } - - error_list analyze_semantics(const char *path, std::unique_ptr& tree, symbol_bag bag) - { - name_analysis_visitor name_analyser(path, bag); - tree->accept(&name_analyser); - - if (name_analyser.has_errors()) - { - return std::move(name_analyser.errors()); - } - type_analysis_visitor type_analyzer(path, bag); - tree->accept(&type_analyzer); - - if (type_analyzer.has_errors()) - { - return std::move(type_analyzer.errors()); - } - return error_list{}; - } - - std::filesystem::path build_path(const std::vector& segments) - { - std::filesystem::path result; - std::vector::const_iterator segment_iterator = std::cbegin(segments); - - if (segment_iterator == std::cend(segments)) - { - return result; - } - result = *segment_iterator; - - ++segment_iterator; - for (; segment_iterator != std::cend(segments); ++segment_iterator) - { - result /= *segment_iterator; - } - result.replace_extension(".elna"); - - return result; - } -} diff --git a/frontend/driver.cc b/frontend/driver.cc deleted file mode 100644 index a266937..0000000 --- a/frontend/driver.cc +++ /dev/null @@ -1,118 +0,0 @@ -/* Parsing driver. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "elna/frontend/driver.h" - -namespace elna::frontend -{ - position make_position(const yy::location& location) - { - position result; - result.line = static_cast(location.begin.line); - result.column = static_cast(location.begin.column); - - return result; - } - - syntax_error::syntax_error(const std::string& message, - const char *input_file, const yy::location& location) - : error(input_file, make_position(location)), message(message) - { - } - - std::string syntax_error::what() const - { - return message; - } - - driver::driver(const char *input_file) - : error_container(input_file) - { - } - - char escape_char(char escape) - { - switch (escape) - { - case 'n': - return '\n'; - case 't': - return '\t'; - case 'f': - return '\f'; - case 'r': - return '\r'; - case 'v': - return '\v'; - case '\\': - return '\\'; - case '\'': - return '\''; - case '"': - return '"'; - case '0': - return '\0'; - default: - return escape_invalid_char; - } - } - - std::optional escape_string(const char *escape) - { - std::string result; - const char *current_position = escape + 1; - - while (*current_position != '\0') - { - if (*current_position == '\\' && *(current_position + 1) == 'x') - { - current_position += 2; - - std::size_t processed; - char character = static_cast(std::stoi(current_position, &processed, 16)); - if (processed == 0) - { - return std::nullopt; - } - else - { - current_position += processed - 1; - result.push_back(character); - } - } - else if (*current_position == '\\') - { - ++current_position; - - char escape = escape_char(*current_position); - if (escape == escape_invalid_char) - { - return std::nullopt; - } - result.push_back(escape); - } - else - { - result.push_back(*current_position); - } - ++current_position; - } - result.pop_back(); // Remove the terminating quote character. - - return result; - } -} diff --git a/frontend/lexer.ll b/frontend/lexer.ll deleted file mode 100644 index b48b4a6..0000000 --- a/frontend/lexer.ll +++ /dev/null @@ -1,314 +0,0 @@ -/* Lexical analyzer. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -%{ -#define YY_NO_UNISTD_H -#define YY_USER_ACTION this->location.columns(yyleng); - -#include -#include "parser.hh" - -#undef YY_DECL -#define YY_DECL yy::parser::symbol_type elna::frontend::lexer::lex(driver& driver) -#define yyterminate() return yy::parser::make_YYEOF(this->location) -%} - -%option c++ noyywrap never-interactive -%option yyclass="lexer" - -%x IN_COMMENT - -ID1 [A-Za-z_] -ID2 [A-Za-z0-9_] -HIGIT [0-9a-fA-F] -BIGIT [01] - -%% -%{ - this->location.step(); -%} - -{ - \*\) BEGIN(INITIAL); - [^*\n]+ ; /* Eat comment in chunks. */ - \* ; /* Eat the lone star. */ - \n+ { - this->location.lines(yyleng); - this->location.step(); - } -} -\(\* BEGIN(IN_COMMENT); -[ \t\r] { - this->location.step(); -} -\n+ { - this->location.lines(yyleng); -} -if { - return yy::parser::make_IF(this->location); -} -then { - return yy::parser::make_THEN(this->location); -} -else { - return yy::parser::make_ELSE(this->location); -} -elsif { - return yy::parser::make_ELSIF(this->location); -} -while { - return yy::parser::make_WHILE(this->location); -} -do { - return yy::parser::make_DO(this->location); -} -proc { - return yy::parser::make_PROCEDURE(this->location); -} -begin { - return yy::parser::make_BEGIN_BLOCK(this->location); - } -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); -} -var { - return yy::parser::make_VAR(this->location); -} -type { - return yy::parser::make_TYPE(this->location); -} -record { - return yy::parser::make_RECORD(this->location); -} -union { - return yy::parser::make_UNION(this->location); -} -true { - return yy::parser::make_BOOLEAN(true, this->location); -} -false { - return yy::parser::make_BOOLEAN(false, this->location); -} -nil { - return yy::parser::make_NIL(this->location); -} -\& { - return yy::parser::make_AND(this->location); -} -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); -} -return { - return yy::parser::make_RETURN(this->location); -} -import { - return yy::parser::make_IMPORT(this->location); -} -cast { - return yy::parser::make_CAST(this->location); -} -defer { - return yy::parser::make_DEFER(this->location); -} -case { - return yy::parser::make_CASE(this->location); -} -of { - return yy::parser::make_OF(this->location); -} -{ID1}{ID2}* { - return yy::parser::make_IDENTIFIER(yytext, this->location); -} -#{ID1}{ID2}* { - return yy::parser::make_TRAIT(yytext + 1, this->location); -} -[[:digit:]]+u { - unsigned long result = strtoul(yytext, NULL, 10); - - if (errno == ERANGE) - { - REJECT; - } - else - { - return yy::parser::make_WORD(result, this->location); - } -} -[[:digit:]]+ { - long result = strtol(yytext, NULL, 10); - - if (errno == ERANGE) - { - REJECT; - } - else - { - return yy::parser::make_INTEGER(result, this->location); - } -} -0[x|X]{HIGIT}+ { - unsigned long result = strtoul(yytext, NULL, 16); - - if (errno == ERANGE) - { - REJECT; - } - else - { - return yy::parser::make_WORD(result, this->location); - } -} -0[b|B]{BIGIT}+ { - unsigned long result = strtoul(yytext, NULL, 2); - - if (errno == ERANGE) - { - REJECT; - } - else - { - return yy::parser::make_WORD(result, this->location); - } -} -[[:digit:]]+\.[[:digit:]]+ { - float result = strtof(yytext, NULL); - - if (errno == ERANGE) - { - REJECT; - } - else - { - return yy::parser::make_FLOAT(result, this->location); - } -} -'[[:print:]]+' { - std::optional result = escape_string(yytext); - if (!result.has_value() || result.value().size() != 1) - { - REJECT; - } - return yy::parser::make_CHARACTER(result.value(), this->location); -} -\"[[:print:]]*\" { - std::optional result = escape_string(yytext); - if (!result.has_value()) - { - REJECT; - } - return yy::parser::make_STRING(result.value(), this->location); -} -\( { - return yy::parser::make_LEFT_PAREN(this->location); -} -\) { - return yy::parser::make_RIGHT_PAREN(this->location); -} -\[ { - return yy::parser::make_LEFT_SQUARE(this->location); -} -\] { - return yy::parser::make_RIGHT_SQUARE(this->location); -} -\<\< { - return yy::parser::make_SHIFT_LEFT(this->location); -} -\>\> { - return yy::parser::make_SHIFT_RIGHT(this->location); -} -\>= { - return yy::parser::make_GREATER_EQUAL(this->location); -} -\<= { - return yy::parser::make_LESS_EQUAL(this->location); -} -\> { - return yy::parser::make_GREATER_THAN(this->location); -} -\< { - return yy::parser::make_LESS_THAN(this->location); -} -\<\> { - return yy::parser::make_NOT_EQUAL(this->location); -} -= { - return yy::parser::make_EQUALS(this->location); -} -; { - return yy::parser::make_SEMICOLON(this->location); -} -\. { - return yy::parser::make_DOT(this->location); -} -, { - return yy::parser::make_COMMA(this->location); -} -\+ { - return yy::parser::make_PLUS(this->location); -} -\-> { - return yy::parser::make_ARROW(this->location); -} -\- { - return yy::parser::make_MINUS(this->location); -} -\* { - return yy::parser::make_MULTIPLICATION(this->location); -} -\/ { - return yy::parser::make_DIVISION(this->location); -} -% { - return yy::parser::make_REMAINDER(this->location); -} -:= { - return yy::parser::make_ASSIGNMENT(this->location); -} -: { - return yy::parser::make_COLON(this->location); -} -\^ { - return yy::parser::make_HAT(this->location); -} -@ { - return yy::parser::make_AT(this->location); -} -! { - return yy::parser::make_EXCLAMATION(this->location); -} -. { - std::stringstream ss; - - ss << "Illegal character 0x" << std::hex << static_cast(yytext[0]); - driver.add_error(ss.str(), driver.input_file, this->location); -} -%% diff --git a/frontend/parser.yy b/frontend/parser.yy deleted file mode 100644 index 5e3837b..0000000 --- a/frontend/parser.yy +++ /dev/null @@ -1,595 +0,0 @@ -/* Syntax analyzer. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -%require "3.4" -%language "c++" - -%code { - using namespace elna; -} - -%code requires { - #include - #include - #include "elna/frontend/driver.h" - - #if !defined(yyFlexLexerOnce) - #include - #endif - - namespace elna::frontend - { - class lexer; - } -} - -%code provides { - namespace elna::frontend - { - - class lexer: public yyFlexLexer - { - public: - yy::location location; - - lexer(std::istream& arg_yyin) - : yyFlexLexer(&arg_yyin) - { - } - - yy::parser::symbol_type lex(driver& driver); - }; - - } -} - -%define api.token.raw -%define api.token.constructor -%define api.value.type variant - -%parse-param {elna::frontend::lexer& lexer} -%param {elna::frontend::driver& driver} -%locations - -%header - -%code { - #define yylex lexer.lex -} -%start program; - -%token IDENTIFIER -%token TRAIT -%token INTEGER -%token WORD -%token FLOAT -%token CHARACTER -%token STRING -%token BOOLEAN -%token LEFT_PAREN "(" RIGHT_PAREN ")" LEFT_SQUARE "[" RIGHT_SQUARE "]" -%token ASSIGNMENT ":=" - ARROW "->" EXCLAMATION "!" - AT "@" HAT "^" - COLON ":" SEMICOLON ";" DOT "." COMMA "," -%token NOT "~" - CAST "cast" - NIL "nil" - CONST "const" - VAR "var" - PROCEDURE "proc" - TYPE "type" - RECORD "record" - UNION "union" - EXTERN "extern" - IF "if" - WHILE "while" - DO "do" - THEN "then" - ELSE "else" - ELSIF "elsif" - RETURN "return" - IMPORT "import" - BEGIN_BLOCK "begin" - END_BLOCK "end" - DEFER "defer" - 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 "or" "&" "xor" -%left "=" "<>" "<" ">" "<=" ">=" -%left "<<" ">>" -%left "+" "-" -%left "*" "/" "%" - -%type literal; -%type > case_labels; -%type switch_case; -%type > switch_cases; -%type constant_declaration; -%type > constant_part constant_declarations; -%type variable_declaration; -%type > variable_declarations variable_part; -%type type_expression; -%type > type_expressions; -%type traits_expression; -%type expression operand simple_expression; -%type unary_expression; -%type binary_expression; -%type > expressions actual_parameter_list; -%type designator_expression; -%type call_expression; -%type return_statement; -%type statement; -%type > required_statements optional_statements; -%type >> statement_part; -%type procedure_declaration; -%type , elna::frontend::procedure_type_expression *>> procedure_heading; -%type return_declaration; -%type > procedure_part; -%type type_declaration; -%type > type_declarations type_part; -%type > block; -%type field_declaration formal_parameter; -%type >> - optional_fields required_fields formal_parameters formal_parameter_list; -%type > elsif_then_statements elsif_do_statements; -%type *> else_statements; -%type cast_expression; -%type identifier_definition; -%type > identifier_definitions; -%type > identifiers import_declaration; -%type > import_declarations import_part; -%% -program: - import_part constant_part type_part variable_part procedure_part statement_part "end" "." - { - if ($6) - { - frontend::program *tree = new frontend::program(frontend::make_position(@1)); - std::swap(tree->body, *$6.release()); - - driver.tree.reset(tree); - } - else - { - driver.tree.reset(new frontend::unit(frontend::make_position(@1))); - } - std::swap(driver.tree->imports, $1); - std::swap(driver.tree->constants, $2); - std::swap(driver.tree->types , $3); - std::swap(driver.tree->variables, $4); - std::swap(driver.tree->procedures, $5); - } -block: constant_part variable_part statement_part "end" - { - if ($3) - { - $$ = std::make_unique(std::move($1), std::move($2), std::move(*$3.release())); - } - else - { - $$ = std::make_unique(std::move($1), std::move($2)); - } - } -statement_part: - /* no statements */ {} - | "begin" required_statements { $$ = std::make_unique>(std::move($2));; } - | return_statement - { - $$ = std::make_unique>(std::vector{ $1 }); - } - | "begin" required_statements ";" return_statement - { - $$ = std::make_unique>(std::move($2)); - $$->push_back($4); - } -identifier_definition: - IDENTIFIER "*" { $$ = frontend::identifier_definition{ $1, true }; } - | IDENTIFIER { $$ = frontend::identifier_definition{ $1, false }; } -identifier_definitions: - identifier_definition "," identifier_definitions - { - std::swap($$, $3); - $$.emplace($$.cbegin(), $1); - } - | identifier_definition { $$.emplace_back(std::move($1)); } -return_declaration: - /* proper procedure */ {} - | "->" "!" { $$ = frontend::procedure_type_expression::return_t(std::monostate{}); } - | "->" type_expression { $$ = frontend::procedure_type_expression::return_t($2); } -procedure_heading: formal_parameter_list return_declaration - { - $$.second = new frontend::procedure_type_expression(frontend::make_position(@1), std::move($2)); - for (auto& [name, type] : $1) - { - $$.first.emplace_back(std::move(name)); - $$.second->parameters.push_back(type); - } - } -procedure_declaration: - "proc" identifier_definition procedure_heading block - { - $$ = new frontend::procedure_declaration(frontend::make_position(@1), std::move($2), $3.second, - std::move(*$4)); - std::swap($3.first, $$->parameter_names); - } - | "proc" identifier_definition procedure_heading "extern" - { - $$ = new frontend::procedure_declaration(frontend::make_position(@1), std::move($2), $3.second); - std::swap($3.first, $$->parameter_names); - } -procedure_part: - /* no procedure declarations */ {} - | procedure_declaration procedure_part - { - std::swap($$, $2); - $$.emplace($$.cbegin(), std::move($1)); - } -call_expression: designator_expression actual_parameter_list - { - $$ = new frontend::procedure_call(frontend::make_position(@1), $1); - std::swap($$->arguments, $2); - } -cast_expression: "cast" "(" expression ":" type_expression ")" - { $$ = new frontend::cast_expression(frontend::make_position(@1), $5, $3); } -elsif_do_statements: - "elsif" expression "do" optional_statements elsif_do_statements - { - frontend::conditional_statements *branch = new frontend::conditional_statements($2, std::move($4)); - std::swap($5, $$); - $$.emplace($$.begin(), branch); - } - | {} -else_statements: - "else" optional_statements { $$ = new std::vector(std::move($2)); } - | { $$ = nullptr; } -elsif_then_statements: - "elsif" expression "then" optional_statements elsif_then_statements - { - frontend::conditional_statements *branch = new frontend::conditional_statements($2, std::move($4)); - std::swap($5, $$); - $$.emplace($$.begin(), branch); - } - | {} -return_statement: "return" expression - { $$ = new frontend::return_statement(frontend::make_position(@1), $2); } -literal: - INTEGER { $$ = new frontend::literal(frontend::make_position(@1), $1); } - | WORD { $$ = new frontend::literal(frontend::make_position(@1), $1); } - | FLOAT { $$ = new frontend::literal(frontend::make_position(@1), $1); } - | BOOLEAN { $$ = new frontend::literal(frontend::make_position(@1), $1); } - | CHARACTER { $$ = new frontend::literal(frontend::make_position(@1), $1.at(0)); } - | "nil" { $$ = new frontend::literal(frontend::make_position(@1), nullptr); } - | STRING { $$ = new frontend::literal(frontend::make_position(@1), $1); } -traits_expression: - TRAIT "(" type_expressions ")" - { - $$ = new frontend::traits_expression(frontend::make_position(@1), $1); - std::swap($3, $$->parameters); - } -simple_expression: - literal { $$ = $1; } - | designator_expression { $$ = $1; } - | traits_expression { $$ = $1; } - | cast_expression { $$ = $1; } - | call_expression { $$ = $1; } - | "(" expression ")" { $$ = $2; } -operand: - unary_expression { $$ = $1; } - | simple_expression { $$ = $1; } -expression: - binary_expression { $$ = $1; } - | operand { $$ = $1; } -binary_expression: - expression "*" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::multiplication); - } - | expression "/" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::division); - } - | expression "%" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::remainder); - } - | expression "+" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::sum); - } - | expression "-" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::subtraction); - } - | expression "=" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::equals); - } - | expression "<>" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::not_equals); - } - | expression "<" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::less); - } - | expression ">" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::greater); - } - | expression "<=" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, - frontend::binary_operator::less_equal); - } - | expression ">=" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::greater_equal); - } - | expression "&" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::conjunction); - } - | expression "or" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::disjunction); - } - | expression "xor" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, - frontend::binary_operator::exclusive_disjunction); - } - | expression "<<" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::shift_left); - } - | expression ">>" expression - { - $$ = new frontend::binary_expression(frontend::make_position(@2), $1, $3, frontend::binary_operator::shift_right); - } -unary_expression: - "@" operand - { - $$ = new frontend::unary_expression(frontend::make_position(@1), $2, frontend::unary_operator::reference); - } - | "~" operand - { - $$ = new frontend::unary_expression(frontend::make_position(@1), $2, frontend::unary_operator::negation); - } - | "-" operand - { - $$ = new frontend::unary_expression(frontend::make_position(@1), $2, frontend::unary_operator::minus); - } -expressions: - expression "," expressions - { - std::swap($$, $3); - $$.emplace($$.cbegin(), $1); - } - | expression { $$.push_back($1); } -type_expressions: - type_expression "," type_expressions - { - std::swap($$, $3); - $$.emplace($$.cbegin(), $1); - } - | type_expression { $$.push_back($1); } -designator_expression: - simple_expression "[" expression "]" - { $$ = new frontend::array_access_expression(frontend::make_position(@2), $1, $3); } - | simple_expression "." IDENTIFIER - { $$ = new frontend::field_access_expression(frontend::make_position(@2), $1, $3); } - | simple_expression "^" - { $$ = new frontend::dereference_expression(frontend::make_position(@1), $1); } - | IDENTIFIER - { $$ = new frontend::named_expression(frontend::make_position(@1), $1); } -statement: - designator_expression ":=" expression - { $$ = new frontend::assign_statement(frontend::make_position(@1), $1, $3); } - | "while" expression "do" optional_statements elsif_do_statements "end" - { - frontend::conditional_statements *body = new frontend::conditional_statements($2, std::move($4)); - $$ = new frontend::while_statement(frontend::make_position(@1), body, std::move($5)); - } - | "if" expression "then" optional_statements elsif_then_statements else_statements "end" - { - frontend::conditional_statements *then = new frontend::conditional_statements($2, std::move($4)); - $$ = new frontend::if_statement(frontend::make_position(@1), then, std::move($5), $6); - } - | call_expression { $$ = $1; } - | "defer" optional_statements "end" - { $$ = new frontend::defer_statement(frontend::make_position(@1), std::move($2)); } - | "case" expression "of" switch_cases else_statements "end" - { $$ = new frontend::case_statement(frontend::make_position(@1), $2, std::move($4), $5); } -switch_case: case_labels ":" optional_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: - expression "," case_labels - { - std::swap($$, $3); - $$.emplace($$.cbegin(), $1); - } - | expression { $$.push_back($1); } -required_statements: - required_statements ";" statement - { - std::swap($$, $1); - $$.insert($$.cend(), $3); - } - | statement { $$.push_back($1); } -optional_statements: - required_statements { std::swap($$, $1); } - | /* no statements */ {} -field_declaration: - IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } -required_fields: - field_declaration ";" required_fields - { - std::swap($$, $3); - $$.emplace($$.cbegin(), $1); - } - | field_declaration { $$.emplace_back($1); } -optional_fields: - required_fields { std::swap($$, $1); } - | /* no fields */ {} -type_expression: - "[" INTEGER "]" type_expression - { - $$ = new frontend::array_type_expression(frontend::make_position(@1), $4, $2); - } - | "^" type_expression - { - $$ = new frontend::pointer_type_expression(frontend::make_position(@1), $2); - } - | "record" optional_fields "end" - { - $$ = new frontend::record_type_expression(frontend::make_position(@1), std::move($2)); - } - | "union" required_fields "end" - { - $$ = new frontend::union_type_expression(frontend::make_position(@1), std::move($2)); - } - | "proc" "(" type_expressions ")" return_declaration - { - auto result = new frontend::procedure_type_expression(frontend::make_position(@1), std::move($5)); - std::swap(result->parameters, $3); - $$ = result; - } - | "(" identifiers ")" - { - $$ = new frontend::enumeration_type_expression(frontend::make_position(@1), std::move($2)); - } - | IDENTIFIER - { - $$ = new frontend::named_expression(frontend::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 }; - $$ = new frontend::variable_declaration( frontend::make_position(@2), std::move($1), shared_type); - } - | identifier_definitions ":" type_expression ":=" "extern" - { - std::shared_ptr shared_type{ $3 }; - $$ = new frontend::variable_declaration( frontend::make_position(@2), std::move($1), shared_type, - std::monostate{}); - } - | identifier_definitions ":" type_expression ":=" expression - { - std::shared_ptr shared_type{ $3 }; - $$ = new frontend::variable_declaration( frontend::make_position(@2), std::move($1), shared_type, $5); - } -variable_declarations: - /* no variable declarations */ {} - | variable_declaration variable_declarations - { - std::swap($$, $2); - $$.insert(std::cbegin($$), $1); - } -variable_part: - /* no variable declarations */ {} - | "var" variable_declarations { std::swap($$, $2); } -constant_declaration: identifier_definition ":=" expression - { - $$ = new frontend::constant_declaration(frontend::make_position(@1), std::move($1), $3); - } -constant_declarations: - constant_declaration constant_declarations - { - std::swap($$, $2); - $$.insert(std::cbegin($$), $1); - } - | /* no constant definitions */ {} -constant_part: - /* no constant definitions */ {} - | "const" constant_declarations { std::swap($$, $2); } -import_declaration: - IDENTIFIER "." import_declaration - { - std::swap($$, $3); - $$.emplace($$.cbegin(), std::move($1)); - } - | IDENTIFIER { $$.emplace_back(std::move($1)); } -import_declarations: - import_declaration "," import_declarations - { - std::swap($$, $3); - $$.emplace($$.cbegin(), new frontend::import_declaration(frontend::make_position(@1), std::move($1))); - } - | import_declaration - { - $$.emplace_back(new frontend::import_declaration(frontend::make_position(@1), std::move($1))); - } -import_part: - /* no import declarations */ {} - | "import" import_declarations { std::swap($$, $2); } -type_declaration: identifier_definition "=" type_expression - { - $$ = new frontend::type_declaration(frontend::make_position(@1), std::move($1), $3); - } -type_declarations: - type_declaration type_declarations - { - std::swap($$, $2); - $$.insert($$.cbegin(), $1); - } - | /* no type definitions */ {} -type_part: - /* no type definitions */ {} - | "type" type_declarations { std::swap($$, $2); } -formal_parameter: - IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } -formal_parameter_list: - "(" ")" {} - | "(" formal_parameters ")" { std::swap($$, $2); } -formal_parameters: - formal_parameter "," formal_parameters - { - std::swap($$, $3); - $$.emplace($$.cbegin(), std::move($1)); - } - | formal_parameter { $$.emplace_back(std::move($1)); } -actual_parameter_list: - "(" ")" {} - | "(" expressions ")" { std::swap($$, $2); } -%% - -void yy::parser::error(const location_type& loc, const std::string& message) -{ - driver.add_error(message, driver.input_file, loc); -} diff --git a/frontend/result.cc b/frontend/result.cc deleted file mode 100644 index aca9c5e..0000000 --- a/frontend/result.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* Miscellaneous types used across stage boundaries. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "elna/frontend/result.h" - -namespace elna::frontend -{ - error::error(const char *path, const struct position position) - : position(position), path(path) - { - } - - std::size_t error::line() const noexcept - { - return this->position.line; - } - - std::size_t error::column() const noexcept - { - return this->position.column; - } - - error_container::error_container(const char *input_file) - : input_file(input_file) - { - } - - std::deque>& error_container::errors() - { - return m_errors; - } - - bool error_container::has_errors() const - { - return !m_errors.empty(); - } - - bool identifier_definition::operator==(const identifier_definition& that) const - { - return *this == that.name; - } - - bool identifier_definition::operator==(const std::string& that) const - { - return this->name == that; - } -} - -std::size_t std::hash::operator()( - const elna::frontend::identifier_definition& key) const -{ - return std::hash{}(key.name); -} diff --git a/frontend/semantic.cc b/frontend/semantic.cc deleted file mode 100644 index ee18492..0000000 --- a/frontend/semantic.cc +++ /dev/null @@ -1,682 +0,0 @@ -/* Name analysis. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "elna/frontend/semantic.h" - -#include -#include - -namespace elna::frontend -{ - undeclared_error::undeclared_error(const std::string& identifier, const char *path, const struct position position) - : error(path, position), identifier(identifier) - { - } - - std::string undeclared_error::what() const - { - return "Type '" + identifier + "' not declared"; - } - - already_declared_error::already_declared_error(const std::string& identifier, - const char *path, const struct position position) - : error(path, position), identifier(identifier) - { - } - - std::string already_declared_error::what() const - { - return "Symbol '" + identifier + "' has been already declared"; - } - - field_duplication_error::field_duplication_error(const std::string& field_name, - const char *path, const struct position position) - : error(path, position), field_name(field_name) - { - } - - std::string field_duplication_error::what() const - { - return "Repeated field name '" + field_name + "'"; - } - - cyclic_declaration_error::cyclic_declaration_error(const std::vector& cycle, - const char *path, const struct position position) - : error(path, position), cycle(cycle) - { - } - - std::string cyclic_declaration_error::what() const - { - auto segment = std::cbegin(this->cycle); - std::string message = "Type declaration forms a cycle: " + *segment; - - ++segment; - for (; segment != std::cend(this->cycle); ++segment) - { - message += " -> " + *segment; - } - return message; - } - - return_error::return_error(const std::string& identifier, const char *path, const struct position position) - : error(path, position), identifier(identifier) - { - } - - std::string return_error::what() const - { - return "Procedure '" + identifier + "' is expected to return, but does not have a return statement"; - } - - variable_initializer_error::variable_initializer_error(const char *path, const struct position position) - : error(path, position) - { - } - - std::string variable_initializer_error::what() const - { - return "Only one variable can be initialized"; - } - - type_analysis_visitor::type_analysis_visitor(const char *path, symbol_bag bag) - : error_container(path), bag(bag) - { - } - - void type_analysis_visitor::visit(program *program) - { - visit(static_cast(program)); - } - - void type_analysis_visitor::visit(procedure_declaration *definition) - { - if (definition->body.has_value() && definition->heading().return_type.proper_type != nullptr) - { - for (statement *const statement : definition->body.value().body()) - { - statement->accept(this); - } - if (!this->returns) - { - add_error(definition->identifier.name, this->input_file, definition->position()); - } - } - } - - void type_analysis_visitor::visit(assign_statement *) - { - } - - void type_analysis_visitor::visit(if_statement *) - { - } - - void type_analysis_visitor::visit(while_statement *) - { - } - - void type_analysis_visitor::visit(return_statement *) - { - this->returns = true; - } - - void type_analysis_visitor::visit(defer_statement *) - { - } - - void type_analysis_visitor::visit(case_statement *) - { - } - - void type_analysis_visitor::visit(procedure_call *) - { - } - - bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr alias, - std::vector& alias_path) - { - if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path)) - { - return false; - } - alias_path.push_back(alias->name); - - if (auto another_alias = alias->reference.get()) - { - return check_unresolved_symbol(another_alias, alias_path); - } - return true; - } - - void type_analysis_visitor::visit(unit *unit) - { - for (type_declaration *const type : unit->types) - { - type->accept(this); - } - for (procedure_declaration *const procedure : unit->procedures) - { - this->returns = false; - procedure->accept(this); - } - } - - void type_analysis_visitor::visit(type_declaration *definition) - { - std::vector alias_path; - auto unresolved_type = this->bag.lookup(definition->identifier.name)->is_type()->symbol.get(); - - if (!check_unresolved_symbol(unresolved_type, alias_path)) - { - add_error(alias_path, this->input_file, definition->position()); - } - } - - name_analysis_visitor::name_analysis_visitor(const char *path, symbol_bag bag) - : error_container(path), bag(bag) - { - } - - procedure_type name_analysis_visitor::build_procedure(procedure_type_expression& type_expression) - { - procedure_type::return_t result_return; - - if (type_expression.return_type.no_return) - { - result_return = procedure_type::return_t(std::monostate{}); - } - else if (type_expression.return_type.proper_type != nullptr) - { - type_expression.return_type.proper_type->accept(this); - result_return = procedure_type::return_t(this->current_type); - } - else - { - result_return = procedure_type::return_t(); - } - procedure_type result_type = procedure_type(result_return); - - for (struct type_expression *parameter : type_expression.parameters) - { - parameter->accept(this); - result_type.parameters.push_back(this->current_type); - } - return result_type; - } - - void name_analysis_visitor::visit(program *program) - { - visit(static_cast(program)); - - this->bag.enter(); - auto variable_type = this->bag.lookup("Int")->is_type()->symbol; - this->bag.enter("count", std::make_shared(variable_type, false)); - - variable_type = this->bag.lookup("Char")->is_type()->symbol; - variable_type = type(std::make_shared(variable_type)); - variable_type = type(std::make_shared(variable_type)); - this->bag.enter("parameters", std::make_shared(variable_type, false)); - - for (statement *const statement : program->body) - { - statement->accept(this); - } - this->bag.leave(); - } - - void name_analysis_visitor::visit(type_declaration *definition) - { - definition->body().accept(this); - auto resolved = this->bag.resolve(definition->identifier.name, this->current_type); - auto info = std::make_shared(type(resolved)); - - info->exported = definition->identifier.exported; - this->bag.enter(definition->identifier.name, info); - } - - void name_analysis_visitor::visit(type_expression *) - { - } - - void name_analysis_visitor::visit(pointer_type_expression *type_expression) - { - type_expression->base().accept(this); - this->current_type = type(std::make_shared(this->current_type)); - } - - void name_analysis_visitor::visit(array_type_expression *type_expression) - { - type_expression->base().accept(this); - auto result_type{ std::make_shared(this->current_type, type_expression->size) }; - - this->current_type = type(result_type); - } - - std::vector name_analysis_visitor::build_composite_type(const std::vector& fields) - { - std::vector result; - std::set field_names; - - for (auto& field : fields) - { - if (field_names.find(field.first) != field_names.cend()) - { - add_error(field.first, this->input_file, field.second->position()); - } - else - { - field_names.insert(field.first); - field.second->accept(this); - result.push_back(std::make_pair(field.first, this->current_type)); - } - } - return result; - } - - void name_analysis_visitor::visit(record_type_expression *type_expression) - { - auto result_type = std::make_shared(); - - result_type->fields = build_composite_type(type_expression->fields); - - this->current_type = type(result_type); - } - - void name_analysis_visitor::visit(union_type_expression *type_expression) - { - auto result_type = std::make_shared(); - - result_type->fields = build_composite_type(type_expression->fields); - - this->current_type = type(result_type); - } - - void name_analysis_visitor::visit(procedure_type_expression *type_expression) - { - std::shared_ptr result_type = - std::make_shared(std::move(build_procedure(*type_expression))); - - this->current_type = type(result_type); - } - - void name_analysis_visitor::visit(enumeration_type_expression *type_expression) - { - std::shared_ptr result_type = std::make_shared(type_expression->members); - - this->current_type = type(result_type); - } - - std::shared_ptr name_analysis_visitor::register_variable(const std::string& name, - const bool is_extern, const struct position position) - { - auto variable_symbol = std::make_shared(this->current_type, is_extern); - - if (!this->bag.enter(name, variable_symbol)) - { - add_error(name, this->input_file, position); - } - return variable_symbol; - } - - void name_analysis_visitor::visit(variable_declaration *declaration) - { - declaration->variable_type().accept(this); - - for (const auto& variable_identifier : declaration->identifiers) - { - auto variable_symbol = register_variable(variable_identifier.name, declaration->is_extern, - declaration->position()); - variable_symbol->exported = variable_identifier.exported; - } - } - - void name_analysis_visitor::visit(constant_declaration *definition) - { - definition->body().accept(this); - auto constant_symbol = std::make_shared(this->current_literal); - - constant_symbol->exported = definition->identifier.exported; - this->bag.enter(definition->identifier.name, constant_symbol); - } - - void name_analysis_visitor::visit(procedure_declaration *definition) - { - std::shared_ptr info; - auto heading = build_procedure(definition->heading()); - - if (definition->body.has_value()) - { - info = std::make_shared(heading, definition->parameter_names, this->bag.enter()); - auto name_iterator = std::cbegin(definition->parameter_names); - auto type_iterator = std::cbegin(heading.parameters); - - while (name_iterator != std::cend(definition->parameter_names) - && type_iterator != std::cend(heading.parameters)) - { - this->current_type = *type_iterator; - auto variable_symbol = register_variable(*name_iterator, false, definition->heading().position()); - variable_symbol->exported = false; - - ++name_iterator; - ++type_iterator; - } - for (constant_declaration *const constant : definition->body.value().constants()) - { - constant->accept(this); - } - for (variable_declaration *const variable : definition->body.value().variables()) - { - variable->accept(this); - } - for (statement *const statement : definition->body.value().body()) - { - statement->accept(this); - } - this->bag.leave(); - } - else - { - info = std::make_shared(heading, definition->parameter_names); - } - info->exported = definition->identifier.exported; - this->bag.enter(definition->identifier.name, info); - } - - void name_analysis_visitor::visit(assign_statement *statement) - { - statement->lvalue().accept(this); - statement->rvalue().accept(this); - } - - void name_analysis_visitor::visit(if_statement *statement) - { - statement->body().prerequisite().accept(this); - for (struct statement *const statement : statement->body().statements) - { - statement->accept(this); - } - for (const auto branch : statement->branches) - { - branch->prerequisite().accept(this); - - for (struct statement *const statement : branch->statements) - { - statement->accept(this); - } - } - if (statement->alternative != nullptr) - { - for (struct statement *const statement : *statement->alternative) - { - statement->accept(this); - } - } - } - - void name_analysis_visitor::visit(import_declaration *) - { - } - - void name_analysis_visitor::visit(while_statement *statement) - { - statement->body().prerequisite().accept(this); - for (struct statement *const statement : statement->body().statements) - { - statement->accept(this); - } - for (const auto branch : statement->branches) - { - branch->prerequisite().accept(this); - - for (struct statement *const statement : branch->statements) - { - statement->accept(this); - } - } - } - - void name_analysis_visitor::visit(return_statement *statement) - { - statement->return_expression().accept(this); - } - - void name_analysis_visitor::visit(defer_statement *statement) - { - for (struct statement *const statement : statement->statements) - { - statement->accept(this); - } - } - - void name_analysis_visitor::visit(case_statement *statement) - { - statement->condition().accept(this); - for (const switch_case& case_block : statement->cases) - { - for (expression *const case_label : case_block.labels) - { - case_label->accept(this); - } - for (struct statement *const statement : case_block.statements) - { - statement->accept(this); - } - } - if (statement->alternative != nullptr) - { - for (struct statement *const statement : *statement->alternative) - { - statement->accept(this); - } - } - } - - void name_analysis_visitor::visit(procedure_call *call) - { - call->callable().accept(this); - for (expression *const argument: call->arguments) - { - argument->accept(this); - } - } - - void name_analysis_visitor::visit(unit *unit) - { - for (type_declaration *const type : unit->types) - { - type->accept(this); - } - for (variable_declaration *const variable : unit->variables) - { - variable->accept(this); - } - for (constant_declaration *const constant : unit->constants) - { - constant->accept(this); - } - for (procedure_declaration *const procedure : unit->procedures) - { - procedure->accept(this); - } - } - - void name_analysis_visitor::visit(traits_expression *trait) - { - if (!trait->parameters.empty()) - { - trait->parameters.front()->accept(this); - trait->types.push_back(this->current_type); - } - } - - void name_analysis_visitor::visit(cast_expression *expression) - { - expression->value().accept(this); - expression->target().accept(this); - expression->expression_type = this->current_type; - } - - void name_analysis_visitor::visit(binary_expression *expression) - { - expression->lhs().accept(this); - expression->rhs().accept(this); - } - - void name_analysis_visitor::visit(unary_expression *expression) - { - expression->operand().accept(this); - } - - void name_analysis_visitor::visit(named_expression *type_expression) - { - auto unresolved_alias = this->bag.declared(type_expression->name); - - if (unresolved_alias != nullptr) - { - this->current_type = type(unresolved_alias); - } - else if (auto from_symbol_table = this->bag.lookup(type_expression->name)) - { - if (auto type_symbol = from_symbol_table->is_type()) - { - this->current_type = type_symbol->symbol; - } - } - else - { - add_error(type_expression->name, this->input_file, type_expression->position()); - this->current_type = type(); - } - } - - void name_analysis_visitor::visit(array_access_expression *expression) - { - expression->base().accept(this); - expression->index().accept(this); - } - - void name_analysis_visitor::visit(field_access_expression *expression) - { - expression->base().accept(this); - } - - void name_analysis_visitor::visit(dereference_expression *expression) - { - expression->base().accept(this); - } - - void name_analysis_visitor::visit(literal *literal) - { - this->current_literal = literal->value; - } - - void name_analysis_visitor::visit(literal *literal) - { - this->current_literal = literal->value; - } - - void name_analysis_visitor::visit(literal *literal) - { - this->current_literal = literal->value; - } - - void name_analysis_visitor::visit(literal *literal) - { - this->current_literal = literal->value; - } - - void name_analysis_visitor::visit(literal *literal) - { - this->current_literal = literal->value; - } - - void name_analysis_visitor::visit(literal *literal) - { - this->current_literal = literal->value; - } - - void name_analysis_visitor::visit(literal *literal) - { - this->current_literal = literal->value; - } - - declaration_visitor::declaration_visitor(const char *path) - : error_container(path) - { - } - - void declaration_visitor::visit(program *program) - { - visit(static_cast(program)); - } - - void declaration_visitor::visit(import_declaration *) - { - } - - void declaration_visitor::visit(unit *unit) - { - for (import_declaration *const _import : unit->imports) - { - _import->accept(this); - } - for (type_declaration *const type : unit->types) - { - type->accept(this); - } - for (variable_declaration *const variable : unit->variables) - { - variable->accept(this); - } - for (procedure_declaration *const procedure : unit->procedures) - { - procedure->accept(this); - } - } - - void declaration_visitor::visit(type_declaration *definition) - { - const std::string& type_identifier = definition->identifier.name; - - if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second) - { - add_error(definition->identifier.name, this->input_file, - definition->position()); - } - } - - void declaration_visitor::visit(variable_declaration *declaration) - { - if (declaration->has_initializer() && declaration->identifiers.size() > 1) - { - add_error(this->input_file, declaration->position()); - } - } - - void declaration_visitor::visit(procedure_declaration *definition) - { - if (!definition->body.has_value()) - { - return; - } - for (variable_declaration *const variable : definition->body.value().variables()) - { - variable->accept(this); - } - } -} diff --git a/frontend/symbol.cc b/frontend/symbol.cc deleted file mode 100644 index bfecbd4..0000000 --- a/frontend/symbol.cc +++ /dev/null @@ -1,427 +0,0 @@ -/* Symbol definitions. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "elna/frontend/symbol.h" - -namespace elna::frontend -{ - type::type() - { - } - - type::type(std::shared_ptr alias) - : tag(type_tag::alias), alias(alias) - { - } - - type::type(std::shared_ptr primitive) - : tag(type_tag::primitive), primitive(primitive) - { - } - - type::type(std::shared_ptr record) - : tag(type_tag::record), record(record) - { - } - - type::type(std::shared_ptr _union) - : tag(type_tag::_union), _union(_union) - { - } - - type::type(std::shared_ptr pointer) - : tag(type_tag::pointer), pointer(pointer) - { - } - - type::type(std::shared_ptr array) - : tag(type_tag::array), array(array) - { - } - - type::type(std::shared_ptr procedure) - : tag(type_tag::procedure), procedure(procedure) - { - } - - type::type(std::shared_ptr enumeration) - : tag(type_tag::enumeration), enumeration(enumeration) - { - } - - void type::copy(const type& other) - { - switch (other.tag) - { - case type_tag::empty: - break; - case type_tag::alias: - new (&alias) std::weak_ptr(other.alias); - break; - case type_tag::primitive: - new (&primitive) std::shared_ptr(other.primitive); - break; - case type_tag::record: - new (&record) std::shared_ptr(other.record); - break; - case type_tag::_union: - new (&_union) std::shared_ptr(other._union); - break; - case type_tag::pointer: - new (&pointer) std::shared_ptr(other.pointer); - break; - case type_tag::array: - new (&array) std::shared_ptr(other.array); - break; - case type_tag::procedure: - new (&procedure) std::shared_ptr(other.procedure); - break; - case type_tag::enumeration: - new (&enumeration) std::shared_ptr(other.enumeration); - break; - } - } - - type::type(const type& other) - : tag(other.tag) - { - copy(other); - } - - void type::move(type&& other) - { - switch (other.tag) - { - case type_tag::empty: - break; - case type_tag::alias: - new (&alias) std::weak_ptr(std::move(other.alias)); - break; - case type_tag::primitive: - new (&primitive) std::shared_ptr(std::move(other.primitive)); - break; - case type_tag::record: - new (&record) std::shared_ptr(std::move(other.record)); - break; - case type_tag::_union: - new (&_union) std::shared_ptr(std::move(other._union)); - break; - case type_tag::pointer: - new (&pointer) std::shared_ptr(std::move(other.pointer)); - break; - case type_tag::array: - new (&array) std::shared_ptr(std::move(other.array)); - break; - 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; - } - } - - type& type::operator=(const type& other) - { - this->~type(); - this->tag = other.tag; - copy(other); - return *this; - } - - type::type(type&& other) - : tag(other.tag) - { - move(std::move(other)); - } - - type& type::operator=(type&& other) - { - this->~type(); - this->tag = other.tag; - move(std::move(other)); - return *this; - } - - bool type::operator==(const std::nullptr_t&) - { - return empty(); - } - - type::~type() - { - switch (tag) - { - case type_tag::empty: - break; - case type_tag::alias: - this->alias.~weak_ptr(); - break; - case type_tag::primitive: - this->primitive.~shared_ptr(); - break; - case type_tag::record: - this->record.~shared_ptr(); - break; - case type_tag::_union: - this->_union.~shared_ptr(); - break; - case type_tag::pointer: - this->pointer.~shared_ptr(); - break; - case type_tag::array: - this->array.~shared_ptr(); - break; - case type_tag::procedure: - this->procedure.~shared_ptr(); - break; - case type_tag::enumeration: - this->enumeration.~shared_ptr(); - break; - } - } - - template<> - std::shared_ptr type::get() const - { - return tag == type_tag::alias ? this->alias.lock() : nullptr; - } - - template<> - std::shared_ptr type::get() const - { - return tag == type_tag::primitive ? this->primitive : nullptr; - } - - template<> - std::shared_ptr type::get() const - { - return tag == type_tag::record ? this->record : nullptr; - } - - template<> - std::shared_ptr type::get() const - { - return tag == type_tag::_union ? this->_union : nullptr; - } - - template<> - std::shared_ptr type::get() const - { - return tag == type_tag::pointer ? this->pointer : nullptr; - } - - template<> - std::shared_ptr type::get() const - { - return tag == type_tag::array ? this->array : nullptr; - } - - template<> - std::shared_ptr type::get() const - { - 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; - } - - alias_type::alias_type(const std::string& name) - : name(name), reference() - { - } - - pointer_type::pointer_type(type base) - : base(base) - { - } - - array_type::array_type(type base, std::uint64_t size) - : base(base), size(size) - { - } - - primitive_type::primitive_type(const std::string& identifier) - : identifier(identifier) - { - } - - procedure_type::procedure_type(return_t return_type) - : return_type(return_type) - { - } - - enumeration_type::enumeration_type(const std::vector& members) - : members(members) - { - } - - info::~info() - { - } - - std::shared_ptr info::is_type() - { - return nullptr; - } - - std::shared_ptr info::is_procedure() - { - return nullptr; - } - - std::shared_ptr info::is_constant() - { - return nullptr; - } - - std::shared_ptr info::is_variable() - { - return nullptr; - } - - type_info::type_info(const type symbol) - : symbol(symbol) - { - } - - std::shared_ptr type_info::is_type() - { - return std::static_pointer_cast(shared_from_this()); - } - - procedure_info::procedure_info(const procedure_type symbol, const std::vector names, - std::shared_ptr scope) - : symbol(symbol), names(names), scope(scope) - { - } - - std::shared_ptr procedure_info::is_procedure() - { - return std::static_pointer_cast(shared_from_this()); - } - - bool procedure_info::is_extern() const - { - return this->scope == nullptr; - } - - constant_info::constant_info(const variant& symbol) - : symbol(symbol) - { - } - - std::shared_ptr constant_info::is_constant() - { - return std::static_pointer_cast(shared_from_this()); - } - - variable_info::variable_info(const type symbol, bool is_extern) - : symbol(symbol), is_extern(is_extern) - { - } - - std::shared_ptr variable_info::is_variable() - { - return std::static_pointer_cast(shared_from_this()); - } - - std::shared_ptr builtin_symbol_table() - { - auto result = std::make_shared(); - - result->enter("Int", std::make_shared(type(std::make_shared("Int")))); - result->enter("Word", std::make_shared(type(std::make_shared("Word")))); - result->enter("Char", std::make_shared(type(std::make_shared("Char")))); - result->enter("Bool", std::make_shared(type(std::make_shared("Bool")))); - result->enter("Pointer", std::make_shared(type(std::make_shared("Pointer")))); - result->enter("Float", std::make_shared(type(std::make_shared("Float")))); - result->enter("String", std::make_shared(type(std::make_shared("String")))); - - return result; - } - - symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr global_table) - : unresolved(unresolved) - { - this->symbols = std::make_shared(global_table); - } - - std::shared_ptr symbol_bag::lookup(const std::string& name) - { - for (auto import_bag : this->imports) - { - if (auto result = import_bag->lookup(name)) - { - return result; - } - } - return this->symbols->lookup(name); - } - - bool symbol_bag::enter(const std::string& name, std::shared_ptr entry) - { - return this->symbols->enter(name, entry); - } - - std::shared_ptr symbol_bag::enter() - { - this->symbols = std::make_shared(this->symbols); - return this->symbols; - } - - void symbol_bag::enter(std::shared_ptr child) - { - this->symbols = child; - } - - std::shared_ptr symbol_bag::leave() - { - std::shared_ptr result = this->symbols; - - this->symbols = result->scope(); - return result; - } - - std::shared_ptr symbol_bag::declared(const std::string& symbol_name) - { - auto unresolved_alias = this->unresolved.find(symbol_name); - - return unresolved_alias == this->unresolved.end() ? std::shared_ptr() : unresolved_alias->second; - } - - std::shared_ptr symbol_bag::resolve(const std::string& symbol_name, type& resolution) - { - auto unresolved_declaration = this->unresolved.at(symbol_name); - - unresolved_declaration->reference = resolution; - return unresolved_declaration; - } - - void symbol_bag::add_import(const symbol_bag& bag) - { - this->imports.push_front(bag.symbols); - } -} diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in index e25fc6d..efc7687 100644 --- a/gcc/Make-lang.in +++ b/gcc/Make-lang.in @@ -150,7 +150,7 @@ elna.stagefeedback: stagefeedback-start ELNA_INCLUDES = -I $(srcdir)/elna/include -I elna/generated ELNA_CXXFLAGS = -std=c++17 -elna/%.o: elna/frontend/%.cc elna/generated/parser.hh elna/generated/location.hh +elna/%.o: elna/boot/%.cc elna/generated/parser.hh elna/generated/location.hh $(COMPILE) $(ELNA_CXXFLAGS) $(ELNA_INCLUDES) $< $(POSTCOMPILE) @@ -162,13 +162,13 @@ elna/%.o: elna/gcc/%.cc elna/generated/parser.hh elna/generated/location.hh $(COMPILE) $(ELNA_CXXFLAGS) $(ELNA_INCLUDES) $< $(POSTCOMPILE) -elna/generated/parser.cc: elna/frontend/parser.yy +elna/generated/parser.cc: elna/boot/parser.yy mkdir -p $(dir $@) $(BISON) -d -o $@ $< elna/generated/parser.hh elna/generated/location.hh: elna/generated/parser.cc @touch $@ -elna/generated/lexer.cc: elna/frontend/lexer.ll +elna/generated/lexer.cc: elna/boot/lexer.ll mkdir -p $(dir $@) $(FLEX) -o $@ $< diff --git a/gcc/elna-builtins.cc b/gcc/elna-builtins.cc index cf06df8..7c97027 100644 --- a/gcc/elna-builtins.cc +++ b/gcc/elna-builtins.cc @@ -64,23 +64,23 @@ namespace elna::gcc std::shared_ptr builtin_symbol_table() { - std::shared_ptr symbol_table = std::make_shared(); + auto builtin_table = std::make_shared(); - declare_builtin_type(symbol_table, "Int", elna_int_type_node); - declare_builtin_type(symbol_table, "Word", elna_word_type_node); - declare_builtin_type(symbol_table, "Char", elna_char_type_node); - declare_builtin_type(symbol_table, "Bool", elna_bool_type_node); - declare_builtin_type(symbol_table, "Pointer", elna_pointer_type_node); - declare_builtin_type(symbol_table, "Float", elna_float_type_node); + declare_builtin_type(builtin_table, "Int", elna_int_type_node); + declare_builtin_type(builtin_table, "Word", elna_word_type_node); + declare_builtin_type(builtin_table, "Char", elna_char_type_node); + declare_builtin_type(builtin_table, "Bool", elna_bool_type_node); + declare_builtin_type(builtin_table, "Pointer", elna_pointer_type_node); + declare_builtin_type(builtin_table, "Float", elna_float_type_node); - tree string_declaration = declare_builtin_type(symbol_table, "String", elna_string_type_node); + tree string_declaration = declare_builtin_type(builtin_table, "String", elna_string_type_node); TYPE_NAME(elna_string_type_node) = DECL_NAME(string_declaration); TYPE_STUB_DECL(elna_string_type_node) = string_declaration; - return symbol_table; + return builtin_table; } - tree build_composite_type(const std::vector& fields, tree composite_type_node, + tree build_composite_type(const std::vector& fields, tree composite_type_node, std::shared_ptr symbols) { for (auto& field : fields) @@ -94,7 +94,7 @@ namespace elna::gcc return composite_type_node; } - tree build_procedure_type(const frontend::procedure_type& procedure, std::shared_ptr symbols) + tree build_procedure_type(const boot::procedure_type& procedure, std::shared_ptr symbols) { std::vector parameter_types(procedure.parameters.size()); @@ -111,16 +111,16 @@ namespace elna::gcc return build_function_type_array(return_type, procedure.parameters.size(), parameter_types.data()); } - tree get_inner_alias(const frontend::type& type, std::shared_ptr symbols) + tree get_inner_alias(const boot::type& type, std::shared_ptr symbols) { - if (auto reference = type.get()) + if (auto reference = type.get()) { auto looked_up = symbols->lookup(reference->identifier); gcc_assert(looked_up != NULL_TREE); return TREE_TYPE(looked_up); } - else if (auto reference = type.get()) + else if (auto reference = type.get()) { tree composite_type_node = make_node(RECORD_TYPE); @@ -128,7 +128,7 @@ namespace elna::gcc return composite_type_node; } - else if (auto reference = type.get()) + else if (auto reference = type.get()) { tree composite_type_node = make_node(UNION_TYPE); @@ -136,34 +136,34 @@ namespace elna::gcc return composite_type_node; } - else if (auto reference = type.get()) + else if (auto reference = type.get()) { return build_enumeration_type(reference->members); } - else if (auto reference = type.get()) + else if (auto reference = type.get()) { return build_global_pointer_type(get_inner_alias(reference->base, symbols)); } - else if (auto reference = type.get()) + else if (auto reference = type.get()) { tree base = get_inner_alias(reference->base, symbols); return build_static_array_type(base, reference->size); } - else if (auto reference = type.get()) + else if (auto reference = type.get()) { auto procedure = build_procedure_type(*reference, symbols); return build_global_pointer_type(procedure); } - else if (auto reference = type.get()) + else if (auto reference = type.get()) { return TREE_TYPE(handle_symbol(reference->name, reference, symbols)); } return error_mark_node; } - tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, + tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, std::shared_ptr symbols) { tree looked_up = symbols->lookup(symbol_name); @@ -189,7 +189,7 @@ namespace elna::gcc return looked_up; } - void declare_procedure(const std::string& name, const frontend::procedure_info& info, + void declare_procedure(const std::string& name, const boot::procedure_info& info, std::shared_ptr symbols) { tree declaration_type = gcc::build_procedure_type(info.symbol, symbols); @@ -210,7 +210,7 @@ namespace elna::gcc std::vector::const_iterator parameter_name = info.names.cbegin(); - for (frontend::type parameter : info.symbol.parameters) + for (boot::type parameter : info.symbol.parameters) { tree declaration_tree = build_decl(UNKNOWN_LOCATION, PARM_DECL, get_identifier(parameter_name->c_str()), function_args_iter_cond(¶meter_type)); @@ -227,7 +227,7 @@ namespace elna::gcc TREE_PUBLIC(fndecl) = info.exported; } - tree declare_variable(const std::string& name, const frontend::variable_info& info, + tree declare_variable(const std::string& name, const boot::variable_info& info, std::shared_ptr symbols) { auto variable_type = get_inner_alias(info.symbol, symbols); @@ -242,10 +242,10 @@ namespace elna::gcc return declaration_tree; } - void declare_type(const std::string& name, const frontend::type_info& info, std::shared_ptr symbols) + void declare_type(const std::string& name, const boot::type_info& info, std::shared_ptr symbols) { // The top level symbol table has basic (builtin) types in it which are not aliases. - if (auto alias_type = info.symbol.get()) + if (auto alias_type = info.symbol.get()) { tree type_declaration = handle_symbol(name, alias_type, symbols); @@ -253,7 +253,7 @@ namespace elna::gcc } } - void rewrite_symbol_table(std::shared_ptr info_table, std::shared_ptr symbols) + void rewrite_symbol_table(std::shared_ptr info_table, std::shared_ptr symbols) { for (auto& [symbol_name, symbol_info] : *info_table) { diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index 162d6cb..fa32788 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -31,7 +31,7 @@ namespace elna::gcc linemap_add(line_table, LC_LEAVE, 0, NULL, 0); } - location_t get_location(const frontend::position *position) + location_t get_location(const boot::position *position) { linemap_line_start(line_table, position->line, 0); @@ -151,7 +151,7 @@ namespace elna::gcc gcc_unreachable(); } - void report_errors(const std::deque>& errors) + void report_errors(const std::deque>& errors) { for (const auto& error : errors) { @@ -159,7 +159,7 @@ namespace elna::gcc if (error->position.line != 0 || error->position.column != 0) { - gcc_location = elna::gcc::get_location(&error->position); + gcc_location = get_location(&error->position); } error_at(gcc_location, error->what().c_str()); } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index a5aa5f5..66bd9a2 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -35,13 +35,13 @@ along with GCC; see the file COPYING3. If not see namespace elna::gcc { - generic_visitor::generic_visitor(std::shared_ptr symbol_table, elna::frontend::symbol_bag bag) + generic_visitor::generic_visitor(std::shared_ptr symbol_table, boot::symbol_bag bag) : bag(bag), symbols(symbol_table) { } void generic_visitor::build_procedure_call(location_t call_location, - tree procedure_address, const std::vector& arguments) + tree procedure_address, const std::vector& arguments) { vec *argument_trees = nullptr; tree symbol_type = TREE_TYPE(TREE_TYPE(procedure_address)); @@ -49,7 +49,7 @@ namespace elna::gcc tree current_parameter = TYPE_ARG_TYPES(symbol_type); vec_alloc(argument_trees, arguments.size()); - for (frontend::expression *const argument : arguments) + for (boot::expression *const argument : arguments) { location_t argument_location = get_location(&argument->position()); if (VOID_TYPE_P(TREE_VALUE(current_parameter))) @@ -88,11 +88,11 @@ namespace elna::gcc } void generic_visitor::build_record_call(location_t call_location, - tree symbol, const std::vector& arguments) + tree symbol, const std::vector& arguments) { vec *tree_arguments = nullptr; tree record_fields = TYPE_FIELDS(symbol); - for (frontend::expression *const argument : arguments) + for (boot::expression *const argument : arguments) { location_t argument_location = get_location(&argument->position()); @@ -129,7 +129,7 @@ namespace elna::gcc } void generic_visitor::build_assert_builtin(location_t call_location, - const std::vector& arguments) + const std::vector& arguments) { if (arguments.size() != 1) { @@ -165,11 +165,11 @@ namespace elna::gcc } } - bool generic_visitor::build_builtin_procedures(frontend::procedure_call *call) + bool generic_visitor::build_builtin_procedures(boot::procedure_call *call) { location_t call_location = get_location(&call->position()); - if (frontend::named_expression *named_call = call->callable().is_named()) + if (boot::named_expression *named_call = call->callable().is_named()) { if (named_call->name == "assert") { @@ -180,7 +180,7 @@ namespace elna::gcc return false; } - void generic_visitor::visit(frontend::procedure_call *call) + void generic_visitor::visit(boot::procedure_call *call) { if (build_builtin_procedures(call)) { @@ -215,7 +215,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::cast_expression *expression) + void generic_visitor::visit(boot::cast_expression *expression) { tree cast_target = get_inner_alias(expression->expression_type, this->symbols->scope()); @@ -235,9 +235,9 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::program *program) + void generic_visitor::visit(boot::program *program) { - visit(static_cast(program)); + visit(static_cast(program)); tree declaration_type = build_function_type_list(elna_int_type_node, elna_int_type_node, @@ -285,27 +285,27 @@ namespace elna::gcc cgraph_node::finalize_function(fndecl, true); } - void generic_visitor::visit(frontend::unit *unit) + void generic_visitor::visit(boot::unit *unit) { - for (frontend::import_declaration *const declaration : unit->imports) + for (boot::import_declaration *const declaration : unit->imports) { declaration->accept(this); } - for (frontend::constant_declaration *const constant : unit->constants) + for (boot::constant_declaration *const constant : unit->constants) { constant->accept(this); } - for (frontend::variable_declaration *const variable : unit->variables) + for (boot::variable_declaration *const variable : unit->variables) { variable->accept(this); } - for (frontend::procedure_declaration *const procedure : unit->procedures) + for (boot::procedure_declaration *const procedure : unit->procedures) { procedure->accept(this); } } - void generic_visitor::visit(frontend::procedure_declaration *definition) + void generic_visitor::visit(boot::procedure_declaration *definition) { tree fndecl = this->symbols->lookup(definition->identifier.name); @@ -324,11 +324,11 @@ namespace elna::gcc { this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain); } - for (frontend::constant_declaration *const constant : definition->body.value().constants()) + for (boot::constant_declaration *const constant : definition->body.value().constants()) { constant->accept(this); } - for (frontend::variable_declaration *const variable : definition->body.value().variables()) + for (boot::variable_declaration *const variable : definition->body.value().variables()) { variable->accept(this); } @@ -381,17 +381,17 @@ namespace elna::gcc return bind_expr; } - void generic_visitor::visit(frontend::literal *literal) + void generic_visitor::visit(boot::literal *literal) { this->current_expression = build_int_cst(elna_int_type_node, literal->value); } - void generic_visitor::visit(frontend::literal *literal) + void generic_visitor::visit(boot::literal *literal) { this->current_expression = build_int_cstu(elna_word_type_node, literal->value); } - void generic_visitor::visit(frontend::literal *literal) + void generic_visitor::visit(boot::literal *literal) { REAL_VALUE_TYPE real_value1; @@ -406,22 +406,22 @@ namespace elna::gcc mpfr_clear(number); } - void generic_visitor::visit(frontend::literal *boolean) + void generic_visitor::visit(boot::literal *boolean) { this->current_expression = boolean->value ? boolean_true_node : boolean_false_node; } - void generic_visitor::visit(frontend::literal *character) + void generic_visitor::visit(boot::literal *character) { this->current_expression = build_int_cstu(elna_char_type_node, character->value); } - void generic_visitor::visit(frontend::literal *) + void generic_visitor::visit(boot::literal *) { this->current_expression = elna_pointer_nil_node; } - void generic_visitor::visit(frontend::literal *string) + void generic_visitor::visit(boot::literal *string) { tree index_constant = build_int_cstu(elna_word_type_node, string->value.size()); tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant)); @@ -444,38 +444,38 @@ namespace elna::gcc this->current_expression = build_constructor(elna_string_type_node, elms); } - tree generic_visitor::build_arithmetic_operation(frontend::binary_expression *expression, + tree generic_visitor::build_arithmetic_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right) { return build_binary_operation(is_numeric_type(TREE_TYPE(left)), expression, operator_code, left, right, TREE_TYPE(left)); } - tree generic_visitor::build_comparison_operation(frontend::binary_expression *expression, + 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)) || POINTER_TYPE_P(TREE_TYPE(left)), expression, operator_code, left, right, elna_bool_type_node); } - tree generic_visitor::build_bit_logic_operation(frontend::binary_expression *expression, tree left, tree right) + tree generic_visitor::build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right) { location_t expression_location = get_location(&expression->position()); tree left_type = TREE_TYPE(left); tree right_type = TREE_TYPE(right); tree_code logical_code, bit_code; - if (expression->operation() == frontend::binary_operator::conjunction) + if (expression->operation() == boot::binary_operator::conjunction) { bit_code = BIT_AND_EXPR; logical_code = TRUTH_ANDIF_EXPR; } - else if (expression->operation() == frontend::binary_operator::disjunction) + else if (expression->operation() == boot::binary_operator::disjunction) { bit_code = BIT_IOR_EXPR; logical_code = TRUTH_ORIF_EXPR; } - else if (expression->operation() == frontend::binary_operator::exclusive_disjunction) + else if (expression->operation() == boot::binary_operator::exclusive_disjunction) { bit_code = BIT_XOR_EXPR; logical_code = TRUTH_XOR_EXPR; @@ -496,22 +496,22 @@ namespace elna::gcc { error_at(expression_location, "Invalid operands of type '%s' and '%s' for operator %s", print_type(left_type).c_str(), print_type(right_type).c_str(), - elna::frontend::print_binary_operator(expression->operation())); + boot::print_binary_operator(expression->operation())); return error_mark_node; } } - tree generic_visitor::build_equality_operation(frontend::binary_expression *expression, tree left, tree right) + tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right) { location_t expression_location = get_location(&expression->position()); tree_code equality_code, combination_code; - if (expression->operation() == frontend::binary_operator::equals) + if (expression->operation() == boot::binary_operator::equals) { equality_code = EQ_EXPR; combination_code = TRUTH_ANDIF_EXPR; } - else if (expression->operation() == frontend::binary_operator::not_equals) + else if (expression->operation() == boot::binary_operator::not_equals) { equality_code = NE_EXPR; combination_code = TRUTH_ORIF_EXPR; @@ -545,7 +545,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::binary_expression *expression) + void generic_visitor::visit(boot::binary_expression *expression) { expression->lhs().accept(this); tree left = this->current_expression; @@ -558,8 +558,8 @@ namespace elna::gcc location_t expression_location = get_location(&expression->position()); if ((POINTER_TYPE_P(left_type) || POINTER_TYPE_P(right_type)) - && (expression->operation() == frontend::binary_operator::sum - || expression->operation() == frontend::binary_operator::subtraction)) + && (expression->operation() == boot::binary_operator::sum + || expression->operation() == boot::binary_operator::subtraction)) { this->current_expression = do_pointer_arithmetic(expression->operation(), left, right, expression_location); @@ -567,7 +567,7 @@ namespace elna::gcc { error_at(expression_location, "invalid operation %s on a pointer and an integral type", - frontend::print_binary_operator(expression->operation())); + boot::print_binary_operator(expression->operation())); } else if (TREE_TYPE(this->current_expression) == ssizetype) { @@ -583,60 +583,60 @@ namespace elna::gcc error_at(expression_location, "invalid operands of type '%s' and '%s' for operator %s", print_type(left_type).c_str(), print_type(right_type).c_str(), - frontend::print_binary_operator(expression->operation())); + boot::print_binary_operator(expression->operation())); this->current_expression = error_mark_node; return; } switch (expression->operation()) { - case frontend::binary_operator::sum: + case boot::binary_operator::sum: this->current_expression = build_arithmetic_operation(expression, PLUS_EXPR, left, right); break; - case frontend::binary_operator::subtraction: + case boot::binary_operator::subtraction: this->current_expression = build_arithmetic_operation(expression, MINUS_EXPR, left, right); break; - case frontend::binary_operator::division: + case boot::binary_operator::division: this->current_expression = build_arithmetic_operation(expression, TRUNC_DIV_EXPR, left, right); break; - case frontend::binary_operator::remainder: + case boot::binary_operator::remainder: this->current_expression = build_arithmetic_operation(expression, TRUNC_MOD_EXPR, left, right); break; - case frontend::binary_operator::multiplication: + case boot::binary_operator::multiplication: this->current_expression = build_arithmetic_operation(expression, MULT_EXPR, left, right); break; - case frontend::binary_operator::less: + case boot::binary_operator::less: this->current_expression = build_comparison_operation(expression, LT_EXPR, left, right); break; - case frontend::binary_operator::greater: + case boot::binary_operator::greater: this->current_expression = build_comparison_operation(expression, GT_EXPR, left, right); break; - case frontend::binary_operator::less_equal: + case boot::binary_operator::less_equal: this->current_expression = build_comparison_operation(expression, LE_EXPR, left, right); break; - case frontend::binary_operator::greater_equal: + case boot::binary_operator::greater_equal: this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right); break; - case frontend::binary_operator::conjunction: + case boot::binary_operator::conjunction: this->current_expression = build_bit_logic_operation(expression, left, right); break; - case frontend::binary_operator::disjunction: + case boot::binary_operator::disjunction: this->current_expression = build_bit_logic_operation(expression, left, right); break; - case frontend::binary_operator::exclusive_disjunction: + case boot::binary_operator::exclusive_disjunction: this->current_expression = build_bit_logic_operation(expression, left, right); break; - case frontend::binary_operator::equals: + case boot::binary_operator::equals: this->current_expression = build_equality_operation(expression, left, right); break; - case frontend::binary_operator::not_equals: + case boot::binary_operator::not_equals: this->current_expression = build_equality_operation(expression, left, right); break; - case frontend::binary_operator::shift_left: + case boot::binary_operator::shift_left: this->current_expression = build_binary_operation( is_numeric_type(left_type) && right_type == elna_word_type_node, expression, LSHIFT_EXPR, left, right, left_type); break; - case frontend::binary_operator::shift_right: + case boot::binary_operator::shift_right: this->current_expression = build_binary_operation( is_numeric_type(left_type) && right_type == elna_word_type_node, expression, RSHIFT_EXPR, left, right, left_type); @@ -644,14 +644,14 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::unary_expression *expression) + void generic_visitor::visit(boot::unary_expression *expression) { expression->operand().accept(this); location_t location = get_location(&expression->position()); switch (expression->operation()) { - case frontend::unary_operator::reference: + case boot::unary_operator::reference: this->current_expression = prepare_rvalue(this->current_expression); TREE_ADDRESSABLE(this->current_expression) = 1; this->current_expression = build_fold_addr_expr_with_type_loc(location, @@ -659,7 +659,7 @@ namespace elna::gcc build_global_pointer_type(TREE_TYPE(this->current_expression))); TREE_NO_TRAMPOLINE(this->current_expression) = 1; break; - case frontend::unary_operator::negation: + case boot::unary_operator::negation: if (TREE_TYPE(this->current_expression) == elna_bool_type_node) { this->current_expression = build1_loc(location, TRUTH_NOT_EXPR, @@ -677,7 +677,7 @@ namespace elna::gcc this->current_expression = error_mark_node; } break; - case frontend::unary_operator::minus: + case boot::unary_operator::minus: if (is_integral_type(TREE_TYPE(this->current_expression))) { this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression), @@ -692,7 +692,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::constant_declaration *definition) + void generic_visitor::visit(boot::constant_declaration *definition) { location_t definition_location = get_location(&definition->position()); definition->body().accept(this); @@ -732,7 +732,7 @@ namespace elna::gcc this->current_expression = NULL_TREE; } - void generic_visitor::visit(frontend::variable_declaration *declaration) + void generic_visitor::visit(boot::variable_declaration *declaration) { for (const auto& variable_identifier : declaration->identifiers) { @@ -784,7 +784,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::named_expression *expression) + void generic_visitor::visit(boot::named_expression *expression) { auto symbol = this->symbols->lookup(expression->name); @@ -800,7 +800,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::array_access_expression *expression) + void generic_visitor::visit(boot::array_access_expression *expression) { expression->base().accept(this); tree designator = this->current_expression; @@ -829,7 +829,7 @@ namespace elna::gcc tree string_ptr = build3_loc(location, COMPONENT_REF, TREE_TYPE(elna_string_ptr_field_node), designator, elna_string_ptr_field_node, NULL_TREE); - tree target_pointer = do_pointer_arithmetic(frontend::binary_operator::sum, string_ptr, offset, location); + tree target_pointer = do_pointer_arithmetic(boot::binary_operator::sum, string_ptr, offset, location); this->current_expression = build1_loc(location, INDIRECT_REF, elna_char_type_node, target_pointer); @@ -842,7 +842,7 @@ namespace elna::gcc } } - bool generic_visitor::expect_trait_type_only(frontend::traits_expression *trait) + bool generic_visitor::expect_trait_type_only(boot::traits_expression *trait) { if (trait->parameters.size() != 1) { @@ -856,7 +856,7 @@ namespace elna::gcc return this->current_expression != error_mark_node; } - bool generic_visitor::expect_trait_for_integral_type(frontend::traits_expression *trait) + bool generic_visitor::expect_trait_for_integral_type(boot::traits_expression *trait) { if (!expect_trait_type_only(trait)) { @@ -872,7 +872,7 @@ namespace elna::gcc return true; } - void generic_visitor::visit(frontend::traits_expression *trait) + void generic_visitor::visit(boot::traits_expression *trait) { location_t trait_location = get_location(&trait->position()); @@ -945,7 +945,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::field_access_expression *expression) + void generic_visitor::visit(boot::field_access_expression *expression) { expression->base().accept(this); location_t expression_location = get_location(&expression->position()); @@ -991,7 +991,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::dereference_expression *expression) + void generic_visitor::visit(boot::dereference_expression *expression) { expression->base().accept(this); location_t expression_location = get_location(&expression->position()); @@ -1010,7 +1010,7 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::assign_statement *statement) + void generic_visitor::visit(boot::assign_statement *statement) { statement->lvalue().accept(this); @@ -1045,7 +1045,7 @@ namespace elna::gcc this->current_expression = NULL_TREE; } - void generic_visitor::visit(frontend::if_statement *statement) + void generic_visitor::visit(boot::if_statement *statement) { tree endif_label_decl = create_artificial_label(UNKNOWN_LOCATION); tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl); @@ -1068,7 +1068,7 @@ namespace elna::gcc this->current_expression = NULL_TREE; } - void generic_visitor::make_if_branch(frontend::conditional_statements& branch, tree goto_endif) + void generic_visitor::make_if_branch(boot::conditional_statements& branch, tree goto_endif) { branch.prerequisite().accept(this); @@ -1102,11 +1102,11 @@ namespace elna::gcc append_statement(else_label_expr); } - void generic_visitor::visit(frontend::import_declaration *) + void generic_visitor::visit(boot::import_declaration *) { } - void generic_visitor::visit(frontend::while_statement *statement) + void generic_visitor::visit(boot::while_statement *statement) { location_t prerequisite_location = get_location(&statement->body().prerequisite().position()); tree prerequisite_label_decl = build_label_decl("while_do", prerequisite_location); @@ -1127,9 +1127,9 @@ namespace elna::gcc this->current_expression = NULL_TREE; } - void generic_visitor::visit_statements(const std::vector& statements) + void generic_visitor::visit_statements(const std::vector& statements) { - for (frontend::statement *const statement : statements) + for (boot::statement *const statement : statements) { statement->accept(this); @@ -1141,9 +1141,9 @@ namespace elna::gcc } } - void generic_visitor::visit(frontend::return_statement *statement) + void generic_visitor::visit(boot::return_statement *statement) { - frontend::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)); @@ -1183,14 +1183,14 @@ namespace elna::gcc this->current_expression = NULL_TREE; } - void generic_visitor::visit(frontend::defer_statement *statement) + void generic_visitor::visit(boot::defer_statement *statement) { enter_scope(); visit_statements(statement->statements); defer(leave_scope()); } - void generic_visitor::visit(frontend::case_statement *statement) + void generic_visitor::visit(boot::case_statement *statement) { statement->condition().accept(this); tree condition_expression = this->current_expression; @@ -1207,9 +1207,9 @@ namespace elna::gcc tree end_label_declaration = create_artificial_label(get_location(&statement->position())); tree switch_statements = alloc_stmt_list(); - for (const frontend::switch_case& case_block : statement->cases) + for (const boot::switch_case& case_block : statement->cases) { - for (frontend::expression *const case_label : case_block.labels) + for (boot::expression *const case_label : case_block.labels) { case_label->accept(this); location_t case_location = get_location(&case_label->position()); diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 93f796b..de7f6b0 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -128,12 +128,12 @@ namespace elna::gcc return field_declaration; } - tree do_pointer_arithmetic(frontend::binary_operator binary_operator, + tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right, location_t operation_location) { tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED); tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED); - if (binary_operator == frontend::binary_operator::sum) + if (binary_operator == boot::binary_operator::sum) { tree pointer{ NULL_TREE }; tree offset{ NULL_TREE }; @@ -164,7 +164,7 @@ namespace elna::gcc return fold_build2_loc(operation_location, POINTER_PLUS_EXPR, TREE_TYPE(pointer), pointer, offset); } - else if (binary_operator == frontend::binary_operator::subtraction) + else if (binary_operator == boot::binary_operator::subtraction) { if (POINTER_TYPE_P(left_type) && is_integral_type(right_type)) { @@ -186,7 +186,7 @@ namespace elna::gcc gcc_unreachable(); } - tree build_binary_operation(bool condition, frontend::binary_expression *expression, + tree build_binary_operation(bool condition, boot::binary_expression *expression, tree_code operator_code, tree left, tree right, tree target_type) { location_t expression_location = get_location(&expression->position()); @@ -202,7 +202,7 @@ namespace elna::gcc error_at(expression_location, "invalid operands of type '%s' and '%s' for operator %s", print_type(left_type).c_str(), print_type(right_type).c_str(), - elna::frontend::print_binary_operator(expression->operation())); + boot::print_binary_operator(expression->operation())); return error_mark_node; } } diff --git a/gcc/elna1.cc b/gcc/elna1.cc index 448a24c..0333f70 100644 --- a/gcc/elna1.cc +++ b/gcc/elna1.cc @@ -29,7 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks-def.h" #include -#include "elna/frontend/dependency.h" +#include "elna/boot/dependency.h" #include "elna/gcc/elna-tree.h" #include "elna/gcc/elna-generic.h" #include "elna/gcc/elna-diagnostic.h" @@ -62,9 +62,9 @@ static bool elna_langhook_init(void) return true; } -using dependency_state = elna::frontend::dependency_state>; +using dependency_state = elna::boot::dependency_state>; -static elna::frontend::dependency elna_parse_file(dependency_state& state, const char *filename) +static elna::boot::dependency elna_parse_file(dependency_state& state, const char *filename) { std::ifstream entry_point{ filename, std::ios::in }; @@ -73,19 +73,19 @@ static elna::frontend::dependency elna_parse_file(dependency_state& state, const fatal_error(UNKNOWN_LOCATION, "Cannot open filename %s: %m", filename); } elna::gcc::linemap_guard{ filename }; - elna::frontend::dependency outcome = elna::frontend::read_source(entry_point, filename); + elna::boot::dependency outcome = elna::boot::read_source(entry_point, filename); if (outcome.has_errors()) { elna::gcc::report_errors(outcome.errors()); return outcome; } - elna::frontend::symbol_bag outcome_bag = elna::frontend::symbol_bag{ std::move(outcome.unresolved), state.globals }; + elna::boot::symbol_bag outcome_bag = elna::boot::symbol_bag{ std::move(outcome.unresolved), state.globals }; for (const auto& sub_tree : outcome.tree->imports) { - std::filesystem::path sub_path = "source" / elna::frontend::build_path(sub_tree->segments); - std::unordered_map::const_iterator cached_import = + std::filesystem::path sub_path = "source" / elna::boot::build_path(sub_tree->segments); + std::unordered_map::const_iterator cached_import = state.cache.find(sub_path); if (cached_import == state.cache.end()) @@ -114,7 +114,7 @@ static void elna_langhook_parse_file(void) for (unsigned int i = 0; i < num_in_fnames; i++) { - elna::frontend::dependency outcome = elna_parse_file(state, in_fnames[i]); + elna::boot::dependency outcome = elna_parse_file(state, in_fnames[i]); linemap_add(line_table, LC_ENTER, 0, in_fnames[i], 1); elna::gcc::generic_visitor generic_visitor{ state.custom, state.cache.find(in_fnames[i])->second }; diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h new file mode 100644 index 0000000..7d94e84 --- /dev/null +++ b/include/elna/boot/ast.h @@ -0,0 +1,800 @@ +/* Abstract syntax tree representation. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include +#include +#include +#include +#include "elna/boot/symbol.h" +#include "elna/boot/result.h" + +namespace elna::boot +{ + enum class binary_operator + { + sum, + subtraction, + multiplication, + division, + remainder, + equals, + not_equals, + less, + greater, + less_equal, + greater_equal, + disjunction, + conjunction, + exclusive_disjunction, + shift_left, + shift_right + }; + + enum class unary_operator + { + reference, + negation, + minus + }; + + class variable_declaration; + class constant_declaration; + class procedure_declaration; + class type_declaration; + class procedure_call; + class cast_expression; + class assign_statement; + class if_statement; + class import_declaration; + class while_statement; + class return_statement; + class case_statement; + class traits_expression; + class unit; + class program; + class binary_expression; + class unary_expression; + class 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 named_expression; + class array_access_expression; + class field_access_expression; + class dereference_expression; + class designator_expression; + class literal_expression; + template + class literal; + class defer_statement; + + /** + * Interface for AST visitors. + */ + struct parser_visitor + { + virtual void visit(variable_declaration *) = 0; + virtual void visit(constant_declaration *) = 0; + virtual void visit(procedure_declaration *) = 0; + virtual void visit(type_declaration *) = 0; + virtual void visit(procedure_call *) = 0; + virtual void visit(cast_expression *) = 0; + virtual void visit(traits_expression *) = 0; + virtual void visit(assign_statement *) = 0; + virtual void visit(if_statement *) = 0; + virtual void visit(import_declaration *) = 0; + 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(unit *) = 0; + virtual void visit(program *) = 0; + virtual void visit(binary_expression *) = 0; + virtual void visit(unary_expression *) = 0; + virtual void visit(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(named_expression *) = 0; + virtual void visit(array_access_expression *) = 0; + virtual void visit(field_access_expression *) = 0; + virtual void visit(dereference_expression *) = 0; + virtual void visit(literal *) = 0; + virtual void visit(literal *) = 0; + virtual void visit(literal *) = 0; + virtual void visit(literal *) = 0; + virtual void visit(literal *) = 0; + virtual void visit(literal *) = 0; + virtual void visit(literal *) = 0; + }; + + /** + * Abstract visitor that doesn't visit any nodes by default. + */ + class empty_visitor : public parser_visitor + { + [[noreturn]] void not_implemented(); + + public: + [[noreturn]] virtual void visit(type_expression *) override; + [[noreturn]] virtual void visit(array_type_expression *) override; + [[noreturn]] virtual void visit(pointer_type_expression *) override; + [[noreturn]] virtual void visit(program *) override; + [[noreturn]] virtual void visit(type_declaration *) override; + [[noreturn]] virtual void visit(record_type_expression *) override; + [[noreturn]] virtual void visit(union_type_expression *) override; + [[noreturn]] virtual void visit(procedure_type_expression *) override; + [[noreturn]] virtual void visit(enumeration_type_expression *) override; + + [[noreturn]] virtual void visit(variable_declaration *) override; + [[noreturn]] virtual void visit(constant_declaration *) override; + [[noreturn]] virtual void visit(procedure_declaration *) override; + [[noreturn]] virtual void visit(assign_statement *) override; + [[noreturn]] virtual void visit(if_statement *) override; + [[noreturn]] virtual void visit(import_declaration *) override; + [[noreturn]] virtual void visit(while_statement *) override; + [[noreturn]] virtual void visit(return_statement *) override; + [[noreturn]] virtual void visit(defer_statement *) override; + [[noreturn]] virtual void visit(case_statement *) override; + [[noreturn]] virtual void visit(procedure_call *) override; + [[noreturn]] virtual void visit(unit *) override; + [[noreturn]] virtual void visit(cast_expression *) override; + [[noreturn]] virtual void visit(traits_expression *) override; + [[noreturn]] virtual void visit(binary_expression *) override; + [[noreturn]] virtual void visit(unary_expression *) override; + [[noreturn]] virtual void visit(named_expression *) override; + [[noreturn]] virtual void visit(array_access_expression *) override; + [[noreturn]] virtual void visit(field_access_expression *) override; + [[noreturn]] virtual void visit(dereference_expression *) override; + [[noreturn]] virtual void visit(literal *) override; + [[noreturn]] virtual void visit(literal *) override; + [[noreturn]] virtual void visit(literal *) override; + [[noreturn]] virtual void visit(literal *) override; + [[noreturn]] virtual void visit(literal *) override; + [[noreturn]] virtual void visit(literal *) override; + [[noreturn]] virtual void visit(literal *) override; + }; + + /** + * AST node. + */ + class node + { + const struct position source_position; + + protected: + /** + * \param position Source code position. + */ + explicit node(const position position); + + public: + virtual void accept(parser_visitor *visitor) = 0; + virtual ~node() = 0; + + /** + * \return Node position in the source code. + */ + const struct position& position() const; + }; + + class statement : public virtual node + { + }; + + class expression : public virtual node + { + public: + virtual cast_expression *is_cast(); + virtual traits_expression *is_traits(); + virtual binary_expression *is_binary(); + virtual unary_expression *is_unary(); + virtual designator_expression *is_designator(); + virtual procedure_call *is_call_expression(); + virtual literal_expression *is_literal(); + }; + + /** + * Symbol definition. + */ + class declaration : public node + { + protected: + declaration(const struct position position, identifier_definition identifier); + + public: + const identifier_definition identifier; + }; + + /** + * Some type expression. + */ + class type_expression : public virtual node + { + public: + virtual named_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(); + + void accept(parser_visitor *visitor) override; + ~type_expression() = 0; + }; + + class array_type_expression : public type_expression + { + type_expression *m_base; + + public: + const std::uint32_t size; + + array_type_expression(const struct position position, + type_expression *base, const std::uint32_t size); + ~array_type_expression(); + + void accept(parser_visitor *visitor) override; + array_type_expression *is_array() override; + + type_expression& base(); + }; + + class pointer_type_expression : public type_expression + { + type_expression *m_base; + + public: + pointer_type_expression(const struct position position, type_expression *base); + ~pointer_type_expression(); + + void accept(parser_visitor *visitor) override; + pointer_type_expression *is_pointer() override; + + type_expression& base(); + }; + + using field_declaration = std::pair; + + class record_type_expression : public type_expression + { + public: + const std::vector fields; + + record_type_expression(const struct position position, std::vector&& fields); + ~record_type_expression(); + + void accept(parser_visitor *visitor) override; + record_type_expression *is_record() override; + }; + + class union_type_expression : public type_expression + { + public: + std::vector fields; + + union_type_expression(const struct position position, std::vector&& fields); + ~union_type_expression(); + + void accept(parser_visitor *visitor) override; + 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. + */ + class variable_declaration : public node + { + std::shared_ptr m_variable_type; + + public: + variable_declaration(const struct position position, + std::vector&& identifier, std::shared_ptr variable_type, + expression *body = nullptr); + variable_declaration(const struct position position, + std::vector&& identifier, std::shared_ptr variable_type, + std::monostate); + + void accept(parser_visitor *visitor) override; + + bool has_initializer() const; + + const std::vector identifiers; + type_expression& variable_type(); + expression *const body{ nullptr }; + const bool is_extern{ false }; + }; + + /** + * Literal expression. + */ + class literal_expression : public expression + { + public: + literal_expression *is_literal() override; + }; + + /** + * Constant definition. + */ + class constant_declaration : public declaration + { + expression *m_body; + + public: + constant_declaration(const struct position position, identifier_definition identifier, + expression *body); + void accept(parser_visitor *visitor) override; + + expression& body(); + + virtual ~constant_declaration() override; + }; + + /** + * Procedure type. + */ + class procedure_type_expression : public type_expression + { + public: + using return_t = return_declaration; + + const return_t return_type; + std::vector parameters; + + procedure_type_expression(const struct position position, return_t return_type = return_t()); + ~procedure_type_expression(); + + void accept(parser_visitor *visitor) override; + procedure_type_expression *is_procedure() override; + }; + + struct block + { + block(std::vector&& constants, std::vector&& variables, + std::vector&& body); + block(std::vector&& constants, std::vector&& variables); + block(const block&) = delete; + block(block&& that); + + block& operator=(const block&) = delete; + block& operator=(block&& that); + + const std::vector& variables(); + const std::vector& constants(); + const std::vector& body(); + + virtual ~block(); + + private: + std::vector m_variables; + std::vector m_constants; + std::vector m_body; + + }; + + /** + * Procedure definition. + */ + class procedure_declaration : public declaration + { + procedure_type_expression *m_heading; + + public: + std::optional body; + std::vector parameter_names; + + procedure_declaration(const struct position position, identifier_definition identifier, + procedure_type_expression *heading, block&& body); + procedure_declaration(const struct position position, identifier_definition identifier, + procedure_type_expression *heading); + void accept(parser_visitor *visitor) override; + + procedure_type_expression& heading(); + + virtual ~procedure_declaration() override; + }; + + /** + * Type definition. + */ + class type_declaration : public declaration + { + type_expression *m_body; + + public: + type_declaration(const struct position position, identifier_definition identifier, + type_expression *expression); + ~type_declaration(); + + void accept(parser_visitor *visitor) override; + + type_expression& body(); + }; + + /** + * Cast expression. + */ + class cast_expression : public expression + { + type_expression *m_target; + expression *m_value; + + public: + type expression_type; + + cast_expression(const struct position position, type_expression *target, expression *value); + void accept(parser_visitor *visitor) override; + cast_expression *is_cast() override; + + type_expression& target(); + expression& value(); + + virtual ~cast_expression() override; + }; + + class traits_expression : public expression + { + public: + std::vector parameters; + const std::string name; + std::vector types; + + traits_expression(const struct position position, const std::string& name); + ~traits_expression(); + + void accept(parser_visitor *visitor) override; + traits_expression *is_traits() override; + }; + + /** + * List of statements paired with a condition. + */ + class conditional_statements + { + expression *m_prerequisite; + + public: + const std::vector statements; + + conditional_statements(expression *prerequisite, std::vector&& statements); + + expression& prerequisite(); + + virtual ~conditional_statements(); + }; + + class return_statement : public statement + { + public: + expression *m_return_expression; + + return_statement(const struct position position, expression *return_expression); + void accept(parser_visitor *visitor) 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; + const std::vector *alternative; + + case_statement(const struct position position, expression *condition, + std::vector&& cases, std::vector *alternative = nullptr); + void accept(parser_visitor *visitor) override; + expression& condition(); + }; + + class designator_expression : public expression + { + public: + virtual named_expression *is_named(); + virtual array_access_expression *is_array_access(); + virtual field_access_expression *is_field_access(); + virtual dereference_expression *is_dereference(); + + designator_expression *is_designator() override; + void accept(parser_visitor *visitor); + ~designator_expression() = 0; + }; + + /** + * Expression refering to an entity by its name. + */ + class named_expression : public designator_expression, public type_expression + { + public: + const std::string name; + + named_expression(const struct position position, const std::string& name); + void accept(parser_visitor *visitor) override; + + named_expression *is_named() override; + }; + + class array_access_expression : public designator_expression + { + expression *m_base; + expression *m_index; + + public: + array_access_expression(const struct position position, expression *base, expression *index); + void accept(parser_visitor *visitor) override; + + expression& base(); + expression& index(); + + array_access_expression *is_array_access() override; + + ~array_access_expression() override; + }; + + class field_access_expression : public designator_expression + { + expression *m_base; + std::string m_field; + + public: + field_access_expression(const struct position position, expression *base, + const std::string& field); + void accept(parser_visitor *visitor) override; + + expression& base(); + std::string& field(); + + field_access_expression *is_field_access() override; + + ~field_access_expression() override; + }; + + class dereference_expression : public designator_expression + { + expression *m_base; + + public: + dereference_expression(const struct position position, expression *base); + void accept(parser_visitor *visitor) override; + + expression& base(); + + dereference_expression *is_dereference() override; + + ~dereference_expression() override; + }; + + /** + * Procedure call expression. + */ + class procedure_call : public expression, public statement + { + designator_expression *m_callable; + + public: + std::vector arguments; + + procedure_call(const struct position position, designator_expression *callable); + void accept(parser_visitor *visitor) override; + virtual procedure_call *is_call_expression() override; + + designator_expression& callable(); + + virtual ~procedure_call() override; + }; + + class assign_statement : public statement + { + designator_expression *m_lvalue; + expression *m_rvalue; + + public: + /** + * \param position Source code position. + * \param lvalue Left-hand side. + * \param rvalue Assigned expression. + */ + assign_statement(const struct position position, designator_expression *lvalue, + expression *rvalue); + void accept(parser_visitor *visitor) override; + + designator_expression& lvalue(); + expression& rvalue(); + + virtual ~assign_statement() override; + }; + + /** + * If-statement. + */ + class if_statement : public statement + { + conditional_statements *m_body; + + public: + const std::vector branches; + const std::vector *alternative; + + if_statement(const struct position position, conditional_statements *body, + std::vector&& branches, + std::vector *alternative = nullptr); + void accept(parser_visitor *visitor) override; + + conditional_statements& body(); + + virtual ~if_statement() override; + }; + + /** + * Import statement. + */ + class import_declaration : public node + { + public: + const std::vector segments; + + import_declaration(const struct position position, std::vector&& segments); + void accept(parser_visitor *visitor) override; + }; + + /** + * While-statement. + */ + class while_statement : public statement + { + conditional_statements *m_body; + + public: + const std::vector branches; + + while_statement(const struct position position, conditional_statements *body, + std::vector&& branches); + void accept(parser_visitor *visitor) override; + + conditional_statements& body(); + + virtual ~while_statement() override; + }; + + class unit : public node + { + public: + std::vector imports; + std::vector constants; + std::vector types; + std::vector variables; + std::vector procedures; + + unit(const struct position position); + virtual void accept(parser_visitor *visitor) override; + + virtual ~unit() override; + }; + + class program : public unit + { + public: + std::vector body; + + program(const struct position position); + void accept(parser_visitor *visitor) override; + + virtual ~program() override; + }; + + template + class literal : public literal_expression + { + public: + T value; + + literal(const struct position position, const T& value) + : node(position), value(value) + { + } + + void accept(parser_visitor *visitor) override + { + visitor->visit(this); + } + }; + + class defer_statement : public statement + { + public: + const std::vector statements; + + defer_statement(const struct position position, std::vector&& statements); + void accept(parser_visitor *visitor) override; + + virtual ~defer_statement() override; + }; + + class binary_expression : public expression + { + expression *m_lhs; + expression *m_rhs; + binary_operator m_operator; + + public: + binary_expression(const struct position position, expression *lhs, + expression *rhs, const binary_operator operation); + + void accept(parser_visitor *visitor) override; + binary_expression *is_binary() override; + + expression& lhs(); + expression& rhs(); + binary_operator operation() const; + + virtual ~binary_expression() override; + }; + + class unary_expression : public expression + { + expression *m_operand; + unary_operator m_operator; + + public: + unary_expression(const struct position position, expression *operand, + const unary_operator operation); + + void accept(parser_visitor *visitor) override; + unary_expression *is_unary() override; + + expression& operand(); + unary_operator operation() const; + + virtual ~unary_expression() override; + }; + + const char *print_binary_operator(const binary_operator operation); +} diff --git a/include/elna/boot/dependency.h b/include/elna/boot/dependency.h new file mode 100644 index 0000000..4ec4d44 --- /dev/null +++ b/include/elna/boot/dependency.h @@ -0,0 +1,55 @@ +/* Dependency graph analysis. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include +#include "elna/boot/result.h" +#include "elna/boot/ast.h" +#include "elna/boot/symbol.h" + +namespace elna::boot +{ + class dependency : public error_container + { + error_list m_errors; + + public: + std::unique_ptr tree; + forward_table unresolved; + + explicit dependency(const char *path); + }; + + dependency read_source(std::istream& entry_point, const char *entry_path); + std::filesystem::path build_path(const std::vector& segments); + error_list analyze_semantics(const char *path, std::unique_ptr& tree, symbol_bag bag); + + template + struct dependency_state + { + const std::shared_ptr globals; + T custom; + std::unordered_map cache; + + explicit dependency_state(T custom) + : globals(builtin_symbol_table()), custom(custom) + { + } + }; +} diff --git a/include/elna/boot/driver.h b/include/elna/boot/driver.h new file mode 100644 index 0000000..288aa0c --- /dev/null +++ b/include/elna/boot/driver.h @@ -0,0 +1,51 @@ +/* Parsing driver. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include "elna/boot/ast.h" +#include "location.hh" + +namespace elna::boot +{ + position make_position(const yy::location& location); + + class syntax_error final : public error + { + std::string message; + + public: + syntax_error(const std::string& message, + const char *input_file, const yy::location& location); + + virtual std::string what() const override; + }; + + class driver : public error_container + { + public: + std::unique_ptr tree; + + driver(const char *input_file); + }; + + constexpr char escape_invalid_char = '\xff'; + + char escape_char(char escape); + std::optional escape_string(const char *escape); +} diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h new file mode 100644 index 0000000..9fc1849 --- /dev/null +++ b/include/elna/boot/result.h @@ -0,0 +1,124 @@ +/* Miscellaneous types used across stage boundaries. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace elna::boot +{ + /** + * Position in the source text. + */ + struct position + { + /// Line. + std::size_t line = 1; + + /// Column. + std::size_t column = 1; + }; + + /** + * A compilation error consists of an error message and position. + */ + class error + { + protected: + error(const char *path, const struct position position); + + public: + const struct position position; + const char *path; + + virtual ~error() = default; + + /// Error text. + virtual std::string what() const = 0; + + /// Error line in the source text. + std::size_t line() const; + + /// Error column in the source text. + std::size_t column() const; + }; + + using error_list = typename std::deque>; + + class error_container + { + protected: + error_list m_errors; + + error_container(const char *input_file); + + public: + const char *input_file; + + error_list& errors(); + + template + void add_error(Args... arguments) + { + auto new_error = std::make_unique(arguments...); + m_errors.emplace_back(std::move(new_error)); + } + + bool has_errors() const; + }; + + /** + * Tags a procedure type as never returning. + */ + template + struct return_declaration + { + return_declaration() = default; + + explicit return_declaration(T type) + : proper_type(type) + { + } + + explicit return_declaration(std::monostate) + : no_return(true) + { + } + + T proper_type{}; + bool no_return{ false }; + }; + + struct identifier_definition + { + std::string name; + bool exported; + + bool operator==(const identifier_definition& that) const; + bool operator==(const std::string& that) const; + }; +} + +template<> +struct std::hash +{ + std::size_t operator()(const elna::boot::identifier_definition& key) const noexcept; +}; diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h new file mode 100644 index 0000000..66eb0a7 --- /dev/null +++ b/include/elna/boot/semantic.h @@ -0,0 +1,192 @@ +/* Name analysis. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include +#include +#include + +#include "elna/boot/ast.h" +#include "elna/boot/result.h" +#include "elna/boot/symbol.h" + +namespace elna::boot +{ + class undeclared_error : public error + { + const std::string identifier; + + public: + undeclared_error(const std::string& identifier, const char *path, const struct position position); + + std::string what() const override; + }; + + class already_declared_error : public error + { + const std::string identifier; + + public: + already_declared_error(const std::string& identifier, const char *path, const struct position position); + + std::string what() const override; + }; + + class field_duplication_error : public error + { + const std::string field_name; + + public: + field_duplication_error(const std::string& field_name, const char *path, const struct position position); + + std::string what() const override; + }; + + class cyclic_declaration_error : public error + { + const std::vector cycle; + + public: + cyclic_declaration_error(const std::vector& cycle, + const char *path, const struct position position); + + std::string what() const override; + }; + + class return_error : public error + { + const std::string identifier; + + public: + return_error(const std::string& identifier, const char *path, const struct position position); + + std::string what() const override; + }; + + class variable_initializer_error : public error + { + public: + variable_initializer_error(const char *path, const struct position position); + + std::string what() const override; + }; + + /** + * Checks types. + */ + class type_analysis_visitor final : public empty_visitor, public error_container + { + bool returns; + symbol_bag bag; + + bool check_unresolved_symbol(std::shared_ptr alias, + std::vector& path); + + public: + explicit type_analysis_visitor(const char *path, symbol_bag bag); + + void visit(program *program) override; + + void visit(procedure_declaration *definition) override; + void visit(assign_statement *) override; + void visit(if_statement *) override; + void visit(while_statement *) override; + void visit(return_statement *) override; + void visit(defer_statement *) override; + void visit(case_statement *) override; + void visit(procedure_call *) override; + void visit(unit *unit) override; + void visit(type_declaration *definition) override; + }; + + /** + * Performs name analysis. + */ + class name_analysis_visitor final : public parser_visitor, public error_container + { + type current_type; + constant_info::variant current_literal; + + symbol_bag bag; + + procedure_type build_procedure(procedure_type_expression& type_expression); + std::vector build_composite_type(const std::vector& fields); + std::shared_ptr register_variable(const std::string& name, + const bool is_extern, const struct position position); + + public: + name_analysis_visitor(const char *path, symbol_bag bag); + + void visit(type_expression *) override; + void visit(array_type_expression *type_expression) override; + void visit(pointer_type_expression *type_expression) override; + void visit(program *program) override; + void visit(type_declaration *definition) override; + 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_declaration *definition) override; + void visit(procedure_declaration *definition) override; + void visit(assign_statement *statement) override; + void visit(if_statement *statement) override; + void visit(import_declaration *) 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(unit *unit) override; + void visit(cast_expression *expression) override; + void visit(traits_expression *trait) override; + void visit(binary_expression *expression) override; + void visit(unary_expression *expression) override; + void visit(named_expression *type_expression) override; + void visit(array_access_expression *expression) override; + void visit(field_access_expression *expression) override; + void visit(dereference_expression *expression) 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; + }; + + /** + * Collects global declarations without resolving any symbols. + */ + class declaration_visitor final : public empty_visitor, public error_container + { + public: + forward_table unresolved; + + explicit declaration_visitor(const char *path); + + void visit(program *program) override; + void visit(import_declaration *) override; + void visit(unit *unit) override; + void visit(type_declaration *definition) override; + void visit(variable_declaration *declaration) override; + void visit(procedure_declaration *definition) override; + }; +} diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h new file mode 100644 index 0000000..5ef917e --- /dev/null +++ b/include/elna/boot/symbol.h @@ -0,0 +1,457 @@ +/* Symbol definitions. + Copyright (C) 2025 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "elna/boot/result.h" + +namespace elna::boot +{ + class alias_type; + class primitive_type; + class record_type; + class union_type; + class pointer_type; + class array_type; + class procedure_type; + class enumeration_type; + + class type + { + enum class type_tag + { + empty, + alias, + primitive, + record, + _union, + pointer, + array, + procedure, + enumeration + }; + type_tag tag{ type_tag::empty }; + union + { + std::weak_ptr alias; + std::shared_ptr primitive; + std::shared_ptr record; + std::shared_ptr _union; + std::shared_ptr pointer; + std::shared_ptr array; + std::shared_ptr procedure; + std::shared_ptr enumeration; + }; + + void copy(const type& other); + void move(type&& other); + + public: + type(); + explicit type(std::shared_ptr alias); + explicit type(std::shared_ptr primitive); + explicit type(std::shared_ptr record); + explicit type(std::shared_ptr _union); + 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); + + type(type&& other); + type& operator=(type&& other); + + bool operator==(const std::nullptr_t&); + + ~type(); + + template + std::shared_ptr get() const; + + bool empty() const; + }; + + struct alias_type + { + const std::string name; + type reference; + + explicit alias_type(const std::string& name); + }; + + struct pointer_type + { + const type base; + + explicit pointer_type(type base); + }; + + struct array_type + { + const type base; + const std::uint64_t size; + + array_type(type base, std::uint64_t size); + }; + + struct primitive_type + { + const std::string identifier; + + explicit primitive_type(const std::string& identifier); + }; + + using type_field = std::pair; + + struct record_type + { + std::vector fields; + }; + + struct union_type + { + std::vector fields; + }; + + struct procedure_type + { + using return_t = return_declaration; + + std::vector parameters; + const return_t return_type; + + 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 variable_info; + + class info : public std::enable_shared_from_this + { + public: + bool exported{ false }; + + virtual ~info() = 0; + + virtual std::shared_ptr is_type(); + virtual std::shared_ptr is_procedure(); + virtual std::shared_ptr is_constant(); + virtual std::shared_ptr is_variable(); + }; + + /** + * Symbol table. + */ + template + class symbol_map + { + public: + using symbol_ptr = typename std::enable_if< + std::is_convertible::value || std::is_assignable::value, + T + >::type; + using iterator = typename std::unordered_map::iterator; + using const_iterator = typename std::unordered_map::const_iterator; + + private: + std::unordered_map entries; + std::shared_ptr outer_scope; + + public: + /** + * Constructs a new symbol with an optional outer scope. + * + * \param scope Outer scope. + */ + explicit symbol_map(std::shared_ptr scope = nullptr) + : outer_scope(scope) + { + } + + iterator begin() + { + return this->entries.begin(); + } + + iterator end() + { + return this->entries.end(); + } + + const_iterator cbegin() const + { + return this->entries.cbegin(); + } + + const_iterator cend() const + { + return this->entries.cend(); + } + + /** + * \return Symbol count in the current scope. + */ + std::size_t size() const + { + return this->entries.size(); + } + + /** + * Looks for symbol in the table by name. Returns nothing if the symbol + * can not be found. + * + * \param name Symbol name. + * + * \return Symbol from the table if found. + */ + symbol_ptr lookup(const std::string& name) + { + auto entry = entries.find(name); + + if (entry != entries.cend()) + { + return entry->second; + } + if (this->outer_scope != nullptr) + { + return this->outer_scope->lookup(name); + } + return nothing; + } + + /** + * \param name Symbol name. + * + * \return Whether the table contains a symbol with the given name. + */ + bool contains(const std::string& name) + { + return lookup(name) != nothing; + } + + /** + * Registers new symbol. + * + * \param name Symbol name. + * \param entry Symbol information. + * + * \return Whether the insertion took place. + */ + bool enter(const std::string& name, symbol_ptr entry) + { + return lookup(name) == nothing && entries.insert({ name, entry }).second; + } + + /** + * Returns the outer scope or nullptr if the this is the global scope. + * + * \return Outer scope. + */ + std::shared_ptr scope() + { + return this->outer_scope; + } + }; + + using symbol_table = symbol_map, std::nullptr_t, nullptr>; + using forward_table = std::unordered_map>; + + class type_info : public info + { + public: + const type symbol; + + explicit type_info(const type symbol); + std::shared_ptr is_type() override; + }; + + /** + * Procedure symbol information. + */ + class procedure_info : public info + { + public: + /// Procedure type. + const procedure_type symbol; + + /// Parameter names. + const std::vector names; + + /// Local definitions. + std::shared_ptr scope; + + /** + * Constructs procedure symbol information. + * + * \param symbol Procedure type. + * \param names Parameter names. + * \param scope Local definition (is `nullptr` for extern symbols). + */ + procedure_info(const procedure_type symbol, const std::vector names, + std::shared_ptr scope = nullptr); + + std::shared_ptr is_procedure() override; + + /** + * \return Whether this is an extern symbol. + */ + bool is_extern() const; + }; + + class constant_info : public info + { + public: + using variant = typename + std::variant; + + const variant symbol; + + explicit constant_info(const variant& symbol); + std::shared_ptr is_constant() override; + }; + + /** + * Variable symbol information. + */ + class variable_info : public info + { + public: + /// Variable type. + const type symbol; + + /// Whether this is an extern symbol. + const bool is_extern; + + /** + * Constructs a variable symbol information. + * + * \param symbol Variable type. + * \param is_extern Whether this is an extern symbol. + */ + variable_info(const type symbol, bool is_extern); + + std::shared_ptr is_variable() override; + }; + + std::shared_ptr builtin_symbol_table(); + + /** + * Symbol bag contains: + * + * - the symbol table of a module itself + * - symbol tables of imported modules + * - forward declarations + */ + class symbol_bag + { + std::shared_ptr symbols; + std::forward_list> imports; + forward_table unresolved; + + public: + + /** + * \param unresolved Forward declarations collected in the previous step. + * \param global_table Global symbols. + */ + symbol_bag(forward_table&& unresolved, std::shared_ptr global_table); + + /** + * Looks up a symbol in the current and imported modules. + * + * \param name Symbol name to look up. + * + * \return Symbol from one of the symbol tables if found. + */ + std::shared_ptr lookup(const std::string& name); + + /** + * Inserts a symbol into the current scope. + * + * \param name Symbol name. + * \param entry Symbol info. + * + * \return Whether the insertion took place. + */ + bool enter(const std::string& name, std::shared_ptr entry); + + /** + * Enters a new scope. + * + * \return Reference to the allocated scope. + */ + std::shared_ptr enter(); + + /** + * Sets the current scope to \a child. + * + * \param child New scope. + */ + void enter(std::shared_ptr child); + + /** + * Leave the current scope. + * + * \return Left scope. + */ + std::shared_ptr leave(); + + /** + * Checks whether there is a forward declaration \a symbol_name and + * returns it if so. + * + * \param symbol_name Type name to look up. + * \return Forward declaration or `nullptr` if the symbol is not declared. + */ + std::shared_ptr declared(const std::string& symbol_name); + + /** + * Completes the forward-declared type \a symbol_name and defines it to + * be \a resolution. + * + * \param symbol_name Type name. + * \param resolution Type definition. + * \return Alias to the defined type. + */ + std::shared_ptr resolve(const std::string& symbol_name, type& resolution); + + /** + * Add imported symbols to the scope. + * + * \param bag Symbol bag of another module. + */ + void add_import(const symbol_bag& bag); + }; +} diff --git a/include/elna/frontend/ast.h b/include/elna/frontend/ast.h deleted file mode 100644 index 0b5f3d7..0000000 --- a/include/elna/frontend/ast.h +++ /dev/null @@ -1,800 +0,0 @@ -/* Abstract syntax tree representation. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#pragma once - -#include -#include -#include -#include -#include -#include "elna/frontend/symbol.h" -#include "elna/frontend/result.h" - -namespace elna::frontend -{ - enum class binary_operator - { - sum, - subtraction, - multiplication, - division, - remainder, - equals, - not_equals, - less, - greater, - less_equal, - greater_equal, - disjunction, - conjunction, - exclusive_disjunction, - shift_left, - shift_right - }; - - enum class unary_operator - { - reference, - negation, - minus - }; - - class variable_declaration; - class constant_declaration; - class procedure_declaration; - class type_declaration; - class procedure_call; - class cast_expression; - class assign_statement; - class if_statement; - class import_declaration; - class while_statement; - class return_statement; - class case_statement; - class traits_expression; - class unit; - class program; - class binary_expression; - class unary_expression; - class 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 named_expression; - class array_access_expression; - class field_access_expression; - class dereference_expression; - class designator_expression; - class literal_expression; - template - class literal; - class defer_statement; - - /** - * Interface for AST visitors. - */ - struct parser_visitor - { - virtual void visit(variable_declaration *) = 0; - virtual void visit(constant_declaration *) = 0; - virtual void visit(procedure_declaration *) = 0; - virtual void visit(type_declaration *) = 0; - virtual void visit(procedure_call *) = 0; - virtual void visit(cast_expression *) = 0; - virtual void visit(traits_expression *) = 0; - virtual void visit(assign_statement *) = 0; - virtual void visit(if_statement *) = 0; - virtual void visit(import_declaration *) = 0; - 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(unit *) = 0; - virtual void visit(program *) = 0; - virtual void visit(binary_expression *) = 0; - virtual void visit(unary_expression *) = 0; - virtual void visit(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(named_expression *) = 0; - virtual void visit(array_access_expression *) = 0; - virtual void visit(field_access_expression *) = 0; - virtual void visit(dereference_expression *) = 0; - virtual void visit(literal *) = 0; - virtual void visit(literal *) = 0; - virtual void visit(literal *) = 0; - virtual void visit(literal *) = 0; - virtual void visit(literal *) = 0; - virtual void visit(literal *) = 0; - virtual void visit(literal *) = 0; - }; - - /** - * Abstract visitor that doesn't visit any nodes by default. - */ - class empty_visitor : public parser_visitor - { - [[noreturn]] void not_implemented(); - - public: - [[noreturn]] virtual void visit(type_expression *) override; - [[noreturn]] virtual void visit(array_type_expression *) override; - [[noreturn]] virtual void visit(pointer_type_expression *) override; - [[noreturn]] virtual void visit(program *) override; - [[noreturn]] virtual void visit(type_declaration *) override; - [[noreturn]] virtual void visit(record_type_expression *) override; - [[noreturn]] virtual void visit(union_type_expression *) override; - [[noreturn]] virtual void visit(procedure_type_expression *) override; - [[noreturn]] virtual void visit(enumeration_type_expression *) override; - - [[noreturn]] virtual void visit(variable_declaration *) override; - [[noreturn]] virtual void visit(constant_declaration *) override; - [[noreturn]] virtual void visit(procedure_declaration *) override; - [[noreturn]] virtual void visit(assign_statement *) override; - [[noreturn]] virtual void visit(if_statement *) override; - [[noreturn]] virtual void visit(import_declaration *) override; - [[noreturn]] virtual void visit(while_statement *) override; - [[noreturn]] virtual void visit(return_statement *) override; - [[noreturn]] virtual void visit(defer_statement *) override; - [[noreturn]] virtual void visit(case_statement *) override; - [[noreturn]] virtual void visit(procedure_call *) override; - [[noreturn]] virtual void visit(unit *) override; - [[noreturn]] virtual void visit(cast_expression *) override; - [[noreturn]] virtual void visit(traits_expression *) override; - [[noreturn]] virtual void visit(binary_expression *) override; - [[noreturn]] virtual void visit(unary_expression *) override; - [[noreturn]] virtual void visit(named_expression *) override; - [[noreturn]] virtual void visit(array_access_expression *) override; - [[noreturn]] virtual void visit(field_access_expression *) override; - [[noreturn]] virtual void visit(dereference_expression *) override; - [[noreturn]] virtual void visit(literal *) override; - [[noreturn]] virtual void visit(literal *) override; - [[noreturn]] virtual void visit(literal *) override; - [[noreturn]] virtual void visit(literal *) override; - [[noreturn]] virtual void visit(literal *) override; - [[noreturn]] virtual void visit(literal *) override; - [[noreturn]] virtual void visit(literal *) override; - }; - - /** - * AST node. - */ - class node - { - const struct position source_position; - - protected: - /** - * \param position Source code position. - */ - explicit node(const position position); - - public: - virtual void accept(parser_visitor *visitor) = 0; - virtual ~node() = 0; - - /** - * \return Node position in the source code. - */ - const struct position& position() const; - }; - - class statement : public virtual node - { - }; - - class expression : public virtual node - { - public: - virtual cast_expression *is_cast(); - virtual traits_expression *is_traits(); - virtual binary_expression *is_binary(); - virtual unary_expression *is_unary(); - virtual designator_expression *is_designator(); - virtual procedure_call *is_call_expression(); - virtual literal_expression *is_literal(); - }; - - /** - * Symbol definition. - */ - class declaration : public node - { - protected: - declaration(const struct position position, identifier_definition identifier); - - public: - const identifier_definition identifier; - }; - - /** - * Some type expression. - */ - class type_expression : public virtual node - { - public: - virtual named_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(); - - void accept(parser_visitor *visitor) override; - ~type_expression() = 0; - }; - - class array_type_expression : public type_expression - { - type_expression *m_base; - - public: - const std::uint32_t size; - - array_type_expression(const struct position position, - type_expression *base, const std::uint32_t size); - ~array_type_expression(); - - void accept(parser_visitor *visitor) override; - array_type_expression *is_array() override; - - type_expression& base(); - }; - - class pointer_type_expression : public type_expression - { - type_expression *m_base; - - public: - pointer_type_expression(const struct position position, type_expression *base); - ~pointer_type_expression(); - - void accept(parser_visitor *visitor) override; - pointer_type_expression *is_pointer() override; - - type_expression& base(); - }; - - using field_declaration = std::pair; - - class record_type_expression : public type_expression - { - public: - const std::vector fields; - - record_type_expression(const struct position position, std::vector&& fields); - ~record_type_expression(); - - void accept(parser_visitor *visitor) override; - record_type_expression *is_record() override; - }; - - class union_type_expression : public type_expression - { - public: - std::vector fields; - - union_type_expression(const struct position position, std::vector&& fields); - ~union_type_expression(); - - void accept(parser_visitor *visitor) override; - 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. - */ - class variable_declaration : public node - { - std::shared_ptr m_variable_type; - - public: - variable_declaration(const struct position position, - std::vector&& identifier, std::shared_ptr variable_type, - expression *body = nullptr); - variable_declaration(const struct position position, - std::vector&& identifier, std::shared_ptr variable_type, - std::monostate); - - void accept(parser_visitor *visitor) override; - - bool has_initializer() const; - - const std::vector identifiers; - type_expression& variable_type(); - expression *const body{ nullptr }; - const bool is_extern{ false }; - }; - - /** - * Literal expression. - */ - class literal_expression : public expression - { - public: - literal_expression *is_literal() override; - }; - - /** - * Constant definition. - */ - class constant_declaration : public declaration - { - expression *m_body; - - public: - constant_declaration(const struct position position, identifier_definition identifier, - expression *body); - void accept(parser_visitor *visitor) override; - - expression& body(); - - virtual ~constant_declaration() override; - }; - - /** - * Procedure type. - */ - class procedure_type_expression : public type_expression - { - public: - using return_t = return_declaration; - - const return_t return_type; - std::vector parameters; - - procedure_type_expression(const struct position position, return_t return_type = return_t()); - ~procedure_type_expression(); - - void accept(parser_visitor *visitor) override; - procedure_type_expression *is_procedure() override; - }; - - struct block - { - block(std::vector&& constants, std::vector&& variables, - std::vector&& body); - block(std::vector&& constants, std::vector&& variables); - block(const block&) = delete; - block(block&& that); - - block& operator=(const block&) = delete; - block& operator=(block&& that); - - const std::vector& variables(); - const std::vector& constants(); - const std::vector& body(); - - virtual ~block(); - - private: - std::vector m_variables; - std::vector m_constants; - std::vector m_body; - - }; - - /** - * Procedure definition. - */ - class procedure_declaration : public declaration - { - procedure_type_expression *m_heading; - - public: - std::optional body; - std::vector parameter_names; - - procedure_declaration(const struct position position, identifier_definition identifier, - procedure_type_expression *heading, block&& body); - procedure_declaration(const struct position position, identifier_definition identifier, - procedure_type_expression *heading); - void accept(parser_visitor *visitor) override; - - procedure_type_expression& heading(); - - virtual ~procedure_declaration() override; - }; - - /** - * Type definition. - */ - class type_declaration : public declaration - { - type_expression *m_body; - - public: - type_declaration(const struct position position, identifier_definition identifier, - type_expression *expression); - ~type_declaration(); - - void accept(parser_visitor *visitor) override; - - type_expression& body(); - }; - - /** - * Cast expression. - */ - class cast_expression : public expression - { - type_expression *m_target; - expression *m_value; - - public: - type expression_type; - - cast_expression(const struct position position, type_expression *target, expression *value); - void accept(parser_visitor *visitor) override; - cast_expression *is_cast() override; - - type_expression& target(); - expression& value(); - - virtual ~cast_expression() override; - }; - - class traits_expression : public expression - { - public: - std::vector parameters; - const std::string name; - std::vector types; - - traits_expression(const struct position position, const std::string& name); - ~traits_expression(); - - void accept(parser_visitor *visitor) override; - traits_expression *is_traits() override; - }; - - /** - * List of statements paired with a condition. - */ - class conditional_statements - { - expression *m_prerequisite; - - public: - const std::vector statements; - - conditional_statements(expression *prerequisite, std::vector&& statements); - - expression& prerequisite(); - - virtual ~conditional_statements(); - }; - - class return_statement : public statement - { - public: - expression *m_return_expression; - - return_statement(const struct position position, expression *return_expression); - void accept(parser_visitor *visitor) 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; - const std::vector *alternative; - - case_statement(const struct position position, expression *condition, - std::vector&& cases, std::vector *alternative = nullptr); - void accept(parser_visitor *visitor) override; - expression& condition(); - }; - - class designator_expression : public expression - { - public: - virtual named_expression *is_named(); - virtual array_access_expression *is_array_access(); - virtual field_access_expression *is_field_access(); - virtual dereference_expression *is_dereference(); - - designator_expression *is_designator() override; - void accept(parser_visitor *visitor); - ~designator_expression() = 0; - }; - - /** - * Expression refering to an entity by its name. - */ - class named_expression : public designator_expression, public type_expression - { - public: - const std::string name; - - named_expression(const struct position position, const std::string& name); - void accept(parser_visitor *visitor) override; - - named_expression *is_named() override; - }; - - class array_access_expression : public designator_expression - { - expression *m_base; - expression *m_index; - - public: - array_access_expression(const struct position position, expression *base, expression *index); - void accept(parser_visitor *visitor) override; - - expression& base(); - expression& index(); - - array_access_expression *is_array_access() override; - - ~array_access_expression() override; - }; - - class field_access_expression : public designator_expression - { - expression *m_base; - std::string m_field; - - public: - field_access_expression(const struct position position, expression *base, - const std::string& field); - void accept(parser_visitor *visitor) override; - - expression& base(); - std::string& field(); - - field_access_expression *is_field_access() override; - - ~field_access_expression() override; - }; - - class dereference_expression : public designator_expression - { - expression *m_base; - - public: - dereference_expression(const struct position position, expression *base); - void accept(parser_visitor *visitor) override; - - expression& base(); - - dereference_expression *is_dereference() override; - - ~dereference_expression() override; - }; - - /** - * Procedure call expression. - */ - class procedure_call : public expression, public statement - { - designator_expression *m_callable; - - public: - std::vector arguments; - - procedure_call(const struct position position, designator_expression *callable); - void accept(parser_visitor *visitor) override; - virtual procedure_call *is_call_expression() override; - - designator_expression& callable(); - - virtual ~procedure_call() override; - }; - - class assign_statement : public statement - { - designator_expression *m_lvalue; - expression *m_rvalue; - - public: - /** - * \param position Source code position. - * \param lvalue Left-hand side. - * \param rvalue Assigned expression. - */ - assign_statement(const struct position position, designator_expression *lvalue, - expression *rvalue); - void accept(parser_visitor *visitor) override; - - designator_expression& lvalue(); - expression& rvalue(); - - virtual ~assign_statement() override; - }; - - /** - * If-statement. - */ - class if_statement : public statement - { - conditional_statements *m_body; - - public: - const std::vector branches; - const std::vector *alternative; - - if_statement(const struct position position, conditional_statements *body, - std::vector&& branches, - std::vector *alternative = nullptr); - void accept(parser_visitor *visitor) override; - - conditional_statements& body(); - - virtual ~if_statement() override; - }; - - /** - * Import statement. - */ - class import_declaration : public node - { - public: - const std::vector segments; - - import_declaration(const struct position position, std::vector&& segments); - void accept(parser_visitor *visitor) override; - }; - - /** - * While-statement. - */ - class while_statement : public statement - { - conditional_statements *m_body; - - public: - const std::vector branches; - - while_statement(const struct position position, conditional_statements *body, - std::vector&& branches); - void accept(parser_visitor *visitor) override; - - conditional_statements& body(); - - virtual ~while_statement() override; - }; - - class unit : public node - { - public: - std::vector imports; - std::vector constants; - std::vector types; - std::vector variables; - std::vector procedures; - - unit(const struct position position); - virtual void accept(parser_visitor *visitor) override; - - virtual ~unit() override; - }; - - class program : public unit - { - public: - std::vector body; - - program(const struct position position); - void accept(parser_visitor *visitor) override; - - virtual ~program() override; - }; - - template - class literal : public literal_expression - { - public: - T value; - - literal(const struct position position, const T& value) - : node(position), value(value) - { - } - - void accept(parser_visitor *visitor) override - { - visitor->visit(this); - } - }; - - class defer_statement : public statement - { - public: - const std::vector statements; - - defer_statement(const struct position position, std::vector&& statements); - void accept(parser_visitor *visitor) override; - - virtual ~defer_statement() override; - }; - - class binary_expression : public expression - { - expression *m_lhs; - expression *m_rhs; - binary_operator m_operator; - - public: - binary_expression(const struct position position, expression *lhs, - expression *rhs, const binary_operator operation); - - void accept(parser_visitor *visitor) override; - binary_expression *is_binary() override; - - expression& lhs(); - expression& rhs(); - binary_operator operation() const; - - virtual ~binary_expression() override; - }; - - class unary_expression : public expression - { - expression *m_operand; - unary_operator m_operator; - - public: - unary_expression(const struct position position, expression *operand, - const unary_operator operation); - - void accept(parser_visitor *visitor) override; - unary_expression *is_unary() override; - - expression& operand(); - unary_operator operation() const; - - virtual ~unary_expression() override; - }; - - const char *print_binary_operator(const binary_operator operation); -} diff --git a/include/elna/frontend/dependency.h b/include/elna/frontend/dependency.h deleted file mode 100644 index f1502d1..0000000 --- a/include/elna/frontend/dependency.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Dependency graph analysis. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#pragma once - -#include -#include -#include "elna/frontend/result.h" -#include "elna/frontend/ast.h" -#include "elna/frontend/symbol.h" - -namespace elna::frontend -{ - class dependency : public error_container - { - error_list m_errors; - - public: - std::unique_ptr tree; - forward_table unresolved; - - explicit dependency(const char *path); - }; - - dependency read_source(std::istream& entry_point, const char *entry_path); - std::filesystem::path build_path(const std::vector& segments); - error_list analyze_semantics(const char *path, std::unique_ptr& tree, symbol_bag bag); - - template - struct dependency_state - { - const std::shared_ptr globals; - T custom; - std::unordered_map cache; - - explicit dependency_state(T custom) - : globals(builtin_symbol_table()), custom(custom) - { - } - }; -} diff --git a/include/elna/frontend/driver.h b/include/elna/frontend/driver.h deleted file mode 100644 index 66ef579..0000000 --- a/include/elna/frontend/driver.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Parsing driver. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#pragma once - -#include -#include "elna/frontend/ast.h" -#include "location.hh" - -namespace elna::frontend -{ - position make_position(const yy::location& location); - - class syntax_error final : public error - { - std::string message; - - public: - syntax_error(const std::string& message, - const char *input_file, const yy::location& location); - - virtual std::string what() const override; - }; - - class driver : public error_container - { - public: - std::unique_ptr tree; - - driver(const char *input_file); - }; - - constexpr char escape_invalid_char = '\xff'; - - char escape_char(char escape); - std::optional escape_string(const char *escape); -} diff --git a/include/elna/frontend/result.h b/include/elna/frontend/result.h deleted file mode 100644 index 7e5ed77..0000000 --- a/include/elna/frontend/result.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Miscellaneous types used across stage boundaries. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace elna::frontend -{ - /** - * Position in the source text. - */ - struct position - { - /// Line. - std::size_t line = 1; - - /// Column. - std::size_t column = 1; - }; - - /** - * A compilation error consists of an error message and position. - */ - class error - { - protected: - error(const char *path, const struct position position); - - public: - const struct position position; - const char *path; - - virtual ~error() = default; - - /// Error text. - virtual std::string what() const = 0; - - /// Error line in the source text. - std::size_t line() const; - - /// Error column in the source text. - std::size_t column() const; - }; - - using error_list = typename std::deque>; - - class error_container - { - protected: - error_list m_errors; - - error_container(const char *input_file); - - public: - const char *input_file; - - error_list& errors(); - - template - void add_error(Args... arguments) - { - auto new_error = std::make_unique(arguments...); - m_errors.emplace_back(std::move(new_error)); - } - - bool has_errors() const; - }; - - /** - * Tags a procedure type as never returning. - */ - template - struct return_declaration - { - return_declaration() = default; - - explicit return_declaration(T type) - : proper_type(type) - { - } - - explicit return_declaration(std::monostate) - : no_return(true) - { - } - - T proper_type{}; - bool no_return{ false }; - }; - - struct identifier_definition - { - std::string name; - bool exported; - - bool operator==(const identifier_definition& that) const; - bool operator==(const std::string& that) const; - }; -} - -template<> -struct std::hash -{ - std::size_t operator()(const elna::frontend::identifier_definition& key) const noexcept; -}; diff --git a/include/elna/frontend/semantic.h b/include/elna/frontend/semantic.h deleted file mode 100644 index 887b660..0000000 --- a/include/elna/frontend/semantic.h +++ /dev/null @@ -1,192 +0,0 @@ -/* Name analysis. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#pragma once - -#include -#include -#include -#include - -#include "elna/frontend/ast.h" -#include "elna/frontend/result.h" -#include "elna/frontend/symbol.h" - -namespace elna::frontend -{ - class undeclared_error : public error - { - const std::string identifier; - - public: - undeclared_error(const std::string& identifier, const char *path, const struct position position); - - std::string what() const override; - }; - - class already_declared_error : public error - { - const std::string identifier; - - public: - already_declared_error(const std::string& identifier, const char *path, const struct position position); - - std::string what() const override; - }; - - class field_duplication_error : public error - { - const std::string field_name; - - public: - field_duplication_error(const std::string& field_name, const char *path, const struct position position); - - std::string what() const override; - }; - - class cyclic_declaration_error : public error - { - const std::vector cycle; - - public: - cyclic_declaration_error(const std::vector& cycle, - const char *path, const struct position position); - - std::string what() const override; - }; - - class return_error : public error - { - const std::string identifier; - - public: - return_error(const std::string& identifier, const char *path, const struct position position); - - std::string what() const override; - }; - - class variable_initializer_error : public error - { - public: - variable_initializer_error(const char *path, const struct position position); - - std::string what() const override; - }; - - /** - * Checks types. - */ - class type_analysis_visitor final : public empty_visitor, public error_container - { - bool returns; - symbol_bag bag; - - bool check_unresolved_symbol(std::shared_ptr alias, - std::vector& path); - - public: - explicit type_analysis_visitor(const char *path, symbol_bag bag); - - void visit(program *program) override; - - void visit(procedure_declaration *definition) override; - void visit(assign_statement *) override; - void visit(if_statement *) override; - void visit(while_statement *) override; - void visit(return_statement *) override; - void visit(defer_statement *) override; - void visit(case_statement *) override; - void visit(procedure_call *) override; - void visit(unit *unit) override; - void visit(type_declaration *definition) override; - }; - - /** - * Performs name analysis. - */ - class name_analysis_visitor final : public parser_visitor, public error_container - { - type current_type; - constant_info::variant current_literal; - - symbol_bag bag; - - procedure_type build_procedure(procedure_type_expression& type_expression); - std::vector build_composite_type(const std::vector& fields); - std::shared_ptr register_variable(const std::string& name, - const bool is_extern, const struct position position); - - public: - name_analysis_visitor(const char *path, symbol_bag bag); - - void visit(type_expression *) override; - void visit(array_type_expression *type_expression) override; - void visit(pointer_type_expression *type_expression) override; - void visit(program *program) override; - void visit(type_declaration *definition) override; - 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_declaration *definition) override; - void visit(procedure_declaration *definition) override; - void visit(assign_statement *statement) override; - void visit(if_statement *statement) override; - void visit(import_declaration *) 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(unit *unit) override; - void visit(cast_expression *expression) override; - void visit(traits_expression *trait) override; - void visit(binary_expression *expression) override; - void visit(unary_expression *expression) override; - void visit(named_expression *type_expression) override; - void visit(array_access_expression *expression) override; - void visit(field_access_expression *expression) override; - void visit(dereference_expression *expression) 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; - }; - - /** - * Collects global declarations without resolving any symbols. - */ - class declaration_visitor final : public empty_visitor, public error_container - { - public: - forward_table unresolved; - - explicit declaration_visitor(const char *path); - - void visit(program *program) override; - void visit(import_declaration *) override; - void visit(unit *unit) override; - void visit(type_declaration *definition) override; - void visit(variable_declaration *declaration) override; - void visit(procedure_declaration *definition) override; - }; -} diff --git a/include/elna/frontend/symbol.h b/include/elna/frontend/symbol.h deleted file mode 100644 index ec912ef..0000000 --- a/include/elna/frontend/symbol.h +++ /dev/null @@ -1,457 +0,0 @@ -/* Symbol definitions. - Copyright (C) 2025 Free Software Foundation, Inc. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "elna/frontend/result.h" - -namespace elna::frontend -{ - class alias_type; - class primitive_type; - class record_type; - class union_type; - class pointer_type; - class array_type; - class procedure_type; - class enumeration_type; - - class type - { - enum class type_tag - { - empty, - alias, - primitive, - record, - _union, - pointer, - array, - procedure, - enumeration - }; - type_tag tag{ type_tag::empty }; - union - { - std::weak_ptr alias; - std::shared_ptr primitive; - std::shared_ptr record; - std::shared_ptr _union; - std::shared_ptr pointer; - std::shared_ptr array; - std::shared_ptr procedure; - std::shared_ptr enumeration; - }; - - void copy(const type& other); - void move(type&& other); - - public: - type(); - explicit type(std::shared_ptr alias); - explicit type(std::shared_ptr primitive); - explicit type(std::shared_ptr record); - explicit type(std::shared_ptr _union); - 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); - - type(type&& other); - type& operator=(type&& other); - - bool operator==(const std::nullptr_t&); - - ~type(); - - template - std::shared_ptr get() const; - - bool empty() const; - }; - - struct alias_type - { - const std::string name; - type reference; - - explicit alias_type(const std::string& name); - }; - - struct pointer_type - { - const type base; - - explicit pointer_type(type base); - }; - - struct array_type - { - const type base; - const std::uint64_t size; - - array_type(type base, std::uint64_t size); - }; - - struct primitive_type - { - const std::string identifier; - - explicit primitive_type(const std::string& identifier); - }; - - using type_field = std::pair; - - struct record_type - { - std::vector fields; - }; - - struct union_type - { - std::vector fields; - }; - - struct procedure_type - { - using return_t = return_declaration; - - std::vector parameters; - const return_t return_type; - - 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 variable_info; - - class info : public std::enable_shared_from_this - { - public: - bool exported{ false }; - - virtual ~info() = 0; - - virtual std::shared_ptr is_type(); - virtual std::shared_ptr is_procedure(); - virtual std::shared_ptr is_constant(); - virtual std::shared_ptr is_variable(); - }; - - /** - * Symbol table. - */ - template - class symbol_map - { - public: - using symbol_ptr = typename std::enable_if< - std::is_convertible::value || std::is_assignable::value, - T - >::type; - using iterator = typename std::unordered_map::iterator; - using const_iterator = typename std::unordered_map::const_iterator; - - private: - std::unordered_map entries; - std::shared_ptr outer_scope; - - public: - /** - * Constructs a new symbol with an optional outer scope. - * - * \param scope Outer scope. - */ - explicit symbol_map(std::shared_ptr scope = nullptr) - : outer_scope(scope) - { - } - - iterator begin() - { - return this->entries.begin(); - } - - iterator end() - { - return this->entries.end(); - } - - const_iterator cbegin() const - { - return this->entries.cbegin(); - } - - const_iterator cend() const - { - return this->entries.cend(); - } - - /** - * \return Symbol count in the current scope. - */ - std::size_t size() const - { - return this->entries.size(); - } - - /** - * Looks for symbol in the table by name. Returns nothing if the symbol - * can not be found. - * - * \param name Symbol name. - * - * \return Symbol from the table if found. - */ - symbol_ptr lookup(const std::string& name) - { - auto entry = entries.find(name); - - if (entry != entries.cend()) - { - return entry->second; - } - if (this->outer_scope != nullptr) - { - return this->outer_scope->lookup(name); - } - return nothing; - } - - /** - * \param name Symbol name. - * - * \return Whether the table contains a symbol with the given name. - */ - bool contains(const std::string& name) - { - return lookup(name) != nothing; - } - - /** - * Registers new symbol. - * - * \param name Symbol name. - * \param entry Symbol information. - * - * \return Whether the insertion took place. - */ - bool enter(const std::string& name, symbol_ptr entry) - { - return lookup(name) == nothing && entries.insert({ name, entry }).second; - } - - /** - * Returns the outer scope or nullptr if the this is the global scope. - * - * \return Outer scope. - */ - std::shared_ptr scope() - { - return this->outer_scope; - } - }; - - using symbol_table = symbol_map, std::nullptr_t, nullptr>; - using forward_table = std::unordered_map>; - - class type_info : public info - { - public: - const type symbol; - - explicit type_info(const type symbol); - std::shared_ptr is_type() override; - }; - - /** - * Procedure symbol information. - */ - class procedure_info : public info - { - public: - /// Procedure type. - const procedure_type symbol; - - /// Parameter names. - const std::vector names; - - /// Local definitions. - std::shared_ptr scope; - - /** - * Constructs procedure symbol information. - * - * \param symbol Procedure type. - * \param names Parameter names. - * \param scope Local definition (is `nullptr` for extern symbols). - */ - procedure_info(const procedure_type symbol, const std::vector names, - std::shared_ptr scope = nullptr); - - std::shared_ptr is_procedure() override; - - /** - * \return Whether this is an extern symbol. - */ - bool is_extern() const; - }; - - class constant_info : public info - { - public: - using variant = typename - std::variant; - - const variant symbol; - - explicit constant_info(const variant& symbol); - std::shared_ptr is_constant() override; - }; - - /** - * Variable symbol information. - */ - class variable_info : public info - { - public: - /// Variable type. - const type symbol; - - /// Whether this is an extern symbol. - const bool is_extern; - - /** - * Constructs a variable symbol information. - * - * \param symbol Variable type. - * \param is_extern Whether this is an extern symbol. - */ - variable_info(const type symbol, bool is_extern); - - std::shared_ptr is_variable() override; - }; - - std::shared_ptr builtin_symbol_table(); - - /** - * Symbol bag contains: - * - * - the symbol table of a module itself - * - symbol tables of imported modules - * - forward declarations - */ - class symbol_bag - { - std::shared_ptr symbols; - std::forward_list> imports; - forward_table unresolved; - - public: - - /** - * \param unresolved Forward declarations collected in the previous step. - * \param global_table Global symbols. - */ - symbol_bag(forward_table&& unresolved, std::shared_ptr global_table); - - /** - * Looks up a symbol in the current and imported modules. - * - * \param name Symbol name to look up. - * - * \return Symbol from one of the symbol tables if found. - */ - std::shared_ptr lookup(const std::string& name); - - /** - * Inserts a symbol into the current scope. - * - * \param name Symbol name. - * \param entry Symbol info. - * - * \return Whether the insertion took place. - */ - bool enter(const std::string& name, std::shared_ptr entry); - - /** - * Enters a new scope. - * - * \return Reference to the allocated scope. - */ - std::shared_ptr enter(); - - /** - * Sets the current scope to \a child. - * - * \param child New scope. - */ - void enter(std::shared_ptr child); - - /** - * Leave the current scope. - * - * \return Left scope. - */ - std::shared_ptr leave(); - - /** - * Checks whether there is a forward declaration \a symbol_name and - * returns it if so. - * - * \param symbol_name Type name to look up. - * \return Forward declaration or `nullptr` if the symbol is not declared. - */ - std::shared_ptr declared(const std::string& symbol_name); - - /** - * Completes the forward-declared type \a symbol_name and defines it to - * be \a resolution. - * - * \param symbol_name Type name. - * \param resolution Type definition. - * \return Alias to the defined type. - */ - std::shared_ptr resolve(const std::string& symbol_name, type& resolution); - - /** - * Add imported symbols to the scope. - * - * \param bag Symbol bag of another module. - */ - void add_import(const symbol_bag& bag); - }; -} diff --git a/include/elna/gcc/elna-builtins.h b/include/elna/gcc/elna-builtins.h index 60baab7..0cdf519 100644 --- a/include/elna/gcc/elna-builtins.h +++ b/include/elna/gcc/elna-builtins.h @@ -30,12 +30,12 @@ namespace elna::gcc void init_ttree(); std::shared_ptr builtin_symbol_table(); - void rewrite_symbol_table(std::shared_ptr info_table, std::shared_ptr symbols); - tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, + void rewrite_symbol_table(std::shared_ptr info_table, std::shared_ptr symbols); + tree handle_symbol(const std::string& symbol_name, std::shared_ptr reference, std::shared_ptr symbols); - tree get_inner_alias(const frontend::type& type, std::shared_ptr symbols); - void declare_procedure(const std::string& name, const frontend::procedure_info& info, + tree get_inner_alias(const boot::type& type, std::shared_ptr symbols); + void declare_procedure(const std::string& name, const boot::procedure_info& info, std::shared_ptr symbols); - tree declare_variable(const std::string& name, const frontend::variable_info& info, + tree declare_variable(const std::string& name, const boot::variable_info& info, std::shared_ptr symbols); } diff --git a/include/elna/gcc/elna-diagnostic.h b/include/elna/gcc/elna-diagnostic.h index 83f768e..1eef65d 100644 --- a/include/elna/gcc/elna-diagnostic.h +++ b/include/elna/gcc/elna-diagnostic.h @@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see #include #include -#include "elna/frontend/result.h" +#include "elna/boot/result.h" namespace elna::gcc { @@ -40,7 +40,7 @@ namespace elna::gcc ~linemap_guard(); }; - location_t get_location(const frontend::position *position); + location_t get_location(const boot::position *position); std::string print_type(tree type); - void report_errors(const std::deque>& errors); + void report_errors(const std::deque>& errors); } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index ec6f32f..7490e92 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -17,9 +17,9 @@ along with GCC; see the file COPYING3. If not see #pragma once -#include "elna/frontend/ast.h" -#include "elna/frontend/symbol.h" -#include "elna/frontend/semantic.h" +#include "elna/boot/ast.h" +#include "elna/boot/symbol.h" +#include "elna/boot/semantic.h" #include "elna/gcc/elna-tree.h" #include "config.h" @@ -33,65 +33,65 @@ along with GCC; see the file COPYING3. If not see namespace elna::gcc { - class generic_visitor final : public frontend::empty_visitor + class generic_visitor final : public boot::empty_visitor { tree current_expression{ NULL_TREE }; - elna::frontend::symbol_bag bag; + elna::boot::symbol_bag bag; std::shared_ptr symbols; void enter_scope(); tree leave_scope(); - void make_if_branch(frontend::conditional_statements& branch, tree goto_endif); + void make_if_branch(boot::conditional_statements& branch, tree goto_endif); - tree build_arithmetic_operation(frontend::binary_expression *expression, + tree build_arithmetic_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right); - tree build_comparison_operation(frontend::binary_expression *expression, + tree build_comparison_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right); - tree build_bit_logic_operation(frontend::binary_expression *expression, tree left, tree right); - tree build_equality_operation(frontend::binary_expression *expression, tree left, tree right); + tree build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right); + tree build_equality_operation(boot::binary_expression *expression, tree left, tree right); void build_procedure_call(location_t call_location, - tree procedure_address, const std::vector& arguments); + tree procedure_address, const std::vector& arguments); void build_record_call(location_t call_location, - tree symbol, const std::vector& arguments); - bool build_builtin_procedures(frontend::procedure_call *call); - void build_assert_builtin(location_t call_location, const std::vector& arguments); + tree symbol, const std::vector& arguments); + bool build_builtin_procedures(boot::procedure_call *call); + void build_assert_builtin(location_t call_location, const std::vector& arguments); - bool expect_trait_type_only(frontend::traits_expression *trait); - bool expect_trait_for_integral_type(frontend::traits_expression *trait); - void visit_statements(const std::vector& statements); + bool expect_trait_type_only(boot::traits_expression *trait); + bool expect_trait_for_integral_type(boot::traits_expression *trait); + void visit_statements(const std::vector& statements); bool assert_constant(location_t expression_location); public: - generic_visitor(std::shared_ptr symbol_table, elna::frontend::symbol_bag bag); + generic_visitor(std::shared_ptr symbol_table, elna::boot::symbol_bag bag); - void visit(frontend::program *program) override; - void visit(frontend::procedure_declaration *definition) override; - void visit(frontend::procedure_call *call) override; - void visit(frontend::cast_expression *expression) override; - void visit(frontend::traits_expression *trait) override; - void visit(frontend::literal *literal) override; - void visit(frontend::literal *literal) override; - void visit(frontend::literal *literal) override; - void visit(frontend::literal *boolean) override; - void visit(frontend::literal *character) override; - void visit(frontend::literal *) override; - void visit(frontend::literal *string) override; - void visit(frontend::binary_expression *expression) override; - void visit(frontend::unary_expression *expression) override; - void visit(frontend::constant_declaration *definition) override; - void visit(frontend::variable_declaration *declaration) override; - void visit(frontend::named_expression *expression) override; - void visit(frontend::array_access_expression *expression) override; - void visit(frontend::field_access_expression *expression) override; - void visit(frontend::dereference_expression *expression) override; - void visit(frontend::unit *unit) override; - void visit(frontend::assign_statement *statement) override; - void visit(frontend::if_statement *statement) override; - void visit(frontend::import_declaration *) override; - void visit(frontend::while_statement *statement) override; - void visit(frontend::return_statement *statement) override; - void visit(frontend::defer_statement *statement) override; - void visit(frontend::case_statement *statement) override; + void visit(boot::program *program) override; + void visit(boot::procedure_declaration *definition) override; + void visit(boot::procedure_call *call) override; + void visit(boot::cast_expression *expression) override; + void visit(boot::traits_expression *trait) override; + void visit(boot::literal *literal) override; + void visit(boot::literal *literal) override; + void visit(boot::literal *literal) override; + void visit(boot::literal *boolean) override; + void visit(boot::literal *character) override; + void visit(boot::literal *) override; + void visit(boot::literal *string) override; + void visit(boot::binary_expression *expression) override; + void visit(boot::unary_expression *expression) override; + void visit(boot::constant_declaration *definition) override; + void visit(boot::variable_declaration *declaration) override; + void visit(boot::named_expression *expression) override; + void visit(boot::array_access_expression *expression) override; + void visit(boot::field_access_expression *expression) override; + void visit(boot::dereference_expression *expression) override; + void visit(boot::unit *unit) override; + void visit(boot::assign_statement *statement) override; + void visit(boot::if_statement *statement) override; + void visit(boot::import_declaration *) override; + void visit(boot::while_statement *statement) 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 48dfeb5..f1402a7 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -27,13 +27,13 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "fold-const.h" -#include "elna/frontend/ast.h" -#include "elna/frontend/symbol.h" +#include "elna/boot/ast.h" +#include "elna/boot/symbol.h" #include "elna/gcc/elna1.h" namespace elna::gcc { - using symbol_table = frontend::symbol_map; + using symbol_table = boot::symbol_map; bool is_integral_type(tree type); bool is_numeric_type(tree type); @@ -74,11 +74,11 @@ namespace elna::gcc void defer(tree statement_tree); tree chain_defer(); - tree do_pointer_arithmetic(frontend::binary_operator binary_operator, + tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right, location_t expression_location); - tree build_binary_operation(bool condition, frontend::binary_expression *expression, + tree build_binary_operation(bool condition, boot::binary_expression *expression, tree_code operator_code, tree left, tree right, tree target_type); - tree build_arithmetic_operation(frontend::binary_expression *expression, + tree build_arithmetic_operation(boot::binary_expression *expression, tree_code operator_code, tree left, tree right); 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); -- cgit v1.2.3