diff options
| -rw-r--r-- | README.md (renamed from gcc/README.md) | 6 | ||||
| -rw-r--r-- | Rakefile | 1 | ||||
| -rw-r--r-- | boot/ast.cc (renamed from frontend/ast.cc) | 90 | ||||
| -rw-r--r-- | boot/dependency.cc (renamed from frontend/dependency.cc) | 8 | ||||
| -rw-r--r-- | boot/driver.cc (renamed from frontend/driver.cc) | 10 | ||||
| -rw-r--r-- | boot/lexer.ll (renamed from frontend/lexer.ll) | 12 | ||||
| -rw-r--r-- | boot/parser.yy | 595 | ||||
| -rw-r--r-- | boot/result.cc (renamed from frontend/result.cc) | 8 | ||||
| -rw-r--r-- | boot/semantic.cc (renamed from frontend/semantic.cc) | 92 | ||||
| -rw-r--r-- | boot/symbol.cc (renamed from frontend/symbol.cc) | 4 | ||||
| -rw-r--r-- | doc/appendix.tex | 10 | ||||
| -rw-r--r-- | doc/language.tex | 193 | ||||
| -rw-r--r-- | frontend/parser.yy | 594 | ||||
| -rw-r--r-- | gcc/Make-lang.in | 6 | ||||
| -rw-r--r-- | gcc/elna-builtins.cc | 54 | ||||
| -rw-r--r-- | gcc/elna-diagnostic.cc | 6 | ||||
| -rw-r--r-- | gcc/elna-generic.cc | 172 | ||||
| -rw-r--r-- | gcc/elna-tree.cc | 10 | ||||
| -rw-r--r-- | gcc/elna1.cc | 16 | ||||
| -rw-r--r-- | include/elna/boot/ast.h (renamed from include/elna/frontend/ast.h) | 55 | ||||
| -rw-r--r-- | include/elna/boot/dependency.h (renamed from include/elna/frontend/dependency.h) | 8 | ||||
| -rw-r--r-- | include/elna/boot/driver.h (renamed from include/elna/frontend/driver.h) | 4 | ||||
| -rw-r--r-- | include/elna/boot/result.h (renamed from include/elna/frontend/result.h) | 6 | ||||
| -rw-r--r-- | include/elna/boot/semantic.h (renamed from include/elna/frontend/semantic.h) | 14 | ||||
| -rw-r--r-- | include/elna/boot/symbol.h (renamed from include/elna/frontend/symbol.h) | 4 | ||||
| -rw-r--r-- | include/elna/gcc/elna-builtins.h | 10 | ||||
| -rw-r--r-- | include/elna/gcc/elna-diagnostic.h | 6 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 92 | ||||
| -rw-r--r-- | include/elna/gcc/elna-tree.h | 12 | ||||
| -rw-r--r-- | rakelib/doc.rake | 5 | ||||
| -rw-r--r-- | rakelib/gcc.rake | 9 | ||||
| -rw-r--r-- | source/cctype.elna | 23 | ||||
| -rw-r--r-- | source/command_line_interface.elna | 18 | ||||
| -rw-r--r-- | source/common.elna | 40 | ||||
| -rw-r--r-- | source/cstdio.elna | 49 | ||||
| -rw-r--r-- | source/cstdlib.elna | 22 | ||||
| -rw-r--r-- | source/cstring.elna | 27 | ||||
| -rw-r--r-- | source/lexer.elna | 139 | ||||
| -rw-r--r-- | source/main.elna | 218 |
39 files changed, 1448 insertions, 1200 deletions
diff --git a/gcc/README.md b/README.md index 99d03c3..039639a 100644 --- a/gcc/README.md +++ b/README.md @@ -14,7 +14,7 @@ in the `boot/` directory. ## Build -The frontend requires GCC 15.2.0 (not tested with other versions). +The frontend requires GCC 15.3.0 (not tested with other versions). Download the GCC source. Copy the contents of this repository into `gcc/elna` inside GCC. Finally build GCC enabling the frontend with @@ -28,14 +28,14 @@ and Mac OS. In the latter case GCC is patched with the patches used by Homebrew (official GCC doesn't support Apple silicon targets). Invoke with ```sh -rake boot +rake gcc ``` `gcc` binary is used by default, but a different gcc version can be specified by passing `CC` and `CXX` environment variables to rake, e.g.: ```sh -rake CC=gcc-15 CXX=g++-15 boot +rake CC=gcc-15 CXX=g++-15 gcc ``` See `rake -T` for more tasks. The GCC source is under `build/tools`. The @@ -7,6 +7,7 @@ require 'pathname' require 'rake/clean' CLEAN.include 'build/gcc' +CLOBBER.include 'build' task default: :source diff --git a/frontend/ast.cc b/boot/ast.cc index e067937..e4c46a4 100644 --- a/frontend/ast.cc +++ b/boot/ast.cc @@ -15,16 +15,16 @@ 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 "elna/frontend/ast.h" +#include "elna/boot/ast.h" -namespace elna::frontend +namespace elna::boot { void empty_visitor::not_implemented() { __builtin_unreachable(); } - void empty_visitor::visit(named_type_expression *) + void empty_visitor::visit(type_expression *) { not_implemented(); } @@ -149,7 +149,7 @@ namespace elna::frontend not_implemented(); } - void empty_visitor::visit(variable_expression *) + void empty_visitor::visit(named_expression *) { not_implemented(); } @@ -253,12 +253,7 @@ namespace elna::frontend return nullptr; } - type_expression::type_expression(const struct position position) - : node(position) - { - } - - named_type_expression *type_expression::is_named() + named_expression *type_expression::is_named() { return nullptr; } @@ -293,24 +288,46 @@ namespace elna::frontend return nullptr; } - named_type_expression::named_type_expression(const struct position position, const std::string& name) - : type_expression(position), name(name) + 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(); } - void named_type_expression::accept(parser_visitor *visitor) - { - visitor->visit(this); - } - - named_type_expression *named_type_expression::is_named() + type_expression::~type_expression() { - return this; } array_type_expression::array_type_expression(const struct position position, type_expression *base, const std::uint32_t size) - : type_expression(position), m_base(base), size(size) + : node(position), m_base(base), size(size) { } @@ -336,7 +353,7 @@ namespace elna::frontend pointer_type_expression::pointer_type_expression(const struct position position, type_expression *base) - : type_expression(position), m_base(base) + : node(position), m_base(base) { } @@ -362,7 +379,7 @@ namespace elna::frontend record_type_expression::record_type_expression(const struct position position, std::vector<field_declaration>&& fields) - : type_expression(position), fields(std::move(fields)) + : node(position), fields(std::move(fields)) { } @@ -386,7 +403,7 @@ namespace elna::frontend union_type_expression::union_type_expression(const struct position position, std::vector<field_declaration>&& fields) - : type_expression(position), fields(std::move(fields)) + : node(position), fields(std::move(fields)) { } @@ -464,7 +481,7 @@ namespace elna::frontend } procedure_type_expression::procedure_type_expression(const struct position position, return_t return_type) - : type_expression(position), return_type(return_type) + : node(position), return_type(return_type) { } @@ -491,7 +508,7 @@ namespace elna::frontend } enumeration_type_expression::enumeration_type_expression(const struct position position, std::vector<std::string>&& members) - : type_expression(position), members(members) + : node(position), members(members) { } @@ -559,6 +576,11 @@ namespace elna::frontend { } + block::block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& 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)) @@ -657,10 +679,6 @@ namespace elna::frontend } } - literal_expression::literal_expression() - { - } - literal_expression *literal_expression::is_literal() { return this; @@ -684,10 +702,6 @@ namespace elna::frontend } } - designator_expression::designator_expression() - { - } - designator_expression::~designator_expression() { } @@ -699,7 +713,7 @@ namespace elna::frontend void designator_expression::accept(parser_visitor *visitor) { - if (variable_expression *node = is_variable()) + if (named_expression *node = is_named()) { return visitor->visit(node); } @@ -718,17 +732,17 @@ namespace elna::frontend __builtin_unreachable(); } - variable_expression::variable_expression(const struct position position, const std::string& name) + named_expression::named_expression(const struct position position, const std::string& name) : node(position), name(name) { } - void variable_expression::accept(parser_visitor *visitor) + void named_expression::accept(parser_visitor *visitor) { visitor->visit(this); } - variable_expression *variable_expression::is_variable() + named_expression *named_expression::is_named() { return this; } @@ -1039,7 +1053,7 @@ namespace elna::frontend visitor->visit(this); } - variable_expression *designator_expression::is_variable() + named_expression *designator_expression::is_named() { return nullptr; } diff --git a/frontend/dependency.cc b/boot/dependency.cc index 25658f8..6b10611 100644 --- a/frontend/dependency.cc +++ b/boot/dependency.cc @@ -15,17 +15,17 @@ 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 "elna/frontend/dependency.h" +#include "elna/boot/dependency.h" #include <fstream> #include <sstream> #include <string.h> -#include "elna/frontend/driver.h" -#include "elna/frontend/semantic.h" +#include "elna/boot/driver.h" +#include "elna/boot/semantic.h" #include "parser.hh" -namespace elna::frontend +namespace elna::boot { dependency::dependency(const char *path) : error_container(path) diff --git a/frontend/driver.cc b/boot/driver.cc index 1c20d09..abbf0f1 100644 --- a/frontend/driver.cc +++ b/boot/driver.cc @@ -15,9 +15,9 @@ 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 "elna/frontend/driver.h" +#include "elna/boot/driver.h" -namespace elna::frontend +namespace elna::boot { position make_position(const yy::location& location) { @@ -50,10 +50,6 @@ namespace elna::frontend { case 'n': return '\n'; - case 'a': - return '\a'; - case 'b': - return '\b'; case 't': return '\t'; case 'f': @@ -68,8 +64,6 @@ namespace elna::frontend return '\''; case '"': return '"'; - case '?': - return '\?'; case '0': return '\0'; default: diff --git a/frontend/lexer.ll b/boot/lexer.ll index f14497b..fac70f0 100644 --- a/frontend/lexer.ll +++ b/boot/lexer.ll @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "parser.hh" #undef YY_DECL -#define YY_DECL yy::parser::symbol_type elna::frontend::lexer::lex(driver& driver) +#define YY_DECL yy::parser::symbol_type elna::boot::lexer::lex(driver& driver) #define yyterminate() return yy::parser::make_YYEOF(this->location) %} @@ -130,12 +130,6 @@ or { return { return yy::parser::make_RETURN(this->location); } -module { - return yy::parser::make_MODULE(this->location); -} -program { - return yy::parser::make_PROGRAM(this->location); -} import { return yy::parser::make_IMPORT(this->location); } @@ -181,7 +175,7 @@ of { return yy::parser::make_INTEGER(result, this->location); } } -0x{HIGIT}+ { +0[x|X]{HIGIT}+ { unsigned long result = strtoul(yytext, NULL, 16); if (errno == ERANGE) @@ -193,7 +187,7 @@ of { return yy::parser::make_WORD(result, this->location); } } -0b{BIGIT}+ { +0[b|B]{BIGIT}+ { unsigned long result = strtoul(yytext, NULL, 2); if (errno == ERANGE) 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 +<http://www.gnu.org/licenses/>. */ + +%require "3.4" +%language "c++" + +%code { + using namespace elna; +} + +%code requires { + #include <cstdint> + #include <iostream> + #include "elna/boot/driver.h" + + #if !defined(yyFlexLexerOnce) + #include <FlexLexer.h> + #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 <std::string> IDENTIFIER +%token <std::string> TRAIT +%token <std::int32_t> INTEGER +%token <std::uint32_t> WORD +%token <float> FLOAT +%token <std::string> CHARACTER +%token <std::string> STRING +%token <bool> 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 <elna::boot::literal_expression *> literal; +%type <std::vector<elna::boot::expression *>> case_labels; +%type <elna::boot::switch_case> switch_case; +%type <std::vector<elna::boot::switch_case>> switch_cases; +%type <elna::boot::constant_declaration *> constant_declaration; +%type <std::vector<elna::boot::constant_declaration *>> constant_part constant_declarations; +%type <elna::boot::variable_declaration *> variable_declaration; +%type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part; +%type <elna::boot::type_expression *> type_expression; +%type <std::vector<elna::boot::type_expression *>> type_expressions; +%type <elna::boot::traits_expression *> traits_expression; +%type <elna::boot::expression *> expression operand simple_expression; +%type <elna::boot::unary_expression *> unary_expression; +%type <elna::boot::binary_expression *> binary_expression; +%type <std::vector<elna::boot::expression *>> expressions actual_parameter_list; +%type <elna::boot::designator_expression *> designator_expression; +%type <elna::boot::procedure_call*> call_expression; +%type <elna::boot::return_statement *> return_statement; +%type <elna::boot::statement *> statement; +%type <std::vector<elna::boot::statement *>> required_statements optional_statements; +%type <std::unique_ptr<std::vector<elna::boot::statement *>>> statement_part; +%type <elna::boot::procedure_declaration *> procedure_declaration; +%type <std::pair<std::vector<std::string>, elna::boot::procedure_type_expression *>> procedure_heading; +%type <elna::boot::procedure_type_expression::return_t> return_declaration; +%type <std::vector<elna::boot::procedure_declaration *>> procedure_part; +%type <elna::boot::type_declaration *> type_declaration; +%type <std::vector<elna::boot::type_declaration *>> type_declarations type_part; +%type <std::unique_ptr<elna::boot::block>> block; +%type <elna::boot::field_declaration> field_declaration formal_parameter; +%type <std::vector<std::pair<std::string, elna::boot::type_expression *>>> + optional_fields required_fields formal_parameters formal_parameter_list; +%type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements; +%type <std::vector<elna::boot::statement *> *> else_statements; +%type <elna::boot::cast_expression *> cast_expression; +%type <elna::boot::identifier_definition> identifier_definition; +%type <std::vector<elna::boot::identifier_definition>> identifier_definitions; +%type <std::vector<std::string>> identifiers import_declaration; +%type <std::vector<elna::boot::import_declaration *>> 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<boot::block>(std::move($1), std::move($2), std::move(*$3.release())); + } + else + { + $$ = std::make_unique<boot::block>(std::move($1), std::move($2)); + } + } +statement_part: + /* no statements */ {} + | "begin" required_statements { $$ = std::make_unique<std::vector<boot::statement *>>(std::move($2));; } + | return_statement + { + $$ = std::make_unique<std::vector<boot::statement *>>(std::vector<boot::statement *>{ $1 }); + } + | "begin" required_statements ";" return_statement + { + $$ = std::make_unique<std::vector<boot::statement *>>(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<boot::statement *>(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<std::int32_t>(boot::make_position(@1), $1); } + | WORD { $$ = new boot::literal<std::uint32_t>(boot::make_position(@1), $1); } + | FLOAT { $$ = new boot::literal<double>(boot::make_position(@1), $1); } + | BOOLEAN { $$ = new boot::literal<bool>(boot::make_position(@1), $1); } + | CHARACTER { $$ = new boot::literal<unsigned char>(boot::make_position(@1), $1.at(0)); } + | "nil" { $$ = new boot::literal<std::nullptr_t>(boot::make_position(@1), nullptr); } + | STRING { $$ = new boot::literal<std::string>(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<boot::type_expression> shared_type{ $3 }; + $$ = new boot::variable_declaration( boot::make_position(@2), std::move($1), shared_type); + } + | identifier_definitions ":" type_expression ":=" "extern" + { + std::shared_ptr<boot::type_expression> 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<boot::type_expression> 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<boot::syntax_error>(message, driver.input_file, loc); +} diff --git a/frontend/result.cc b/boot/result.cc index aca9c5e..dab82f4 100644 --- a/frontend/result.cc +++ b/boot/result.cc @@ -15,9 +15,9 @@ 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 "elna/frontend/result.h" +#include "elna/boot/result.h" -namespace elna::frontend +namespace elna::boot { error::error(const char *path, const struct position position) : position(position), path(path) @@ -60,8 +60,8 @@ namespace elna::frontend } } -std::size_t std::hash<elna::frontend::identifier_definition>::operator()( - const elna::frontend::identifier_definition& key) const +std::size_t std::hash<elna::boot::identifier_definition>::operator()( + const elna::boot::identifier_definition& key) const { return std::hash<std::string>{}(key.name); } diff --git a/frontend/semantic.cc b/boot/semantic.cc index 36c75b8..3ccc81b 100644 --- a/frontend/semantic.cc +++ b/boot/semantic.cc @@ -15,12 +15,12 @@ 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 "elna/frontend/semantic.h" +#include "elna/boot/semantic.h" #include <algorithm> #include <set> -namespace elna::frontend +namespace elna::boot { undeclared_error::undeclared_error(const std::string& identifier, const char *path, const struct position position) : error(path, position), identifier(identifier) @@ -223,10 +223,20 @@ namespace elna::frontend { visit(static_cast<unit *>(program)); + this->bag.enter(); + auto variable_type = this->bag.lookup("Int")->is_type()->symbol; + this->bag.enter("count", std::make_shared<variable_info>(variable_type, false)); + + variable_type = this->bag.lookup("Char")->is_type()->symbol; + variable_type = type(std::make_shared<pointer_type>(variable_type)); + variable_type = type(std::make_shared<pointer_type>(variable_type)); + this->bag.enter("parameters", std::make_shared<variable_info>(variable_type, false)); + for (statement *const statement : program->body) { statement->accept(this); } + this->bag.leave(); } void name_analysis_visitor::visit(type_declaration *definition) @@ -239,23 +249,8 @@ namespace elna::frontend this->bag.enter(definition->identifier.name, info); } - void name_analysis_visitor::visit(named_type_expression *type_expression) + void name_analysis_visitor::visit(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)) - { - this->current_type = from_symbol_table->is_type()->symbol; - } - else - { - add_error<undeclared_error>(type_expression->name, this->input_file, type_expression->position()); - this->current_type = type(); - } } void name_analysis_visitor::visit(pointer_type_expression *type_expression) @@ -267,7 +262,9 @@ namespace elna::frontend void name_analysis_visitor::visit(array_type_expression *type_expression) { type_expression->base().accept(this); - this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size)); + auto result_type{ std::make_shared<array_type>(this->current_type, type_expression->size) }; + + this->current_type = type(result_type); } std::vector<type_field> name_analysis_visitor::build_composite_type(const std::vector<field_declaration>& fields) @@ -324,20 +321,27 @@ namespace elna::frontend this->current_type = type(result_type); } + std::shared_ptr<variable_info> name_analysis_visitor::register_variable(const std::string& name, + const bool is_extern, const struct position position) + { + auto variable_symbol = std::make_shared<variable_info>(this->current_type, is_extern); + + if (!this->bag.enter(name, variable_symbol)) + { + add_error<already_declared_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 = std::make_shared<variable_info>(this->current_type, declaration->is_extern); - + auto variable_symbol = register_variable(variable_identifier.name, declaration->is_extern, + declaration->position()); variable_symbol->exported = variable_identifier.exported; - if (!this->bag.enter(variable_identifier.name, variable_symbol)) - { - add_error<already_declared_error>(variable_identifier.name, this->input_file, - declaration->position()); - } } } @@ -358,7 +362,19 @@ namespace elna::frontend if (definition->body.has_value()) { info = std::make_shared<procedure_info>(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); @@ -489,6 +505,10 @@ namespace elna::frontend { variable->accept(this); } + for (constant_declaration *const constant : unit->constants) + { + constant->accept(this); + } for (procedure_declaration *const procedure : unit->procedures) { procedure->accept(this); @@ -522,8 +542,26 @@ namespace elna::frontend expression->operand().accept(this); } - void name_analysis_visitor::visit(variable_expression *) + 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<undeclared_error>(type_expression->name, this->input_file, type_expression->position()); + this->current_type = type(); + } } void name_analysis_visitor::visit(array_access_expression *expression) diff --git a/frontend/symbol.cc b/boot/symbol.cc index bfecbd4..902d331 100644 --- a/frontend/symbol.cc +++ b/boot/symbol.cc @@ -15,9 +15,9 @@ 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 "elna/frontend/symbol.h" +#include "elna/boot/symbol.h" -namespace elna::frontend +namespace elna::boot { type::type() { diff --git a/doc/appendix.tex b/doc/appendix.tex index 0777d55..09bdbde 100644 --- a/doc/appendix.tex +++ b/doc/appendix.tex @@ -14,14 +14,14 @@ <binary-digit> = `0' | `1'. -<hex-character> = `\\x' <hex-digit> <hex-digit>. +<hex-character> = `\\x' <hex-digit> \{<hex-digit>\}. <escaped-character> = `\\' \\ - (`n' | `a' | `b' | `t' | `f' | `r' | `v' | `\\' | `\textquotesingle' | `\textquotedbl' | `?\@' | `0'). + (`n' | `t' | `f' | `r' | `v' | `\\' | `\textquotesingle' | `\textquotedbl' | `0'). <printable-character> = \enspace? a printable ASCII character\space?. -<character> = <printable-character> | <escaped-character> | <hex-digit>. +<character> = <printable-character> | <escaped-character> | <hex-character>. <identifier> = <letter> \{<letter> | <decimal-digit>\}. @@ -38,10 +38,10 @@ <real-literal> = <integer-literal> `.\@' <decimal-digit> \{<decimal-digit>\} \alt{} <integer-literal>\} `e' [`+' | `-'] <decimal-digit> \{<decimal-digit>\}. -<string-literal> = `\textquotedbl' \{<character>\} `\textquotedbl'. - <character-literal> = `\textquotesingle' <character> `\textquotesingle'. +<string-literal> = `\textquotedbl' \{<character>\} `\textquotedbl'. + <literal> = <integer-literal> | <word-literal> | <real-literal> \alt{} <string-literal> | <character-literal> \alt{} `true' | `false' | `nil'. diff --git a/doc/language.tex b/doc/language.tex index 9112127..36ee877 100644 --- a/doc/language.tex +++ b/doc/language.tex @@ -10,10 +10,179 @@ Each procedure can get some input and produce an output as a result of executing a \textbf{statement block}, a list, where each \textbf{statement} is executed in the order it appears in the block. -Statement components are other statement blocks and \textbf{expressions}, -where a statement has control over the evaluation of its components. -Statements can also modify the state of the procedure or the program by -mutating variables. +\chapter{Vocabulary} + +A language is an infinite set of sentences, namely the sentences well formed +according to its syntax. In Elna, these sentences are called compilation units. +Each unit is a finite sequence of \textit{tokens} from a finite vocabulary. +The vocabulary of Elna consists of identifiers, reserved words, numbers, characters, +strings, operators, delimiters, and comments. They are called \textit{tokens} +and are composed of sequences of characters. + +The following lexical rules must be observed when composing tokens. Blanks and +line breaks must not occur within tokens (except in comments and strings). They +are ignored unless they are essential to separate two consecutive tokens. +Capital and lower-case letters are considered as being distinct. + +\section{Identifiers} + +\textit{Identifiers} are sequences of letters, digits and underscores. The first +character must be a letter or an underscore. + +\begin{grammar} +<identifier> = <letter> \{<letter> | <decimal-digit>\}. +\end{grammar} + +Examples: + +\begin{itemize} + \item \verb|x| + \item \verb|TypeName| + \item \verb|procedure_name| +\end{itemize} + +\section{Numbers} + +Numbers are signed or unsigned integers, or real numbers. Integers may be +preceded by a prefix and followed by a suffix. The prefixes \verb|0x| and +\verb|0X| indicate hexadecimal representation, \verb|0b| and \verb|0B| +indicate binary representation. Unsigned integers have the suffix \verb|u|, +signed integers have no suffix. + +A \textit{real number} always contains a decimal point. Optionally it may +also contain a decimal scale factor. The letters \verb|e| or \verb|E| is +pronounced as `times ten to the power of'. + +\begin{grammar} +<integer-literal> = `0' | <counting-digit> \{<decimal-digit>\}. + +<word-literal> = <integer-literal> `u' + \alt{} `0' (`X' | `x') <hex-digit> \{<hex-digit>\} + \alt{} `0' (`B' | `b') <binary-digit> \{<binary-digit>\}. + +<real-literal> = <integer-literal> `.\@' <decimal-digit> \{<decimal-digit>\} + \alt{} <integer-literal>\} `e' [`+' | `-'] <decimal-digit> \{<decimal-digit>\}. +\end{grammar} + +Examples: + +\begin{itemize} + \item 2016 + \item 1987u + \item 0xff + \item 0b101 + \item 0.5 + \item 4.567e8 +\end{itemize} + +\section{Strings and characters} + +Single \textit{characters} are enclosed in single quotation marks +(\textquotesingle).\@ \textit{Strings} are sequences of characters enclosed in +double quotation marks (\textquotedbl). The number of characters in a string is +called the \textit{the length} of the string. + +\begin{grammar} +<escaped-character> = `\\' \\ + (`n' | `t' | `f' | `r' | `v' | `\\' | `\textquotesingle' | `\textquotedbl' | `0'). + +<hex-character> = `\\x' <hex-digit> \{<hex-digit>\}. + +<character> = <printable-character> | <escaped-character> | <hex-character>. + +<character-literal> = `\textquotesingle' <character> `\textquotesingle'. + +<string-literal> = `\textquotedbl' \{<character>\} `\textquotedbl'. +\end{grammar} + +Alternatively, a single character may be represented by a +\textit{escape sequence} (see~\ref{table:escape}), a character combination +beginning with a backslash (\textbackslash). + +\begin{table}[ht] +\centering +\begin{tabular}{r l} + \textbf{Sequence} & \textbf{Meaning} \\ + \toprule + \verb|\n| & Newline \\ + \midrule + \verb|\t| & Horizontal tab \\ + \midrule + \verb|\f| & Form feed \\ + \midrule + \verb|\r| & Carriage return \\ + \midrule + \verb|\v| & Vertical tab \\ + \midrule + \verb|\\| & Backslash \\ + \midrule + \verb|\'| & Single quote \\ + \midrule + \verb|\"| & Double quote \\ + \midrule + \verb|\0| & Null character \\ + \midrule + \verb|\xh…| & Arbitrary hexadecimal value, where \verb|n| is a hexadecimal digit \\ + \bottomrule +\end{tabular} +\caption{Escape sequences}\label{table:escape} +\end{table} + +Examples: + +\begin{itemize} + \item \verb|"String"| + \item \verb|'c'| + \item \verb|'\''| + \item \verb|"\"multi\nline\nquoted\nstring\""| +\end{itemize} + +\section{Operators and delimiters} + +\textit{Operators} and \textit{delimiters} are the special characters, character +pairs, or reserved words listed below. These reserved words consist exclusively +of letters and cannot be used in the role of identifiers. + +\begin{itemize} + \item{}:= + \item $@\quad\hat{}\quad\sim$ + \item $.\quad,\quad;\quad:\quad|$ + \item $<\quad>\quad>=\quad<=\quad<>\quad=$ + \item $+\quad-\quad*\quad/$ + \item $or\quad{}xor\quad\&$ + \item (\ and\ ) + \item \lbrack{} and \rbrack{} + \item \{ and \} + \item Pointer + \item module + \item import + \item type + \item const + \item var + \item begin + \item end + \item proc + \item record + \item while + \item do + \item case + \item of + \item if + \item then + \item elsif + \item else + \item cast + \item return + \item true + \item false + \item nil +\end{itemize} + +\section{Comments} + +\textit{Comments} may be inserted between any two tokens in a program. They +are arbitrary character sequences opened by the bracket \verb|(*| and closed +by \verb|*)|. Comments do not affect the meaning of a program. \chapter{Expressions} @@ -335,5 +504,21 @@ relations $=$ and $<>$ apply to all types. \chapter{Statements} +\begin{grammar} +<statement> = <assignment> | <procedure-call> | <defer-statement> + | <label-declaration> | <goto-statement> | + | <while-statement> | <if-statement> | <case-statement>. +\end{grammar} + +Statements denote actions. There are elementary and structured statements. +Elementary statements are not composed of any parts that are themselves +statements. They are the assignment and the procedure call. Structured +statements are composed of parts that are themselves statements. They +are used to express sequencing and conditional, selective, and +repetitive execution. A statement may also be empty, in which case it +denotes no action. The empty statement is included in order to relax +punctuation rules in statement sequences. + +\section{Elementary statements} \section{Conditional statements} \section{Loop statements} diff --git a/frontend/parser.yy b/frontend/parser.yy deleted file mode 100644 index bace8d7..0000000 --- a/frontend/parser.yy +++ /dev/null @@ -1,594 +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 -<http://www.gnu.org/licenses/>. */ - -%require "3.4" -%language "c++" - -%code { - using namespace elna; -} - -%code requires { - #include <cstdint> - #include <iostream> - #include "elna/frontend/driver.h" - - #if !defined(yyFlexLexerOnce) - #include <FlexLexer.h> - #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 <std::string> IDENTIFIER -%token <std::string> TRAIT -%token <std::int32_t> INTEGER -%token <std::uint32_t> WORD -%token <float> FLOAT -%token <std::string> CHARACTER -%token <std::string> STRING -%token <bool> 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" - PROGRAM "program" - MODULE "module" - 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 <elna::frontend::literal_expression *> literal; -%type <std::vector<elna::frontend::expression *>> case_labels; -%type <elna::frontend::switch_case> switch_case; -%type <std::vector<elna::frontend::switch_case>> switch_cases; -%type <elna::frontend::constant_declaration *> constant_declaration; -%type <std::vector<elna::frontend::constant_declaration *>> constant_part constant_declarations; -%type <elna::frontend::variable_declaration *> variable_declaration; -%type <std::vector<elna::frontend::variable_declaration *>> variable_declarations variable_part; -%type <elna::frontend::type_expression *> type_expression; -%type <std::vector<elna::frontend::type_expression *>> type_expressions; -%type <elna::frontend::traits_expression *> traits_expression; -%type <elna::frontend::expression *> expression operand simple_expression; -%type <elna::frontend::unary_expression *> unary_expression; -%type <elna::frontend::binary_expression *> binary_expression; -%type <std::vector<elna::frontend::expression *>> expressions actual_parameter_list; -%type <elna::frontend::designator_expression *> designator_expression; -%type <elna::frontend::procedure_call*> call_expression; -%type <elna::frontend::return_statement *> return_statement; -%type <elna::frontend::statement *> statement; -%type <std::vector<elna::frontend::statement *>> required_statements optional_statements statement_part; -%type <elna::frontend::procedure_declaration *> procedure_declaration; -%type <std::pair<std::vector<std::string>, elna::frontend::procedure_type_expression *>> procedure_heading; -%type <elna::frontend::procedure_type_expression::return_t> return_declaration; -%type <std::vector<elna::frontend::procedure_declaration *>> procedure_declarations procedure_part; -%type <elna::frontend::type_declaration *> type_declaration; -%type <std::vector<elna::frontend::type_declaration *>> type_declarations type_part; -%type <std::unique_ptr<elna::frontend::block>> block; -%type <elna::frontend::field_declaration> field_declaration formal_parameter; -%type <std::vector<std::pair<std::string, elna::frontend::type_expression *>>> - optional_fields required_fields formal_parameters formal_parameter_list; -%type <std::vector<elna::frontend::conditional_statements *>> elsif_then_statements elsif_do_statements; -%type <std::vector<elna::frontend::statement *> *> else_statements; -%type <elna::frontend::cast_expression *> cast_expression; -%type <elna::frontend::identifier_definition> identifier_definition; -%type <std::vector<elna::frontend::identifier_definition>> identifier_definitions; -%type <std::vector<std::string>> identifiers import_declaration; -%type <std::vector<elna::frontend::import_declaration *>> import_declarations import_part; -%% -program: - "program" ";" import_part constant_part type_part variable_part procedure_part statement_part "end" "." - { - auto tree = new frontend::program(frontend::make_position(@1)); - - std::swap(tree->imports, $3); - std::swap(tree->constants, $4); - std::swap(tree->types , $5); - std::swap(tree->variables, $6); - std::swap(tree->procedures, $7); - std::swap(tree->body, $8); - - driver.tree.reset(tree); - } - | "module" ";" import_part constant_part type_part variable_part procedure_part "end" "." - { - auto tree = new frontend::unit(frontend::make_position(@1)); - - std::swap(tree->imports, $3); - std::swap(tree->constants, $4); - std::swap(tree->types , $5); - std::swap(tree->variables, $6); - std::swap(tree->procedures, $7); - - driver.tree.reset(tree); - } -block: constant_part variable_part statement_part "end" - { - $$ = std::make_unique<frontend::block>(std::move($1), std::move($2), std::move($3)); - } -statement_part: - /* no statements */ {} - | "begin" required_statements { std::swap($$, $2); } - | return_statement { $$.push_back($1); } - | "begin" required_statements ";" return_statement - { - std::swap($$, $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(*$5)); - 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_declarations: - procedure_declaration procedure_declarations - { - std::swap($$, $2); - $$.emplace($$.cbegin(), std::move($1)); - } - | procedure_declaration { $$.emplace_back(std::move($1)); } -procedure_part: - /* no procedure definitions */ {} - | procedure_declarations { std::swap($$, $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<frontend::statement *>(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<std::int32_t>(frontend::make_position(@1), $1); } - | WORD { $$ = new frontend::literal<std::uint32_t>(frontend::make_position(@1), $1); } - | FLOAT { $$ = new frontend::literal<double>(frontend::make_position(@1), $1); } - | BOOLEAN { $$ = new frontend::literal<bool>(frontend::make_position(@1), $1); } - | CHARACTER { $$ = new frontend::literal<unsigned char>(frontend::make_position(@1), $1.at(0)); } - | "nil" { $$ = new frontend::literal<std::nullptr_t>(frontend::make_position(@1), nullptr); } - | STRING { $$ = new frontend::literal<std::string>(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::variable_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_type_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<frontend::type_expression> shared_type{ $3 }; - $$ = new frontend::variable_declaration( frontend::make_position(@2), std::move($1), shared_type); - } - | identifier_definitions ":" type_expression ":=" "extern" ";" - { - std::shared_ptr<frontend::type_expression> 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<frontend::type_expression> 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<frontend::syntax_error>(message, driver.input_file, loc); -} 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<symbol_table> builtin_symbol_table() { - std::shared_ptr<elna::gcc::symbol_table> symbol_table = std::make_shared<elna::gcc::symbol_table>(); + auto builtin_table = std::make_shared<symbol_table>(); - 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<frontend::type_field>& fields, tree composite_type_node, + tree build_composite_type(const std::vector<boot::type_field>& fields, tree composite_type_node, std::shared_ptr<symbol_table> 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<symbol_table> symbols) + tree build_procedure_type(const boot::procedure_type& procedure, std::shared_ptr<symbol_table> symbols) { std::vector<tree> 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<symbol_table> symbols) + tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols) { - if (auto reference = type.get<frontend::primitive_type>()) + if (auto reference = type.get<boot::primitive_type>()) { auto looked_up = symbols->lookup(reference->identifier); gcc_assert(looked_up != NULL_TREE); return TREE_TYPE(looked_up); } - else if (auto reference = type.get<frontend::record_type>()) + else if (auto reference = type.get<boot::record_type>()) { 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<frontend::union_type>()) + else if (auto reference = type.get<boot::union_type>()) { 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<frontend::enumeration_type>()) + else if (auto reference = type.get<boot::enumeration_type>()) { return build_enumeration_type(reference->members); } - else if (auto reference = type.get<frontend::pointer_type>()) + else if (auto reference = type.get<boot::pointer_type>()) { return build_global_pointer_type(get_inner_alias(reference->base, symbols)); } - else if (auto reference = type.get<frontend::array_type>()) + else if (auto reference = type.get<boot::array_type>()) { tree base = get_inner_alias(reference->base, symbols); return build_static_array_type(base, reference->size); } - else if (auto reference = type.get<frontend::procedure_type>()) + else if (auto reference = type.get<boot::procedure_type>()) { auto procedure = build_procedure_type(*reference, symbols); return build_global_pointer_type(procedure); } - else if (auto reference = type.get<frontend::alias_type>()) + else if (auto reference = type.get<boot::alias_type>()) { return TREE_TYPE(handle_symbol(reference->name, reference, symbols)); } return error_mark_node; } - tree handle_symbol(const std::string& symbol_name, std::shared_ptr<frontend::alias_type> reference, + tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::alias_type> reference, std::shared_ptr<symbol_table> 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<symbol_table> symbols) { tree declaration_type = gcc::build_procedure_type(info.symbol, symbols); @@ -210,7 +210,7 @@ namespace elna::gcc std::vector<std::string>::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<symbol_table> 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<symbol_table> symbols) + void declare_type(const std::string& name, const boot::type_info& info, std::shared_ptr<symbol_table> symbols) { // The top level symbol table has basic (builtin) types in it which are not aliases. - if (auto alias_type = info.symbol.get<frontend::alias_type>()) + if (auto alias_type = info.symbol.get<boot::alias_type>()) { tree type_declaration = handle_symbol(name, alias_type, symbols); @@ -253,7 +253,7 @@ namespace elna::gcc } } - void rewrite_symbol_table(std::shared_ptr<frontend::symbol_table> info_table, std::shared_ptr<symbol_table> symbols) + void rewrite_symbol_table(std::shared_ptr<boot::symbol_table> info_table, std::shared_ptr<symbol_table> 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<std::unique_ptr<frontend::error>>& errors) + void report_errors(const std::deque<std::unique_ptr<boot::error>>& 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 b37b111..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> symbol_table, elna::frontend::symbol_bag bag) + generic_visitor::generic_visitor(std::shared_ptr<symbol_table> 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<frontend::expression *>& arguments) + tree procedure_address, const std::vector<boot::expression *>& arguments) { vec<tree, va_gc> *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<frontend::expression *>& arguments) + tree symbol, const std::vector<boot::expression *>& arguments) { vec<constructor_elt, va_gc> *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<frontend::expression *>& arguments) + const std::vector<boot::expression *>& 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::variable_expression *named_call = call->callable().is_variable()) + 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<frontend::unit *>(program)); + visit(static_cast<boot::unit *>(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<std::int32_t> *literal) + void generic_visitor::visit(boot::literal<std::int32_t> *literal) { this->current_expression = build_int_cst(elna_int_type_node, literal->value); } - void generic_visitor::visit(frontend::literal<std::uint32_t> *literal) + void generic_visitor::visit(boot::literal<std::uint32_t> *literal) { this->current_expression = build_int_cstu(elna_word_type_node, literal->value); } - void generic_visitor::visit(frontend::literal<double> *literal) + void generic_visitor::visit(boot::literal<double> *literal) { REAL_VALUE_TYPE real_value1; @@ -406,22 +406,22 @@ namespace elna::gcc mpfr_clear(number); } - void generic_visitor::visit(frontend::literal<bool> *boolean) + void generic_visitor::visit(boot::literal<bool> *boolean) { this->current_expression = boolean->value ? boolean_true_node : boolean_false_node; } - void generic_visitor::visit(frontend::literal<unsigned char> *character) + void generic_visitor::visit(boot::literal<unsigned char> *character) { this->current_expression = build_int_cstu(elna_char_type_node, character->value); } - void generic_visitor::visit(frontend::literal<nullptr_t> *) + void generic_visitor::visit(boot::literal<nullptr_t> *) { this->current_expression = elna_pointer_nil_node; } - void generic_visitor::visit(frontend::literal<std::string> *string) + void generic_visitor::visit(boot::literal<std::string> *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::variable_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); @@ -1023,7 +1023,7 @@ namespace elna::gcc if (TREE_CODE(lvalue) == CONST_DECL) { error_at(statement_location, "Cannot modify constant '%s'", - statement->lvalue().is_variable()->name.c_str()); + statement->lvalue().is_named()->name.c_str()); } else if (TYPE_READONLY(TREE_TYPE(lvalue))) { @@ -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<frontend::statement *>& statements) + void generic_visitor::visit_statements(const std::vector<boot::statement *>& 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 <fstream> -#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<std::shared_ptr<elna::gcc::symbol_table>>; +using dependency_state = elna::boot::dependency_state<std::shared_ptr<elna::gcc::symbol_table>>; -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<std::filesystem::path, elna::frontend::symbol_bag>::const_iterator cached_import = + std::filesystem::path sub_path = "source" / elna::boot::build_path(sub_tree->segments); + std::unordered_map<std::filesystem::path, elna::boot::symbol_bag>::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/frontend/ast.h b/include/elna/boot/ast.h index bbb8a36..7d94e84 100644 --- a/include/elna/frontend/ast.h +++ b/include/elna/boot/ast.h @@ -22,10 +22,10 @@ along with GCC; see the file COPYING3. If not see #include <string> #include <vector> #include <optional> -#include "elna/frontend/symbol.h" -#include "elna/frontend/result.h" +#include "elna/boot/symbol.h" +#include "elna/boot/result.h" -namespace elna::frontend +namespace elna::boot { enum class binary_operator { @@ -71,14 +71,14 @@ namespace elna::frontend class program; class binary_expression; class unary_expression; - class named_type_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 variable_expression; + class named_expression; class array_access_expression; class field_access_expression; class dereference_expression; @@ -111,14 +111,14 @@ namespace elna::frontend 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(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(named_expression *) = 0; virtual void visit(array_access_expression *) = 0; virtual void visit(field_access_expression *) = 0; virtual void visit(dereference_expression *) = 0; @@ -139,7 +139,7 @@ namespace elna::frontend [[noreturn]] void not_implemented(); public: - [[noreturn]] virtual void visit(named_type_expression *) override; + [[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; @@ -165,7 +165,7 @@ namespace elna::frontend [[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(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; @@ -232,10 +232,10 @@ namespace elna::frontend /** * Some type expression. */ - class type_expression : public node + class type_expression : public virtual node { public: - virtual named_type_expression *is_named(); + virtual named_expression *is_named(); virtual array_type_expression *is_array(); virtual pointer_type_expression *is_pointer(); virtual record_type_expression *is_record(); @@ -243,21 +243,8 @@ namespace elna::frontend 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; + ~type_expression() = 0; }; class array_type_expression : public type_expression @@ -363,9 +350,6 @@ namespace elna::frontend { public: literal_expression *is_literal() override; - - protected: - literal_expression(); }; /** @@ -407,6 +391,7 @@ namespace elna::frontend { block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables, std::vector<statement *>&& body); + block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables); block(const block&) = delete; block(block&& that); @@ -553,7 +538,7 @@ namespace elna::frontend class designator_expression : public expression { public: - virtual variable_expression *is_variable(); + virtual named_expression *is_named(); virtual array_access_expression *is_array_access(); virtual field_access_expression *is_field_access(); virtual dereference_expression *is_dereference(); @@ -561,20 +546,20 @@ namespace elna::frontend 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 + /** + * Expression refering to an entity by its name. + */ + class named_expression : public designator_expression, public type_expression { public: const std::string name; - variable_expression(const struct position position, const std::string& name); + named_expression(const struct position position, const std::string& name); void accept(parser_visitor *visitor) override; - variable_expression *is_variable() override; + named_expression *is_named() override; }; class array_access_expression : public designator_expression diff --git a/include/elna/frontend/dependency.h b/include/elna/boot/dependency.h index f1502d1..4ec4d44 100644 --- a/include/elna/frontend/dependency.h +++ b/include/elna/boot/dependency.h @@ -19,11 +19,11 @@ along with GCC; see the file COPYING3. If not see #include <filesystem> #include <fstream> -#include "elna/frontend/result.h" -#include "elna/frontend/ast.h" -#include "elna/frontend/symbol.h" +#include "elna/boot/result.h" +#include "elna/boot/ast.h" +#include "elna/boot/symbol.h" -namespace elna::frontend +namespace elna::boot { class dependency : public error_container { diff --git a/include/elna/frontend/driver.h b/include/elna/boot/driver.h index 66ef579..288aa0c 100644 --- a/include/elna/frontend/driver.h +++ b/include/elna/boot/driver.h @@ -18,10 +18,10 @@ along with GCC; see the file COPYING3. If not see #pragma once #include <optional> -#include "elna/frontend/ast.h" +#include "elna/boot/ast.h" #include "location.hh" -namespace elna::frontend +namespace elna::boot { position make_position(const yy::location& location); diff --git a/include/elna/frontend/result.h b/include/elna/boot/result.h index 7e5ed77..9fc1849 100644 --- a/include/elna/frontend/result.h +++ b/include/elna/boot/result.h @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see #include <memory> #include <variant> -namespace elna::frontend +namespace elna::boot { /** * Position in the source text. @@ -118,7 +118,7 @@ namespace elna::frontend } template<> -struct std::hash<elna::frontend::identifier_definition> +struct std::hash<elna::boot::identifier_definition> { - std::size_t operator()(const elna::frontend::identifier_definition& key) const noexcept; + std::size_t operator()(const elna::boot::identifier_definition& key) const noexcept; }; diff --git a/include/elna/frontend/semantic.h b/include/elna/boot/semantic.h index 8a295e4..66eb0a7 100644 --- a/include/elna/frontend/semantic.h +++ b/include/elna/boot/semantic.h @@ -22,11 +22,11 @@ along with GCC; see the file COPYING3. If not see #include <memory> #include <deque> -#include "elna/frontend/ast.h" -#include "elna/frontend/result.h" -#include "elna/frontend/symbol.h" +#include "elna/boot/ast.h" +#include "elna/boot/result.h" +#include "elna/boot/symbol.h" -namespace elna::frontend +namespace elna::boot { class undeclared_error : public error { @@ -127,11 +127,13 @@ namespace elna::frontend procedure_type build_procedure(procedure_type_expression& type_expression); std::vector<type_field> build_composite_type(const std::vector<field_declaration>& fields); + std::shared_ptr<variable_info> 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(named_type_expression *type_expression) override; + 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; @@ -157,7 +159,7 @@ namespace elna::frontend 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(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; diff --git a/include/elna/frontend/symbol.h b/include/elna/boot/symbol.h index ec912ef..5ef917e 100644 --- a/include/elna/frontend/symbol.h +++ b/include/elna/boot/symbol.h @@ -24,9 +24,9 @@ along with GCC; see the file COPYING3. If not see #include <vector> #include <forward_list> -#include "elna/frontend/result.h" +#include "elna/boot/result.h" -namespace elna::frontend +namespace elna::boot { class alias_type; class primitive_type; 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<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, + void rewrite_symbol_table(std::shared_ptr<boot::symbol_table> info_table, std::shared_ptr<symbol_table> symbols); + tree handle_symbol(const std::string& symbol_name, std::shared_ptr<boot::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, + tree get_inner_alias(const boot::type& type, std::shared_ptr<symbol_table> symbols); + void declare_procedure(const std::string& name, const boot::procedure_info& info, std::shared_ptr<symbol_table> 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<symbol_table> 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 <deque> #include <memory> -#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<std::unique_ptr<frontend::error>>& errors); + void report_errors(const std::deque<std::unique_ptr<boot::error>>& errors); } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 97cd512..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<symbol_table> 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<frontend::expression *>& arguments); + tree procedure_address, const std::vector<boot::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); + tree symbol, const std::vector<boot::expression *>& arguments); + bool build_builtin_procedures(boot::procedure_call *call); + void build_assert_builtin(location_t call_location, const std::vector<boot::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 expect_trait_type_only(boot::traits_expression *trait); + bool expect_trait_for_integral_type(boot::traits_expression *trait); + void visit_statements(const std::vector<boot::statement *>& statements); bool assert_constant(location_t expression_location); public: - generic_visitor(std::shared_ptr<symbol_table> symbol_table, elna::frontend::symbol_bag bag); + generic_visitor(std::shared_ptr<symbol_table> 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<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; + 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<std::int32_t> *literal) override; + void visit(boot::literal<std::uint32_t> *literal) override; + void visit(boot::literal<double> *literal) override; + void visit(boot::literal<bool> *boolean) override; + void visit(boot::literal<unsigned char> *character) override; + void visit(boot::literal<std::nullptr_t> *) override; + void visit(boot::literal<std::string> *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<tree, tree, NULL_TREE>; + using symbol_table = boot::symbol_map<tree, tree, NULL_TREE>; 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); diff --git a/rakelib/doc.rake b/rakelib/doc.rake index 54f5d35..7838871 100644 --- a/rakelib/doc.rake +++ b/rakelib/doc.rake @@ -19,8 +19,9 @@ rule '.bbl' => '.bcf' do |t| end namespace :doc do - task :tex do - sh 'pdflatex', '-output-directory', '../build/doc', 'report', chdir: 'doc' + task tex: 'build/doc' do |t| + sh 'pdflatex', '-output-directory', "../#{t.prerequisites.first}", 'report', + chdir: 'doc' end end diff --git a/rakelib/gcc.rake b/rakelib/gcc.rake index 39b4442..3f36ce9 100644 --- a/rakelib/gcc.rake +++ b/rakelib/gcc.rake @@ -10,7 +10,7 @@ require 'pathname' def gcc_verbose(gcc_binary) read, write = IO.pipe - sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write) + sh({'LC_ALL' => 'C'}, gcc_binary, '--verbose', err: write) write.close output = read.read read.close @@ -60,10 +60,10 @@ end namespace :gcc do # Dependencies. - GCC_VERSION = "15.2.0" + GCC_VERSION = "15.3.0" HOST_GCC = 'build/host/gcc' HOST_INSTALL = 'build/host/install' - GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/formula-patches/575ffcaed6d3112916fed77d271dd3799a7255c4/gcc/gcc-15.1.0.diff' + GCC_PATCH = 'https://raw.githubusercontent.com/Homebrew/homebrew-core/refs/heads/main/Patches/gcc/gcc-15.3.0.diff' directory HOST_GCC directory HOST_INSTALL @@ -84,9 +84,10 @@ namespace :gcc do configure_options = [ "--prefix=#{File.realpath HOST_INSTALL}", - '--enable-languages=c,c++,elna', + '--enable-languages=c,c++,jit,elna', '--disable-bootstrap', '--disable-multilib', + '--enable-host-shared', '--with-system-zlib', "--target=#{build_target}", "--build=#{build_target}", diff --git a/source/cctype.elna b/source/cctype.elna index 3906cd1..13dc50a 100644 --- a/source/cctype.elna +++ b/source/cctype.elna @@ -1,14 +1,23 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -proc isdigit*(c: Int ) -> Int; extern; -proc isalnum*(c: Int) -> Int; extern; -proc isalpha*(c: Int) -> Int; extern; -proc isspace*(c: Int) -> Int; extern; +proc isdigit*(c: Int ) -> Int +extern -proc tolower*(c: Int) -> Int; extern; -proc toupper*(c: Int) -> Int; extern; +proc isalnum*(c: Int) -> Int +extern + +proc isalpha*(c: Int) -> Int +extern + +proc isspace*(c: Int) -> Int +extern + +proc tolower*(c: Int) -> Int +extern + +proc toupper*(c: Int) -> Int +extern end. diff --git a/source/command_line_interface.elna b/source/command_line_interface.elna index 040fdeb..78e1cf5 100644 --- a/source/command_line_interface.elna +++ b/source/command_line_interface.elna @@ -5,9 +5,7 @@ (* Command line handling. *) -module; - -import cstdlib, cstring, common; +import cstdlib, cstring, common type CommandLine* = record @@ -15,14 +13,14 @@ type output: ^Char; lex: Bool; parse: Bool - end; + end -proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine; +proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine var - parameter: ^Char; - i: Int; - result: ^CommandLine; - parsed: Bool; + parameter: ^Char + i: Int + result: ^CommandLine + parsed: Bool begin i := 1; result := cast(malloc(#size(CommandLine)): ^CommandLine); @@ -88,6 +86,6 @@ begin end; return result -end; +end end. diff --git a/source/common.elna b/source/common.elna index e7b30ca..33a79b8 100644 --- a/source/common.elna +++ b/source/common.elna @@ -1,50 +1,50 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -import cstring, cstdio; +import cstring, cstdio type - Identifier = [256]Char; + Identifier = [256]Char TextLocation* = record line: Word; column: Word - end; + end -proc write*(fd: Int, buf: Pointer, Word: Int) -> Int; extern; +proc write*(fd: Int, buf: Pointer, Word: Int) -> Int +extern -proc write_s*(value: String); +proc write_s*(value: String) begin (* fwrite(cast(value.ptr: Pointer), value.length, 1u, stdout) *) write(1, cast(value.ptr: Pointer), cast(value.length: Int)) -end; +end -proc write_z*(value: ^Char); +proc write_z*(value: ^Char) begin write(1, cast(value: Pointer), cast(strlen(value): Int)) -end; +end -proc write_b*(value: Bool); +proc write_b*(value: Bool) begin if value then write_s("true") else write_s("false") end -end; +end -proc write_c*(value: Char); +proc write_c*(value: Char) begin putchar(cast(value: Int)); fflush(nil) -end; +end -proc write_i*(value: Int); +proc write_i*(value: Int) var - digit: Int; - n: Word; - buffer: [10]Char; + digit: Int + n: Word + buffer: [10]Char begin n := 10u; @@ -62,11 +62,11 @@ begin n := n + 1u; write_c(buffer[n]) end -end; +end -proc write_u*(value: Word); +proc write_u*(value: Word) begin write_i(cast(value: Int)) -end; +end end. diff --git a/source/cstdio.elna b/source/cstdio.elna index c7507ff..b86014f 100644 --- a/source/cstdio.elna +++ b/source/cstdio.elna @@ -1,29 +1,46 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; type - FILE* = record end; + FILE* = record end var - stdin*: ^FILE := extern; - stdout*: ^FILE := extern; - stderr*: ^FILE := extern; + stdin*: ^FILE := extern + stdout*: ^FILE := extern + stderr*: ^FILE := extern -proc fopen*(pathname: ^Char, mode: ^Char) -> ^FILE; extern; -proc fclose*(stream: ^FILE) -> Int; extern; -proc fseek*(stream: ^FILE, off: Int, whence: Int) -> Int; extern; -proc rewind*(stream: ^FILE); extern; -proc ftell*(stream: ^FILE) -> Int; extern; -proc fflush*(stream: ^FILE) -> Int; extern; +proc fopen*(pathname: ^Char, mode: ^Char) -> ^FILE +extern -proc fread*(ptr: Pointer, size: Word, nmemb: Word, stream: ^FILE) -> Word; extern; -proc fwrite*(ptr: Pointer, size: Word, nitems: Word, stream: ^FILE) -> Word; extern; +proc fclose*(stream: ^FILE) -> Int +extern -proc perror(s: ^Char); extern; +proc fseek*(stream: ^FILE, off: Int, whence: Int) -> Int +extern -proc puts(s: ^Char) -> Int; extern; -proc putchar(c: Int) -> Int; extern; +proc rewind*(stream: ^FILE) +extern + +proc ftell*(stream: ^FILE) -> Int +extern + +proc fflush*(stream: ^FILE) -> Int +extern + +proc fread*(ptr: Pointer, size: Word, nmemb: Word, stream: ^FILE) -> Word +extern + +proc fwrite*(ptr: Pointer, size: Word, nitems: Word, stream: ^FILE) -> Word +extern + +proc perror(s: ^Char) +extern + +proc puts(s: ^Char) -> Int +extern + +proc putchar(c: Int) -> Int +extern end. diff --git a/source/cstdlib.elna b/source/cstdlib.elna index da2029c..3346440 100644 --- a/source/cstdlib.elna +++ b/source/cstdlib.elna @@ -1,15 +1,23 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -proc malloc(size: Word) -> Pointer; extern; -proc free(ptr: Pointer); extern; -proc calloc(nmemb: Word, size: Word) -> Pointer; extern; -proc realloc(ptr: Pointer, size: Word) -> Pointer; extern; +proc malloc(size: Word) -> Pointer +extern -proc atoi(str: ^Char) -> Int; extern; +proc free(ptr: Pointer) +extern -proc exit(code: Int) -> !; extern; +proc calloc(nmemb: Word, size: Word) -> Pointer +extern + +proc realloc(ptr: Pointer, size: Word) -> Pointer +extern + +proc atoi(str: ^Char) -> Int +extern + +proc exit(code: Int) -> ! +extern end. diff --git a/source/cstring.elna b/source/cstring.elna index 24d852a..ef04e59 100644 --- a/source/cstring.elna +++ b/source/cstring.elna @@ -1,15 +1,26 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -proc memset(ptr: Pointer, c: Int, n: Word) -> ^Char; extern; -proc memcpy(dst: Pointer, src: Pointer, n: Word); extern; +proc memset(ptr: Pointer, c: Int, n: Word) -> ^Char +extern -proc strcmp(s1: ^Char, s2: ^Char) -> Int; extern; -proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int; extern; -proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char; extern; -proc strcpy(dst: ^Char, src: ^Char) -> ^Char; extern; -proc strlen(ptr: ^Char) -> Word; extern; +proc memcpy(dst: Pointer, src: Pointer, n: Word) +extern + +proc strcmp(s1: ^Char, s2: ^Char) -> Int +extern + +proc strncmp(s1: ^Char, s2: ^Char, n: Word) -> Int +extern + +proc strncpy(dst: ^Char, src: ^Char, dsize: Word) -> ^Char +extern + +proc strcpy(dst: ^Char, src: ^Char) -> ^Char +extern + +proc strlen(ptr: ^Char) -> Word +extern end. diff --git a/source/lexer.elna b/source/lexer.elna index d5f529b..e6fc38c 100644 --- a/source/lexer.elna +++ b/source/lexer.elna @@ -1,12 +1,11 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -module; -import cstdio, cstring, cctype, cstdlib, common; +import cstdio, cstring, cctype, cstdlib, common const - CHUNK_SIZE := 85536u; + CHUNK_SIZE := 85536u type (* @@ -38,7 +37,7 @@ type greater, less, other - ); + ) TransitionState = ( start, colon, @@ -56,7 +55,7 @@ type leading_zero, decimal_suffix, finish - ); + ) LexerToken = record kind: LexerKind; value: union @@ -67,18 +66,18 @@ type end; start_location: TextLocation; end_location: TextLocation - end; - TransitionAction = proc(^Lexer, ^LexerToken); + end + TransitionAction = proc(^Lexer, ^LexerToken) Transition = record action: TransitionAction; next_state: TransitionState - end; - TransitionClasses = [22]Transition; + end + TransitionClasses = [22]Transition BufferPosition* = record iterator: ^Char; location: TextLocation - end; + end Lexer* = record input: ^FILE; buffer: ^Char; @@ -86,7 +85,7 @@ type length: Word; start: BufferPosition; current: BufferPosition - end; + end LexerKind* = ( unknown, identifier, @@ -153,15 +152,15 @@ type _program, _module, _import - ); + ) var - classification: [128]TransitionClass; - transitions: [16]TransitionClasses; + classification: [128]TransitionClass + transitions: [16]TransitionClasses -proc initialize_classification(); +proc initialize_classification() var - i: Word; + i: Word begin classification[1] := TransitionClass.eof; (* NUL *) classification[2] := TransitionClass.invalid; (* SOH *) @@ -297,13 +296,13 @@ begin classification[i] := TransitionClass.other; i := i + 1u end -end; +end -proc compare_keyword(keyword: String, token_start: BufferPosition, token_end: ^Char) -> Bool; +proc compare_keyword(keyword: String, token_start: BufferPosition, token_end: ^Char) -> Bool var - result: Bool; - index: Word; - continue: Bool; + result: Bool + index: Word + continue: Bool begin index := 0u; result := true; @@ -319,28 +318,28 @@ begin result := result & index = keyword.length; return result & (token_start.iterator = token_end) -end; +end (* Reached the end of file. *) -proc transition_action_eof(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_eof(lexer: ^Lexer, token: ^LexerToken) begin token^.kind := LexerKind.unknown -end; +end -proc increment(position: ^BufferPosition); +proc increment(position: ^BufferPosition) begin position^.iterator := position^.iterator + 1 -end; +end (* Add the character to the token currently read and advance to the next character. *) -proc transition_action_accumulate(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_accumulate(lexer: ^Lexer, token: ^LexerToken) begin increment(@lexer^.current) -end; +end (* The current character is not a part of the token. Finish the token already * read. Don't advance to the next character. *) -proc transition_action_finalize(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_finalize(lexer: ^Lexer, token: ^LexerToken) begin if lexer^.start.iterator^ = ':' then token^.kind := LexerKind.colon @@ -360,10 +359,10 @@ begin if lexer^.start.iterator^ = '.' then token^.kind := LexerKind.dot end -end; +end (* An action for tokens containing multiple characters. *) -proc transition_action_composite(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_composite(lexer: ^Lexer, token: ^LexerToken) begin if lexer^.start.iterator^ = '<' then if lexer^.current.iterator^ = '>' then @@ -383,10 +382,10 @@ begin token^.kind := LexerKind.arrow end; increment(@lexer^.current) -end; +end (* Skip a space. *) -proc transition_action_skip(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_skip(lexer: ^Lexer, token: ^LexerToken) begin increment(@lexer^.start); @@ -395,12 +394,12 @@ begin lexer^.start.location.column := 1u end; lexer^.current := lexer^.start -end; +end (* Delimited string action. *) -proc transition_action_delimited(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_delimited(lexer: ^Lexer, token: ^LexerToken) var - text_length: Word; + text_length: Word begin if lexer^.start.iterator^ = '(' then token^.kind := LexerKind.comment @@ -422,10 +421,10 @@ begin token^.kind := LexerKind.string end; increment(@lexer^.current) -end; +end (* Finalize keyword or identifier. *) -proc transition_action_key_id(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_key_id(lexer: ^Lexer, token: ^LexerToken) begin token^.kind := LexerKind.identifier; @@ -515,11 +514,11 @@ begin token^.kind := LexerKind.boolean; token^.value.booleanKind := false end -end; +end (* Action for tokens containing only one character. The character cannot be * followed by other characters forming a composite token. *) -proc transition_action_single(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_single(lexer: ^Lexer, token: ^LexerToken) begin if lexer^.current.iterator^ = '&' then token^.kind := LexerKind.and @@ -567,14 +566,14 @@ begin token^.kind := LexerKind.pipe end; increment(@lexer^.current) -end; +end (* Handle an integer literal. *) -proc transition_action_integer(lexer: ^Lexer, token: ^LexerToken); +proc transition_action_integer(lexer: ^Lexer, token: ^LexerToken) var - buffer: String; - integer_length: Word; - found: Bool; + buffer: String + integer_length: Word + found: Bool begin token^.kind := LexerKind.integer; @@ -584,12 +583,12 @@ begin token^.value.identifierKind[cast(token^.value.identifierKind[1]: Int) + 2] := '\0'; token^.value.integerKind := atoi(@token^.value.identifierKind[2]) -end; +end -proc set_default_transition(current_state: TransitionState, default_action: TransitionAction, next_state: TransitionState) -> Int; +proc set_default_transition(current_state: TransitionState, default_action: TransitionAction, next_state: TransitionState) -> Int var - default_transition: Transition; - state_index: Int; + default_transition: Transition + state_index: Int begin default_transition.action := default_action; default_transition.next_state := next_state; @@ -619,7 +618,7 @@ begin transitions[state_index][cast(TransitionClass.other: Int) + 1] := default_transition; return state_index -end; +end (* * The transition table describes transitions from one state to another, given @@ -637,9 +636,9 @@ end; * For the meaning of actions see labels in the lex_next function, which * handles each action. *) -proc initialize_transitions(); +proc initialize_transitions() var - state_index: Int; + state_index: Int begin (* Start state. *) state_index := cast(TransitionState.start: Int) + 1; @@ -877,9 +876,9 @@ begin transitions[state_index][cast(TransitionClass.x: Int) + 1].action := nil; transitions[state_index][cast(TransitionClass.x: Int) + 1].next_state := TransitionState.finish -end; +end -proc lexer_make*(lexer: ^Lexer, input: ^FILE); +proc lexer_make*(lexer: ^Lexer, input: ^FILE) begin lexer^.input := input; lexer^.length := 0u; @@ -887,17 +886,17 @@ begin lexer^.buffer := cast(malloc(CHUNK_SIZE): ^Char); memset(cast(lexer^.buffer: Pointer), 0, CHUNK_SIZE); lexer^.size := CHUNK_SIZE -end; +end (* Returns the last read token. *) -proc lexer_current*(lexer: ^Lexer) -> LexerToken; +proc lexer_current*(lexer: ^Lexer) -> LexerToken var - current_class: TransitionClass; - current_state: TransitionState; - current_transition: Transition; - result: LexerToken; - index1: Word; - index2: Word; + current_class: TransitionClass + current_state: TransitionState + current_transition: Transition + result: LexerToken + index1: Word + index2: Word begin lexer^.current := lexer^.start; current_state := TransitionState.start; @@ -919,12 +918,12 @@ begin result.end_location := lexer^.current.location; return result -end; +end (* Read and return the next token. *) -proc lexer_lex*(lexer: ^Lexer) -> LexerToken; +proc lexer_lex*(lexer: ^Lexer) -> LexerToken var - result: LexerToken; + result: LexerToken begin if lexer^.length = 0u then lexer^.length := fread(cast(lexer^.buffer: Pointer), CHUNK_SIZE, 1u, lexer^.input); @@ -936,17 +935,17 @@ begin result := lexer_current(lexer); return result -end; +end -proc lexer_destroy*(lexer: ^Lexer); +proc lexer_destroy*(lexer: ^Lexer) begin free(cast(lexer^.buffer: Pointer)) -end; +end -proc lexer_initialize(); +proc lexer_initialize() begin initialize_classification(); initialize_transitions() -end; +end end. diff --git a/source/main.elna b/source/main.elna index dae045b..db5e76f 100644 --- a/source/main.elna +++ b/source/main.elna @@ -1,9 +1,8 @@ (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) -program; -import cstdio, cctype, common, command_line_interface, lexer; +import cstdio, cstdlib, cstring, cctype, common, command_line_interface, lexer type SourceFile* = record @@ -11,12 +10,12 @@ type handle: ^FILE; size: Word; index: Word - end; + end StringBuffer* = record data: Pointer; size: Word; capacity: Word - end; + end SourceCode = record position: TextLocation; @@ -24,7 +23,7 @@ type empty: proc(Pointer) -> Bool; advance: proc(Pointer); head: proc(Pointer) -> Char - end; + end Token* = record kind: LexerKind; value: union @@ -33,49 +32,49 @@ type boolean_value: Bool; char_value: Char end - end; + end Tokenizer* = record length: Word; data: ^Token - end; + end (* Standard procedures. *) -proc reallocarray(ptr: Pointer, n: Word, size: Word) -> Pointer; +proc reallocarray(ptr: Pointer, n: Word, size: Word) -> Pointer return realloc(ptr, n * size) -end; +end -proc substring(string: String, start: Word, count: Word) -> String; +proc substring(string: String, start: Word, count: Word) -> String return String(string.ptr + start, count) -end; +end -proc open_substring(string: String, start: Word) -> String; +proc open_substring(string: String, start: Word) -> String return substring(string, start, string.length - start) -end; +end -proc string_dup(origin: String) -> String; +proc string_dup(origin: String) -> String var - copy: ^Char; + copy: ^Char begin copy := cast(malloc(origin.length): ^Char); strncpy(copy, origin.ptr, origin.length); return String(copy, origin.length) -end; +end -proc string_buffer_new() -> StringBuffer; +proc string_buffer_new() -> StringBuffer var - result: StringBuffer; + result: StringBuffer begin result.capacity := 64u; result.data := malloc(result.capacity); result.size := 0u; return result -end; +end -proc string_buffer_push(buffer: ^StringBuffer, char: Char); +proc string_buffer_push(buffer: ^StringBuffer, char: Char) begin if buffer^.size >= buffer^.capacity then buffer^.capacity := buffer^.capacity + 1024u; @@ -83,30 +82,30 @@ begin end; cast(buffer^.data + buffer^.size: ^Char)^ := cast(char: Char); buffer^.size := buffer^.size + 1u -end; +end -proc string_buffer_pop(buffer: ^StringBuffer, count: Word); +proc string_buffer_pop(buffer: ^StringBuffer, count: Word) begin buffer^.size := buffer^.size - count -end; +end -proc string_buffer_clear(buffer: ^StringBuffer) -> String; +proc string_buffer_clear(buffer: ^StringBuffer) -> String var - result: String; + result: String begin result := String(cast(buffer^.data: ^Char), buffer^.size); buffer^.size := 0u; return result -end; +end (* Source code stream procedures. *) -proc read_source(filename: ^Char) -> ^SourceFile; +proc read_source(filename: ^Char) -> ^SourceFile var - result: ^SourceFile; - file_handle: ^FILE; + result: ^SourceFile + file_handle: ^FILE begin file_handle := fopen(filename, "rb\0".ptr); @@ -117,11 +116,11 @@ begin result^.index := 1u end; return result -end; +end -proc source_file_empty(source_input: Pointer) -> Bool; +proc source_file_empty(source_input: Pointer) -> Bool var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); @@ -131,68 +130,62 @@ begin end; return source_file^.size = 0u -end; +end -proc source_file_head(source_input: Pointer) -> Char; +proc source_file_head(source_input: Pointer) -> Char var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); return source_file^.buffer[source_file^.index] -end; +end -proc source_file_advance(source_input: Pointer); +proc source_file_advance(source_input: Pointer) var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); source_file^.index := source_file^.index + 1u -end; +end -proc source_code_empty(source_code: ^SourceCode) -> Bool; +proc source_code_empty(source_code: ^SourceCode) -> Bool return source_code^.empty(source_code^.input) -end; +end -proc source_code_head(source_code: SourceCode) -> Char; +proc source_code_head(source_code: SourceCode) -> Char return source_code.head(source_code.input) -end; +end -proc source_code_advance(source_code: ^SourceCode); +proc source_code_advance(source_code: ^SourceCode) begin source_code^.advance(source_code^.input); source_code^.position.column := source_code^.position.column -end; +end -proc source_code_break(source_code: ^SourceCode); +proc source_code_break(source_code: ^SourceCode) begin source_code^.position.line := source_code^.position.line + 1u; source_code^.position.column := 0u -end; +end -proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool; +proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool return ~source_code_empty(source_code) & source_code_head(source_code^) = expected -end; +end (* Token procedures. *) -proc lexer_escape(escape: Char, result: ^Char) -> Bool; +proc lexer_escape(escape: Char, result: ^Char) -> Bool var - successful: Bool; + successful: Bool begin case escape of 'n': result^ := '\n'; successful := true - | 'a': - result^ := '\a'; - successful := true - | 'b': - result^ := '\b'; - successful := true | 't': result^ := '\t'; successful := true @@ -214,9 +207,6 @@ begin | '"': result^ := '"'; successful := true - | '?': - result^ := '\?'; - successful := true | '0': result^ := '\0'; successful := true @@ -224,12 +214,12 @@ begin successful := false end; return successful -end; +end (* Skip spaces. *) -proc lexer_spaces(source_code: ^SourceCode); +proc lexer_spaces(source_code: ^SourceCode) var - current: Char; + current: Char begin while ~source_code_empty(source_code) & isspace(cast(source_code_head(source_code^): Int)) <> 0 do current := source_code_head(source_code^); @@ -239,26 +229,26 @@ begin end; source_code_advance(source_code) end -end; +end (* Checker whether the character is allowed in an identificator. *) -proc lexer_is_ident(char: Char) -> Bool; +proc lexer_is_ident(char: Char) -> Bool return isalnum(cast(char: Int)) <> 0 or char = '_' -end; +end -proc lexer_identifier(source_code: ^SourceCode, token_content: ^StringBuffer); +proc lexer_identifier(source_code: ^SourceCode, token_content: ^StringBuffer) var - content_length: Word; + content_length: Word begin while ~source_code_empty(source_code) & lexer_is_ident(source_code_head(source_code^)) do string_buffer_push(token_content, source_code_head(source_code^)); source_code_advance(source_code) end -end; +end -proc lexer_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; +proc lexer_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool var - trailing: Word; + trailing: Word begin trailing := 0u; @@ -277,11 +267,11 @@ begin end; return trailing = 2u -end; +end -proc lexer_character(source_code: ^SourceCode, token_content: ^Char) -> Bool; +proc lexer_character(source_code: ^SourceCode, token_content: ^Char) -> Bool var - successful: Bool; + successful: Bool begin successful := ~source_code_empty(source_code); @@ -299,14 +289,14 @@ begin source_code_advance(source_code) end; return successful -end; +end -proc lexer_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; +proc lexer_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool var - token_end, constructed_string: ^Char; - token_length: Word; - is_valid: Bool := true; - next_char: Char; + token_end, constructed_string: ^Char + token_length: Word + is_valid: Bool := true + next_char: Char begin while is_valid & ~source_code_empty(source_code) & source_code_head(source_code^) <> '"' do is_valid := lexer_character(source_code, @next_char); @@ -322,9 +312,9 @@ begin is_valid := false end; return is_valid -end; +end -proc lexer_number(source_code: ^SourceCode, token_content: ^Int); +proc lexer_number(source_code: ^SourceCode, token_content: ^Int) begin token_content^ := 0; @@ -333,12 +323,12 @@ begin source_code_advance(source_code) end -end; +end (* Categorize an identifier. *) -proc lexer_categorize(token_content: String) -> Token; +proc lexer_categorize(token_content: String) -> Token var - current_token: Token; + current_token: Token begin if token_content = "if" then current_token.kind := LexerKind._if @@ -402,23 +392,23 @@ begin end; return current_token -end; +end -proc lexer_add_token(lexer: ^Tokenizer, token: Token); +proc lexer_add_token(lexer: ^Tokenizer, token: Token) var - new_length: Word; + new_length: Word begin new_length := lexer^.length + 1u; lexer^.data := cast(reallocarray(cast(lexer^.data: Pointer), new_length, #size(Token)): ^Token); (lexer^.data + lexer^.length)^ := token; lexer^.length := new_length -end; +end (* Read the next token from the input. *) -proc lexer_next(source_code: SourceCode, token_buffer: ^StringBuffer) -> Token; +proc lexer_next(source_code: SourceCode, token_buffer: ^StringBuffer) -> Token var - current_token: Token; - first_char: Char; + current_token: Token + first_char: Char begin current_token.kind := LexerKind.unknown; @@ -587,14 +577,14 @@ begin end; return current_token -end; +end (* Split the source text into tokens. *) -proc lexer_text(source_code: SourceCode) -> Tokenizer; +proc lexer_text(source_code: SourceCode) -> Tokenizer var - current_token: Token; - token_buffer: StringBuffer; - lexer: Tokenizer; + current_token: Token + token_buffer: StringBuffer + lexer: Tokenizer begin lexer := Tokenizer(0u, nil); token_buffer := string_buffer_new(); @@ -615,16 +605,16 @@ begin end; return lexer -end; +end (* Parser. *) -proc parse(tokens: ^Token, tokens_size: Word); +proc parse(tokens: ^Token, tokens_size: Word) var - current_token: ^Token; - i: Word := 0u; + current_token: ^Token + i: Word := 0u begin while i < tokens_size do current_token := tokens + i; @@ -777,16 +767,16 @@ begin i := i + 1u end; write_c('\n') -end; +end (* Compilation entry. *) -proc compile_in_stages(command_line: ^CommandLine, source_code: SourceCode) -> Int; +proc compile_in_stages(command_line: ^CommandLine, source_code: SourceCode) -> Int var - return_code: Int := 0; - lexer: Tokenizer; + return_code: Int := 0 + lexer: Tokenizer begin if command_line^.lex or command_line^.parse then lexer := lexer_text(source_code) @@ -796,16 +786,16 @@ begin end; return return_code -end; +end -proc process(argc: Int, argv: ^^Char) -> Int; +proc process(argc: Int, argv: ^^Char) -> Int var - tokens: ^Token; - tokens_size: Word; - source_code: SourceCode; - command_line: ^CommandLine; - return_code: Int := 0; - source_file: ^SourceFile; + tokens: ^Token + tokens_size: Word + source_code: SourceCode + command_line: ^CommandLine + return_code: Int := 0 + source_file: ^SourceFile begin command_line := parse_command_line(argc, argv); if command_line = nil then @@ -835,7 +825,7 @@ begin return_code := compile_in_stages(command_line, source_code) end; return return_code -end; +end return process(count, parameters) end. |
