summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/elna/frontend/ast.h815
-rw-r--r--include/elna/frontend/dependency.h55
-rw-r--r--include/elna/frontend/driver.h51
-rw-r--r--include/elna/frontend/result.h124
-rw-r--r--include/elna/frontend/semantic.h190
-rw-r--r--include/elna/frontend/symbol.h457
-rw-r--r--include/elna/gcc/elna-builtins.h41
-rw-r--r--include/elna/gcc/elna-diagnostic.h46
-rw-r--r--include/elna/gcc/elna-generic.h97
-rw-r--r--include/elna/gcc/elna-tree.h105
-rw-r--r--include/elna/gcc/elna1.h94
11 files changed, 2075 insertions, 0 deletions
diff --git a/include/elna/frontend/ast.h b/include/elna/frontend/ast.h
new file mode 100644
index 0000000..bbb8a36
--- /dev/null
+++ b/include/elna/frontend/ast.h
@@ -0,0 +1,815 @@
+/* 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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+#include <optional>
+#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 named_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 variable_expression;
+ class array_access_expression;
+ class field_access_expression;
+ class dereference_expression;
+ class designator_expression;
+ class literal_expression;
+ template<typename T>
+ 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(named_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(variable_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<std::int32_t> *) = 0;
+ virtual void visit(literal<std::uint32_t> *) = 0;
+ virtual void visit(literal<double> *) = 0;
+ virtual void visit(literal<bool> *) = 0;
+ virtual void visit(literal<unsigned char> *) = 0;
+ virtual void visit(literal<std::nullptr_t> *) = 0;
+ virtual void visit(literal<std::string> *) = 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(named_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(variable_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<std::int32_t> *) override;
+ [[noreturn]] virtual void visit(literal<std::uint32_t> *) override;
+ [[noreturn]] virtual void visit(literal<double> *) override;
+ [[noreturn]] virtual void visit(literal<bool> *) override;
+ [[noreturn]] virtual void visit(literal<unsigned char> *) override;
+ [[noreturn]] virtual void visit(literal<std::nullptr_t> *) override;
+ [[noreturn]] virtual void visit(literal<std::string> *) 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 node
+ {
+ public:
+ virtual named_type_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();
+
+ protected:
+ type_expression(const struct position position);
+ };
+
+ /**
+ * Expression refering to a type by its name.
+ */
+ class named_type_expression : public type_expression
+ {
+ public:
+ const std::string name;
+
+ named_type_expression(const struct position position, const std::string& name);
+ void accept(parser_visitor *visitor) override;
+ named_type_expression *is_named() override;
+ };
+
+ 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<std::string, type_expression *>;
+
+ class record_type_expression : public type_expression
+ {
+ public:
+ const std::vector<field_declaration> fields;
+
+ record_type_expression(const struct position position, std::vector<field_declaration>&& 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<field_declaration> fields;
+
+ union_type_expression(const struct position position, std::vector<field_declaration>&& 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<std::string> members;
+
+ enumeration_type_expression(const struct position, std::vector<std::string>&& members);
+
+ void accept(parser_visitor *visitor) override;
+ enumeration_type_expression *is_enumeration() override;
+ };
+
+ /**
+ * Variable declaration.
+ */
+ class variable_declaration : public node
+ {
+ std::shared_ptr<type_expression> m_variable_type;
+
+ public:
+ variable_declaration(const struct position position,
+ std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type,
+ expression *body = nullptr);
+ variable_declaration(const struct position position,
+ std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type,
+ std::monostate);
+
+ void accept(parser_visitor *visitor) override;
+
+ bool has_initializer() const;
+
+ const std::vector<identifier_definition> 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;
+
+ protected:
+ literal_expression();
+ };
+
+ /**
+ * 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<type_expression *>;
+
+ const return_t return_type;
+ std::vector<type_expression *> 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<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables,
+ std::vector<statement *>&& body);
+ block(const block&) = delete;
+ block(block&& that);
+
+ block& operator=(const block&) = delete;
+ block& operator=(block&& that);
+
+ const std::vector<variable_declaration *>& variables();
+ const std::vector<constant_declaration *>& constants();
+ const std::vector<statement *>& body();
+
+ virtual ~block();
+
+ private:
+ std::vector<variable_declaration *> m_variables;
+ std::vector<constant_declaration *> m_constants;
+ std::vector<statement *> m_body;
+
+ };
+
+ /**
+ * Procedure definition.
+ */
+ class procedure_declaration : public declaration
+ {
+ procedure_type_expression *m_heading;
+
+ public:
+ std::optional<block> body;
+ std::vector<std::string> 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<type_expression *> parameters;
+ const std::string name;
+ std::vector<type> 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<statement *> statements;
+
+ conditional_statements(expression *prerequisite, std::vector<statement *>&& 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<expression *> labels;
+ std::vector<statement *> statements;
+ };
+
+ class case_statement : public statement
+ {
+ expression *m_condition;
+
+ public:
+ const std::vector<switch_case> cases;
+ const std::vector<statement *> *alternative;
+
+ case_statement(const struct position position, expression *condition,
+ std::vector<switch_case>&& cases, std::vector<statement *> *alternative = nullptr);
+ void accept(parser_visitor *visitor) override;
+ expression& condition();
+ };
+
+ class designator_expression : public expression
+ {
+ public:
+ virtual variable_expression *is_variable();
+ 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;
+
+ protected:
+ designator_expression();
+ };
+
+ class variable_expression : public designator_expression, public literal_expression
+ {
+ public:
+ const std::string name;
+
+ variable_expression(const struct position position, const std::string& name);
+ void accept(parser_visitor *visitor) override;
+
+ variable_expression *is_variable() 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<expression *> 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<conditional_statements *> branches;
+ const std::vector<statement *> *alternative;
+
+ if_statement(const struct position position, conditional_statements *body,
+ std::vector<conditional_statements *>&& branches,
+ std::vector<statement *> *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<std::string> segments;
+
+ import_declaration(const struct position position, std::vector<std::string>&& segments);
+ void accept(parser_visitor *visitor) override;
+ };
+
+ /**
+ * While-statement.
+ */
+ class while_statement : public statement
+ {
+ conditional_statements *m_body;
+
+ public:
+ const std::vector<conditional_statements *> branches;
+
+ while_statement(const struct position position, conditional_statements *body,
+ std::vector<conditional_statements *>&& branches);
+ void accept(parser_visitor *visitor) override;
+
+ conditional_statements& body();
+
+ virtual ~while_statement() override;
+ };
+
+ class unit : public node
+ {
+ public:
+ std::vector<import_declaration *> imports;
+ std::vector<constant_declaration *> constants;
+ std::vector<type_declaration *> types;
+ std::vector<variable_declaration *> variables;
+ std::vector<procedure_declaration *> procedures;
+
+ unit(const struct position position);
+ virtual void accept(parser_visitor *visitor) override;
+
+ virtual ~unit() override;
+ };
+
+ class program : public unit
+ {
+ public:
+ std::vector<statement *> body;
+
+ program(const struct position position);
+ void accept(parser_visitor *visitor) override;
+
+ virtual ~program() override;
+ };
+
+ template<typename T>
+ 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<statement *> statements;
+
+ defer_statement(const struct position position, std::vector<statement *>&& 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
new file mode 100644
index 0000000..f1502d1
--- /dev/null
+++ b/include/elna/frontend/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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <filesystem>
+#include <fstream>
+#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<unit> 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<std::string>& segments);
+ error_list analyze_semantics(const char *path, std::unique_ptr<unit>& tree, symbol_bag bag);
+
+ template<typename T>
+ struct dependency_state
+ {
+ const std::shared_ptr<symbol_table> globals;
+ T custom;
+ std::unordered_map<std::filesystem::path, symbol_bag> 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
new file mode 100644
index 0000000..66ef579
--- /dev/null
+++ b/include/elna/frontend/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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <optional>
+#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<unit> tree;
+
+ driver(const char *input_file);
+ };
+
+ constexpr char escape_invalid_char = '\xff';
+
+ char escape_char(char escape);
+ std::optional<std::string> escape_string(const char *escape);
+}
diff --git a/include/elna/frontend/result.h b/include/elna/frontend/result.h
new file mode 100644
index 0000000..7e5ed77
--- /dev/null
+++ b/include/elna/frontend/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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <cstddef>
+#include <string>
+#include <deque>
+#include <memory>
+#include <variant>
+
+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<std::unique_ptr<error>>;
+
+ class error_container
+ {
+ protected:
+ error_list m_errors;
+
+ error_container(const char *input_file);
+
+ public:
+ const char *input_file;
+
+ error_list& errors();
+
+ template<typename T, typename... Args>
+ void add_error(Args... arguments)
+ {
+ auto new_error = std::make_unique<T>(arguments...);
+ m_errors.emplace_back(std::move(new_error));
+ }
+
+ bool has_errors() const;
+ };
+
+ /**
+ * Tags a procedure type as never returning.
+ */
+ template<typename T>
+ 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<elna::frontend::identifier_definition>
+{
+ 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
new file mode 100644
index 0000000..8a295e4
--- /dev/null
+++ b/include/elna/frontend/semantic.h
@@ -0,0 +1,190 @@
+/* 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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+#include <memory>
+#include <deque>
+
+#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<std::string> cycle;
+
+ public:
+ cyclic_declaration_error(const std::vector<std::string>& 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_type> alias,
+ std::vector<std::string>& 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<type_field> build_composite_type(const std::vector<field_declaration>& fields);
+
+ public:
+ name_analysis_visitor(const char *path, symbol_bag bag);
+
+ void visit(named_type_expression *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(variable_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<std::int32_t> *literal) override;
+ void visit(literal<std::uint32_t> *literal) override;
+ void visit(literal<double> *literal) override;
+ void visit(literal<bool> *literal) override;
+ void visit(literal<unsigned char> *literal) override;
+ void visit(literal<std::nullptr_t> *literal) override;
+ void visit(literal<std::string> *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
new file mode 100644
index 0000000..ec912ef
--- /dev/null
+++ b/include/elna/frontend/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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <cstdint>
+#include <unordered_map>
+#include <string>
+#include <memory>
+#include <vector>
+#include <forward_list>
+
+#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_type> alias;
+ std::shared_ptr<primitive_type> primitive;
+ std::shared_ptr<record_type> record;
+ std::shared_ptr<union_type> _union;
+ std::shared_ptr<pointer_type> pointer;
+ std::shared_ptr<array_type> array;
+ std::shared_ptr<procedure_type> procedure;
+ std::shared_ptr<enumeration_type> enumeration;
+ };
+
+ void copy(const type& other);
+ void move(type&& other);
+
+ public:
+ type();
+ explicit type(std::shared_ptr<alias_type> alias);
+ explicit type(std::shared_ptr<primitive_type> primitive);
+ explicit type(std::shared_ptr<record_type> record);
+ explicit type(std::shared_ptr<union_type> _union);
+ explicit type(std::shared_ptr<pointer_type> pointer);
+ explicit type(std::shared_ptr<array_type> array);
+ explicit type(std::shared_ptr<procedure_type> procedure);
+ explicit type(std::shared_ptr<enumeration_type> 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<typename T>
+ std::shared_ptr<T> 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<std::string, type>;
+
+ struct record_type
+ {
+ std::vector<type_field> fields;
+ };
+
+ struct union_type
+ {
+ std::vector<type_field> fields;
+ };
+
+ struct procedure_type
+ {
+ using return_t = return_declaration<type>;
+
+ std::vector<type> parameters;
+ const return_t return_type;
+
+ procedure_type(return_t return_type = return_t());
+ };
+
+ struct enumeration_type
+ {
+ std::vector<std::string> members;
+
+ explicit enumeration_type(const std::vector<std::string>& members);
+ };
+
+ class type_info;
+ class procedure_info;
+ class constant_info;
+ class variable_info;
+
+ class info : public std::enable_shared_from_this<info>
+ {
+ public:
+ bool exported{ false };
+
+ virtual ~info() = 0;
+
+ virtual std::shared_ptr<type_info> is_type();
+ virtual std::shared_ptr<procedure_info> is_procedure();
+ virtual std::shared_ptr<constant_info> is_constant();
+ virtual std::shared_ptr<variable_info> is_variable();
+ };
+
+ /**
+ * Symbol table.
+ */
+ template<typename T, typename U, U nothing>
+ class symbol_map
+ {
+ public:
+ using symbol_ptr = typename std::enable_if<
+ std::is_convertible<U, T>::value || std::is_assignable<T, U>::value,
+ T
+ >::type;
+ using iterator = typename std::unordered_map<std::string, symbol_ptr>::iterator;
+ using const_iterator = typename std::unordered_map<std::string, symbol_ptr>::const_iterator;
+
+ private:
+ std::unordered_map<std::string, symbol_ptr> entries;
+ std::shared_ptr<symbol_map> outer_scope;
+
+ public:
+ /**
+ * Constructs a new symbol with an optional outer scope.
+ *
+ * \param scope Outer scope.
+ */
+ explicit symbol_map(std::shared_ptr<symbol_map> 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<symbol_map> scope()
+ {
+ return this->outer_scope;
+ }
+ };
+
+ using symbol_table = symbol_map<std::shared_ptr<info>, std::nullptr_t, nullptr>;
+ using forward_table = std::unordered_map<std::string, std::shared_ptr<alias_type>>;
+
+ class type_info : public info
+ {
+ public:
+ const type symbol;
+
+ explicit type_info(const type symbol);
+ std::shared_ptr<type_info> is_type() override;
+ };
+
+ /**
+ * Procedure symbol information.
+ */
+ class procedure_info : public info
+ {
+ public:
+ /// Procedure type.
+ const procedure_type symbol;
+
+ /// Parameter names.
+ const std::vector<std::string> names;
+
+ /// Local definitions.
+ std::shared_ptr<symbol_table> 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<std::string> names,
+ std::shared_ptr<symbol_table> scope = nullptr);
+
+ std::shared_ptr<procedure_info> 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<std::int32_t, std::uint32_t, double, bool, unsigned char, std::nullptr_t, std::string>;
+
+ const variant symbol;
+
+ explicit constant_info(const variant& symbol);
+ std::shared_ptr<constant_info> 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<variable_info> is_variable() override;
+ };
+
+ std::shared_ptr<symbol_table> 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<symbol_table> symbols;
+ std::forward_list<std::shared_ptr<symbol_table>> 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<symbol_table> 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<info> 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<info> entry);
+
+ /**
+ * Enters a new scope.
+ *
+ * \return Reference to the allocated scope.
+ */
+ std::shared_ptr<symbol_table> enter();
+
+ /**
+ * Sets the current scope to \a child.
+ *
+ * \param child New scope.
+ */
+ void enter(std::shared_ptr<symbol_table> child);
+
+ /**
+ * Leave the current scope.
+ *
+ * \return Left scope.
+ */
+ std::shared_ptr<symbol_table> 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<alias_type> 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<alias_type> 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
new file mode 100644
index 0000000..60baab7
--- /dev/null
+++ b/include/elna/gcc/elna-builtins.h
@@ -0,0 +1,41 @@
+/* Builtin 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
+<http://www.gnu.org/licenses/>. */
+
+#include <memory>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-iterator.h"
+
+#include "elna/gcc/elna-tree.h"
+
+namespace elna::gcc
+{
+ void init_ttree();
+ std::shared_ptr<symbol_table> builtin_symbol_table();
+
+ void rewrite_symbol_table(std::shared_ptr<frontend::symbol_table> info_table, std::shared_ptr<symbol_table> symbols);
+ tree handle_symbol(const std::string& symbol_name, std::shared_ptr<frontend::alias_type> reference,
+ std::shared_ptr<symbol_table> symbols);
+ tree get_inner_alias(const frontend::type& type, std::shared_ptr<symbol_table> symbols);
+ void declare_procedure(const std::string& name, const frontend::procedure_info& info,
+ std::shared_ptr<symbol_table> symbols);
+ tree declare_variable(const std::string& name, const frontend::variable_info& info,
+ std::shared_ptr<symbol_table> symbols);
+}
diff --git a/include/elna/gcc/elna-diagnostic.h b/include/elna/gcc/elna-diagnostic.h
new file mode 100644
index 0000000..83f768e
--- /dev/null
+++ b/include/elna/gcc/elna-diagnostic.h
@@ -0,0 +1,46 @@
+/* Elna frontend specific diagnostic routines.
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "input.h"
+#include "tree.h"
+#include "diagnostic.h"
+
+#include <deque>
+#include <memory>
+
+#include "elna/frontend/result.h"
+
+namespace elna::gcc
+{
+ struct linemap_guard
+ {
+ explicit linemap_guard(const char *filename);
+ linemap_guard(const linemap_guard&) = delete;
+ linemap_guard(linemap_guard&&) = delete;
+
+ ~linemap_guard();
+ };
+
+ location_t get_location(const frontend::position *position);
+ std::string print_type(tree type);
+ void report_errors(const std::deque<std::unique_ptr<frontend::error>>& errors);
+}
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
new file mode 100644
index 0000000..97cd512
--- /dev/null
+++ b/include/elna/gcc/elna-generic.h
@@ -0,0 +1,97 @@
+/* Visitor generating a GENERIC tree.
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include "elna/frontend/ast.h"
+#include "elna/frontend/symbol.h"
+#include "elna/frontend/semantic.h"
+#include "elna/gcc/elna-tree.h"
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-iterator.h"
+
+#include <string>
+#include <forward_list>
+
+namespace elna::gcc
+{
+ class generic_visitor final : public frontend::empty_visitor
+ {
+ tree current_expression{ NULL_TREE };
+ elna::frontend::symbol_bag bag;
+ std::shared_ptr<symbol_table> symbols;
+
+ void enter_scope();
+ tree leave_scope();
+
+ void make_if_branch(frontend::conditional_statements& branch, tree goto_endif);
+
+ tree build_arithmetic_operation(frontend::binary_expression *expression,
+ tree_code operator_code, tree left, tree right);
+ tree build_comparison_operation(frontend::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);
+ void build_procedure_call(location_t call_location,
+ tree procedure_address, const std::vector<frontend::expression *>& arguments);
+ void build_record_call(location_t call_location,
+ tree symbol, const std::vector<frontend::expression *>& arguments);
+ bool build_builtin_procedures(frontend::procedure_call *call);
+ void build_assert_builtin(location_t call_location, const std::vector<frontend::expression *>& 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<frontend::statement *>& statements);
+ bool assert_constant(location_t expression_location);
+
+ public:
+ generic_visitor(std::shared_ptr<symbol_table> symbol_table, elna::frontend::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<std::int32_t> *literal) override;
+ void visit(frontend::literal<std::uint32_t> *literal) override;
+ void visit(frontend::literal<double> *literal) override;
+ void visit(frontend::literal<bool> *boolean) override;
+ void visit(frontend::literal<unsigned char> *character) override;
+ void visit(frontend::literal<std::nullptr_t> *) override;
+ void visit(frontend::literal<std::string> *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::variable_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;
+ };
+}
diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h
new file mode 100644
index 0000000..48dfeb5
--- /dev/null
+++ b/include/elna/gcc/elna-tree.h
@@ -0,0 +1,105 @@
+/* Utilities to manipulate GCC trees.
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <forward_list>
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-iterator.h"
+#include "stringpool.h"
+#include "fold-const.h"
+
+#include "elna/frontend/ast.h"
+#include "elna/frontend/symbol.h"
+#include "elna/gcc/elna1.h"
+
+namespace elna::gcc
+{
+ using symbol_table = frontend::symbol_map<tree, tree, NULL_TREE>;
+
+ bool is_integral_type(tree type);
+ bool is_numeric_type(tree type);
+ bool is_unique_type(tree type);
+ bool is_void_type(tree type);
+
+ /**
+ * \param type The type to evaluate.
+ * \return Whether this type can be converted to another type.
+ */
+ bool is_castable_type(tree type);
+
+ /**
+ * \param lhs Left hand value.
+ * \param rhs Right hand value.
+ * \return Whether rhs can be assigned to lhs.
+ */
+ bool are_compatible_pointers(tree lhs_type, tree rhs);
+
+ /**
+ * Prepares a value to be bound to a variable or parameter.
+ *
+ * If rvalue is a procedure declaration, builds a procedure pointer.
+ *
+ * \param rvalue Value to be assigned.
+ * \return Processed value.
+ */
+ tree prepare_rvalue(tree rvalue);
+
+ /**
+ * \param assignee Assignee.
+ * \param assignee Assignment.
+ * \return Whether an expression assignment can be assigned to a variable of type assignee.
+ */
+ bool is_assignable_from(tree assignee, tree assignment);
+
+ void append_statement(tree statement_tree);
+ void defer(tree statement_tree);
+ tree chain_defer();
+
+ tree do_pointer_arithmetic(frontend::binary_operator binary_operator,
+ tree left, tree right, location_t expression_location);
+ tree build_binary_operation(bool condition, frontend::binary_expression *expression,
+ tree_code operator_code, tree left, tree right, tree target_type);
+ tree build_arithmetic_operation(frontend::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);
+ tree build_global_pointer_type(tree type);
+ tree build_static_array_type(tree type, const std::uint64_t size);
+ tree build_enumeration_type(const std::vector<std::string>& members);
+ tree build_label_decl(const char *name, location_t loc);
+
+ tree extract_constant(tree expression);
+
+ template<typename... Args>
+ tree call_built_in(location_t call_location, const char *name, tree return_type, Args... arguments)
+ {
+ tree *builtin = elna_global_decls->get(name);
+ gcc_assert(builtin != nullptr);
+
+ tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(*builtin));
+ tree builtin_addr = build1_loc(call_location, ADDR_EXPR, build_pointer_type(fndecl_type), *builtin);
+
+ tree argument_trees[sizeof...(Args)] = {arguments...};
+
+ return fold_build_call_array(return_type, builtin_addr, sizeof...(Args), argument_trees);
+ }
+}
diff --git a/include/elna/gcc/elna1.h b/include/elna/gcc/elna1.h
new file mode 100644
index 0000000..91d0e6f
--- /dev/null
+++ b/include/elna/gcc/elna1.h
@@ -0,0 +1,94 @@
+/* Language-dependent hooks for Elna.
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+enum elna_tree_index
+{
+ ELNA_TI_INT_TYPE,
+ ELNA_TI_WORD_TYPE,
+ ELNA_TI_CHAR_TYPE,
+ ELNA_TI_BOOL_TYPE,
+ ELNA_TI_POINTER_TYPE,
+ ELNA_TI_FLOAT_TYPE,
+ ELNA_TI_STRING_TYPE,
+ ELNA_TI_BOOL_TRUE,
+ ELNA_TI_BOOL_FALSE,
+ ELNA_TI_POINTER_NIL,
+ ELNA_TI_STRING_PTR_FIELD,
+ ELNA_TI_STRING_LENGTH_FIELD,
+ ELNA_TI_MAX
+};
+
+extern GTY(()) tree elna_global_trees[ELNA_TI_MAX];
+extern GTY(()) hash_map<nofree_string_hash, tree> *elna_global_decls;
+
+#define elna_int_type_node elna_global_trees[ELNA_TI_INT_TYPE]
+#define elna_word_type_node elna_global_trees[ELNA_TI_WORD_TYPE]
+#define elna_char_type_node elna_global_trees[ELNA_TI_CHAR_TYPE]
+#define elna_bool_type_node elna_global_trees[ELNA_TI_BOOL_TYPE]
+#define elna_pointer_type_node elna_global_trees[ELNA_TI_POINTER_TYPE]
+#define elna_float_type_node elna_global_trees[ELNA_TI_FLOAT_TYPE]
+#define elna_string_type_node elna_global_trees[ELNA_TI_STRING_TYPE]
+#define elna_bool_true_node elna_global_trees[ELNA_TI_BOOL_TRUE]
+#define elna_bool_false_node elna_global_trees[ELNA_TI_BOOL_FALSE]
+#define elna_pointer_nil_node elna_global_trees[ELNA_TI_POINTER_NIL]
+#define elna_string_ptr_field_node elna_global_trees[ELNA_TI_STRING_PTR_FIELD]
+#define elna_string_length_field_node elna_global_trees[ELNA_TI_STRING_LENGTH_FIELD]
+
+/* Language-dependent contents of a type. */
+struct GTY (()) lang_type
+{
+};
+
+/* Language-dependent contents of a decl. */
+struct GTY (()) lang_decl
+{
+};
+
+struct GTY (()) defer_scope
+{
+ tree defer_block;
+ tree try_statements;
+};
+
+struct GTY ((chain_next ("%h.level_chain"))) binding_level
+{
+ // A block chain is needed to call defer statements beloning to each block.
+ tree blocks;
+
+ // Parent level.
+ struct binding_level *level_chain;
+
+ // Statements before the first defer has been seen.
+ tree statement_list;
+
+ // Defer statement coupled with statements following it.
+ vec<defer_scope, va_gc> *defers;
+};
+
+struct GTY (()) language_function
+{
+ // Local variables and constants.
+ tree names;
+
+ // Lexical scope.
+ struct binding_level *binding_level;
+};
+
+#define f_binding_level DECL_STRUCT_FUNCTION(current_function_decl)->language->binding_level
+#define f_names DECL_STRUCT_FUNCTION(current_function_decl)->language->names