aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md (renamed from gcc/README.md)6
-rw-r--r--Rakefile1
-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.yy595
-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.tex10
-rw-r--r--doc/language.tex193
-rw-r--r--frontend/parser.yy594
-rw-r--r--gcc/Make-lang.in6
-rw-r--r--gcc/elna-builtins.cc54
-rw-r--r--gcc/elna-diagnostic.cc6
-rw-r--r--gcc/elna-generic.cc172
-rw-r--r--gcc/elna-tree.cc10
-rw-r--r--gcc/elna1.cc16
-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.h10
-rw-r--r--include/elna/gcc/elna-diagnostic.h6
-rw-r--r--include/elna/gcc/elna-generic.h92
-rw-r--r--include/elna/gcc/elna-tree.h12
-rw-r--r--rakelib/doc.rake5
-rw-r--r--rakelib/gcc.rake9
-rw-r--r--source/cctype.elna23
-rw-r--r--source/command_line_interface.elna18
-rw-r--r--source/common.elna40
-rw-r--r--source/cstdio.elna49
-rw-r--r--source/cstdlib.elna22
-rw-r--r--source/cstring.elna27
-rw-r--r--source/lexer.elna139
-rw-r--r--source/main.elna218
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
diff --git a/Rakefile b/Rakefile
index 4b2ac58..16fc6a6 100644
--- a/Rakefile
+++ b/Rakefile
@@ -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(&parameter_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.