Merge GCC frontend into the branch

This commit is contained in:
2025-12-02 10:22:06 +01:00
parent 5f7d839741
commit 23b6f074c7
53 changed files with 13330 additions and 0 deletions

1178
frontend/ast.cc Normal file

File diff suppressed because it is too large Load Diff

102
frontend/dependency.cc Normal file
View File

@@ -0,0 +1,102 @@
/* Dependency graph analysis.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "elna/frontend/dependency.h"
#include <fstream>
#include <sstream>
#include <string.h>
#include "elna/frontend/driver.h"
#include "elna/frontend/semantic.h"
#include "parser.hh"
namespace elna::frontend
{
dependency::dependency(const char *path)
: error_container(path)
{
}
dependency read_source(std::istream& entry_point, const char *entry_path)
{
driver parse_driver{ entry_path };
lexer tokenizer(entry_point);
yy::parser parser(tokenizer, parse_driver);
dependency outcome{ entry_path };
if (parser())
{
std::swap(outcome.errors(), parse_driver.errors());
return outcome;
}
else
{
std::swap(outcome.tree, parse_driver.tree);
}
declaration_visitor declaration_visitor(entry_path);
outcome.tree->accept(&declaration_visitor);
if (!declaration_visitor.errors().empty())
{
std::swap(outcome.errors(), declaration_visitor.errors());
}
outcome.unresolved = declaration_visitor.unresolved;
return outcome;
}
error_list analyze_semantics(const char *path, std::unique_ptr<unit>& tree, symbol_bag bag)
{
name_analysis_visitor name_analyser(path, bag);
tree->accept(&name_analyser);
if (name_analyser.has_errors())
{
return std::move(name_analyser.errors());
}
type_analysis_visitor type_analyzer(path, bag);
tree->accept(&type_analyzer);
if (type_analyzer.has_errors())
{
return std::move(type_analyzer.errors());
}
return error_list{};
}
std::filesystem::path build_path(const std::vector<std::string>& segments)
{
std::filesystem::path result;
std::vector<std::string>::const_iterator segment_iterator = std::cbegin(segments);
if (segment_iterator == std::cend(segments))
{
return result;
}
result = *segment_iterator;
++segment_iterator;
for (; segment_iterator != std::cend(segments); ++segment_iterator)
{
result /= *segment_iterator;
}
result.replace_extension(".elna");
return result;
}
}

124
frontend/driver.cc Normal file
View File

@@ -0,0 +1,124 @@
/* Parsing driver.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "elna/frontend/driver.h"
namespace elna::frontend
{
position make_position(const yy::location& location)
{
position result;
result.line = static_cast<std::size_t>(location.begin.line);
result.column = static_cast<std::size_t>(location.begin.column);
return result;
}
syntax_error::syntax_error(const std::string& message,
const char *input_file, const yy::location& location)
: error(input_file, make_position(location)), message(message)
{
}
std::string syntax_error::what() const
{
return message;
}
driver::driver(const char *input_file)
: error_container(input_file)
{
}
char escape_char(char escape)
{
switch (escape)
{
case 'n':
return '\n';
case 'a':
return '\a';
case 'b':
return '\b';
case 't':
return '\t';
case 'f':
return '\f';
case 'r':
return '\r';
case 'v':
return '\v';
case '\\':
return '\\';
case '\'':
return '\'';
case '"':
return '"';
case '?':
return '\?';
case '0':
return '\0';
default:
return escape_invalid_char;
}
}
std::optional<std::string> escape_string(const char *escape)
{
std::string result;
const char *current_position = escape + 1;
while (*current_position != '\0')
{
if (*current_position == '\\' && *(current_position + 1) == 'x')
{
current_position += 2;
std::size_t processed;
char character = static_cast<char>(std::stoi(current_position, &processed, 16));
if (processed == 0)
{
return std::nullopt;
}
else
{
current_position += processed - 1;
result.push_back(character);
}
}
else if (*current_position == '\\')
{
++current_position;
char escape = escape_char(*current_position);
if (escape == escape_invalid_char)
{
return std::nullopt;
}
result.push_back(escape);
}
else
{
result.push_back(*current_position);
}
++current_position;
}
result.pop_back(); // Remove the terminating quote character.
return result;
}
}

320
frontend/lexer.ll Normal file
View File

@@ -0,0 +1,320 @@
/* Lexical analyzer.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
%{
#define YY_NO_UNISTD_H
#define YY_USER_ACTION this->location.columns(yyleng);
#include <sstream>
#include "parser.hh"
#undef YY_DECL
#define YY_DECL yy::parser::symbol_type elna::frontend::lexer::lex(driver& driver)
#define yyterminate() return yy::parser::make_YYEOF(this->location)
%}
%option c++ noyywrap never-interactive
%option yyclass="lexer"
%x IN_COMMENT
ID1 [A-Za-z_]
ID2 [A-Za-z0-9_]
HIGIT [0-9a-fA-F]
BIGIT [01]
%%
%{
this->location.step();
%}
<IN_COMMENT>{
\*\) BEGIN(INITIAL);
[^*\n]+ ; /* Eat comment in chunks. */
\* ; /* Eat the lone star. */
\n+ {
this->location.lines(yyleng);
this->location.step();
}
}
\(\* BEGIN(IN_COMMENT);
[ \t\r] {
this->location.step();
}
\n+ {
this->location.lines(yyleng);
}
if {
return yy::parser::make_IF(this->location);
}
then {
return yy::parser::make_THEN(this->location);
}
else {
return yy::parser::make_ELSE(this->location);
}
elsif {
return yy::parser::make_ELSIF(this->location);
}
while {
return yy::parser::make_WHILE(this->location);
}
do {
return yy::parser::make_DO(this->location);
}
proc {
return yy::parser::make_PROCEDURE(this->location);
}
begin {
return yy::parser::make_BEGIN_BLOCK(this->location);
}
end {
return yy::parser::make_END_BLOCK(this->location);
}
extern {
return yy::parser::make_EXTERN(this->location);
}
const {
return yy::parser::make_CONST(this->location);
}
var {
return yy::parser::make_VAR(this->location);
}
type {
return yy::parser::make_TYPE(this->location);
}
record {
return yy::parser::make_RECORD(this->location);
}
union {
return yy::parser::make_UNION(this->location);
}
true {
return yy::parser::make_BOOLEAN(true, this->location);
}
false {
return yy::parser::make_BOOLEAN(false, this->location);
}
nil {
return yy::parser::make_NIL(this->location);
}
\& {
return yy::parser::make_AND(this->location);
}
xor {
return yy::parser::make_XOR(this->location);
}
or {
return yy::parser::make_OR(this->location);
}
\| {
return yy::parser::make_PIPE(this->location);
}
\~ {
return yy::parser::make_NOT(this->location);
}
return {
return yy::parser::make_RETURN(this->location);
}
module {
return yy::parser::make_MODULE(this->location);
}
program {
return yy::parser::make_PROGRAM(this->location);
}
import {
return yy::parser::make_IMPORT(this->location);
}
cast {
return yy::parser::make_CAST(this->location);
}
defer {
return yy::parser::make_DEFER(this->location);
}
case {
return yy::parser::make_CASE(this->location);
}
of {
return yy::parser::make_OF(this->location);
}
{ID1}{ID2}* {
return yy::parser::make_IDENTIFIER(yytext, this->location);
}
#{ID1}{ID2}* {
return yy::parser::make_TRAIT(yytext + 1, this->location);
}
[[:digit:]]+u {
unsigned long result = strtoul(yytext, NULL, 10);
if (errno == ERANGE)
{
REJECT;
}
else
{
return yy::parser::make_WORD(result, this->location);
}
}
[[:digit:]]+ {
long result = strtol(yytext, NULL, 10);
if (errno == ERANGE)
{
REJECT;
}
else
{
return yy::parser::make_INTEGER(result, this->location);
}
}
0x{HIGIT}+ {
unsigned long result = strtoul(yytext, NULL, 16);
if (errno == ERANGE)
{
REJECT;
}
else
{
return yy::parser::make_WORD(result, this->location);
}
}
0b{BIGIT}+ {
unsigned long result = strtoul(yytext, NULL, 2);
if (errno == ERANGE)
{
REJECT;
}
else
{
return yy::parser::make_WORD(result, this->location);
}
}
[[:digit:]]+\.[[:digit:]]+ {
float result = strtof(yytext, NULL);
if (errno == ERANGE)
{
REJECT;
}
else
{
return yy::parser::make_FLOAT(result, this->location);
}
}
'[[:print:]]+' {
std::optional<std::string> result = escape_string(yytext);
if (!result.has_value() || result.value().size() != 1)
{
REJECT;
}
return yy::parser::make_CHARACTER(result.value(), this->location);
}
\"[[:print:]]*\" {
std::optional<std::string> result = escape_string(yytext);
if (!result.has_value())
{
REJECT;
}
return yy::parser::make_STRING(result.value(), this->location);
}
\( {
return yy::parser::make_LEFT_PAREN(this->location);
}
\) {
return yy::parser::make_RIGHT_PAREN(this->location);
}
\[ {
return yy::parser::make_LEFT_SQUARE(this->location);
}
\] {
return yy::parser::make_RIGHT_SQUARE(this->location);
}
\<\< {
return yy::parser::make_SHIFT_LEFT(this->location);
}
\>\> {
return yy::parser::make_SHIFT_RIGHT(this->location);
}
\>= {
return yy::parser::make_GREATER_EQUAL(this->location);
}
\<= {
return yy::parser::make_LESS_EQUAL(this->location);
}
\> {
return yy::parser::make_GREATER_THAN(this->location);
}
\< {
return yy::parser::make_LESS_THAN(this->location);
}
\<\> {
return yy::parser::make_NOT_EQUAL(this->location);
}
= {
return yy::parser::make_EQUALS(this->location);
}
; {
return yy::parser::make_SEMICOLON(this->location);
}
\. {
return yy::parser::make_DOT(this->location);
}
, {
return yy::parser::make_COMMA(this->location);
}
\+ {
return yy::parser::make_PLUS(this->location);
}
\-> {
return yy::parser::make_ARROW(this->location);
}
\- {
return yy::parser::make_MINUS(this->location);
}
\* {
return yy::parser::make_MULTIPLICATION(this->location);
}
\/ {
return yy::parser::make_DIVISION(this->location);
}
% {
return yy::parser::make_REMAINDER(this->location);
}
:= {
return yy::parser::make_ASSIGNMENT(this->location);
}
: {
return yy::parser::make_COLON(this->location);
}
\^ {
return yy::parser::make_HAT(this->location);
}
@ {
return yy::parser::make_AT(this->location);
}
! {
return yy::parser::make_EXCLAMATION(this->location);
}
. {
std::stringstream ss;
ss << "Illegal character 0x" << std::hex << static_cast<unsigned int>(yytext[0]);
driver.add_error<syntax_error>(ss.str(), driver.input_file, this->location);
}
%%

594
frontend/parser.yy Normal file
View File

@@ -0,0 +1,594 @@
/* 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);
}

67
frontend/result.cc Normal file
View File

@@ -0,0 +1,67 @@
/* Miscellaneous types used across stage boundaries.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "elna/frontend/result.h"
namespace elna::frontend
{
error::error(const char *path, const struct position position)
: position(position), path(path)
{
}
std::size_t error::line() const noexcept
{
return this->position.line;
}
std::size_t error::column() const noexcept
{
return this->position.column;
}
error_container::error_container(const char *input_file)
: input_file(input_file)
{
}
std::deque<std::unique_ptr<error>>& error_container::errors()
{
return m_errors;
}
bool error_container::has_errors() const
{
return !m_errors.empty();
}
bool identifier_definition::operator==(const identifier_definition& that) const
{
return *this == that.name;
}
bool identifier_definition::operator==(const std::string& that) const
{
return this->name == that;
}
}
std::size_t std::hash<elna::frontend::identifier_definition>::operator()(
const elna::frontend::identifier_definition& key) const
{
return std::hash<std::string>{}(key.name);
}

644
frontend/semantic.cc Normal file
View File

@@ -0,0 +1,644 @@
/* Name analysis.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "elna/frontend/semantic.h"
#include <algorithm>
#include <set>
namespace elna::frontend
{
undeclared_error::undeclared_error(const std::string& identifier, const char *path, const struct position position)
: error(path, position), identifier(identifier)
{
}
std::string undeclared_error::what() const
{
return "Type '" + identifier + "' not declared";
}
already_declared_error::already_declared_error(const std::string& identifier,
const char *path, const struct position position)
: error(path, position), identifier(identifier)
{
}
std::string already_declared_error::what() const
{
return "Symbol '" + identifier + "' has been already declared";
}
field_duplication_error::field_duplication_error(const std::string& field_name,
const char *path, const struct position position)
: error(path, position), field_name(field_name)
{
}
std::string field_duplication_error::what() const
{
return "Repeated field name '" + field_name + "'";
}
cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle,
const char *path, const struct position position)
: error(path, position), cycle(cycle)
{
}
std::string cyclic_declaration_error::what() const
{
auto segment = std::cbegin(this->cycle);
std::string message = "Type declaration forms a cycle: " + *segment;
++segment;
for (; segment != std::cend(this->cycle); ++segment)
{
message += " -> " + *segment;
}
return message;
}
return_error::return_error(const std::string& identifier, const char *path, const struct position position)
: error(path, position), identifier(identifier)
{
}
std::string return_error::what() const
{
return "Procedure '" + identifier + "' is expected to return, but does not have a return statement";
}
variable_initializer_error::variable_initializer_error(const char *path, const struct position position)
: error(path, position)
{
}
std::string variable_initializer_error::what() const
{
return "Only one variable can be initialized";
}
type_analysis_visitor::type_analysis_visitor(const char *path, symbol_bag bag)
: error_container(path), bag(bag)
{
}
void type_analysis_visitor::visit(program *program)
{
visit(static_cast<unit *>(program));
}
void type_analysis_visitor::visit(procedure_declaration *definition)
{
if (definition->body.has_value() && definition->heading().return_type.proper_type != nullptr)
{
for (statement *const statement : definition->body.value().body())
{
statement->accept(this);
}
if (!this->returns)
{
add_error<return_error>(definition->identifier.name, this->input_file, definition->position());
}
}
}
void type_analysis_visitor::visit(assign_statement *)
{
}
void type_analysis_visitor::visit(if_statement *)
{
}
void type_analysis_visitor::visit(while_statement *)
{
}
void type_analysis_visitor::visit(return_statement *)
{
this->returns = true;
}
void type_analysis_visitor::visit(defer_statement *)
{
}
void type_analysis_visitor::visit(case_statement *)
{
}
void type_analysis_visitor::visit(procedure_call *)
{
}
bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr<alias_type> alias,
std::vector<std::string>& alias_path)
{
if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path))
{
return false;
}
alias_path.push_back(alias->name);
if (auto another_alias = alias->reference.get<alias_type>())
{
return check_unresolved_symbol(another_alias, alias_path);
}
return true;
}
void type_analysis_visitor::visit(unit *unit)
{
for (type_declaration *const type : unit->types)
{
type->accept(this);
}
for (procedure_declaration *const procedure : unit->procedures)
{
this->returns = false;
procedure->accept(this);
}
}
void type_analysis_visitor::visit(type_declaration *definition)
{
std::vector<std::string> alias_path;
auto unresolved_type = this->bag.lookup(definition->identifier.name)->is_type()->symbol.get<alias_type>();
if (!check_unresolved_symbol(unresolved_type, alias_path))
{
add_error<cyclic_declaration_error>(alias_path, this->input_file, definition->position());
}
}
name_analysis_visitor::name_analysis_visitor(const char *path, symbol_bag bag)
: error_container(path), bag(bag)
{
}
procedure_type name_analysis_visitor::build_procedure(procedure_type_expression& type_expression)
{
procedure_type::return_t result_return;
if (type_expression.return_type.no_return)
{
result_return = procedure_type::return_t(std::monostate{});
}
else if (type_expression.return_type.proper_type != nullptr)
{
type_expression.return_type.proper_type->accept(this);
result_return = procedure_type::return_t(this->current_type);
}
else
{
result_return = procedure_type::return_t();
}
procedure_type result_type = procedure_type(result_return);
for (struct type_expression *parameter : type_expression.parameters)
{
parameter->accept(this);
result_type.parameters.push_back(this->current_type);
}
return result_type;
}
void name_analysis_visitor::visit(program *program)
{
visit(static_cast<unit *>(program));
for (statement *const statement : program->body)
{
statement->accept(this);
}
}
void name_analysis_visitor::visit(type_declaration *definition)
{
definition->body().accept(this);
auto resolved = this->bag.resolve(definition->identifier.name, this->current_type);
auto info = std::make_shared<type_info>(type(resolved));
info->exported = definition->identifier.exported;
this->bag.enter(definition->identifier.name, info);
}
void name_analysis_visitor::visit(named_type_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))
{
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)
{
type_expression->base().accept(this);
this->current_type = type(std::make_shared<pointer_type>(this->current_type));
}
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));
}
std::vector<type_field> name_analysis_visitor::build_composite_type(const std::vector<field_declaration>& fields)
{
std::vector<type_field> result;
std::set<std::string> field_names;
for (auto& field : fields)
{
if (field_names.find(field.first) != field_names.cend())
{
add_error<field_duplication_error>(field.first, this->input_file, field.second->position());
}
else
{
field_names.insert(field.first);
field.second->accept(this);
result.push_back(std::make_pair(field.first, this->current_type));
}
}
return result;
}
void name_analysis_visitor::visit(record_type_expression *type_expression)
{
auto result_type = std::make_shared<record_type>();
result_type->fields = build_composite_type(type_expression->fields);
this->current_type = type(result_type);
}
void name_analysis_visitor::visit(union_type_expression *type_expression)
{
auto result_type = std::make_shared<union_type>();
result_type->fields = build_composite_type(type_expression->fields);
this->current_type = type(result_type);
}
void name_analysis_visitor::visit(procedure_type_expression *type_expression)
{
std::shared_ptr<procedure_type> result_type =
std::make_shared<procedure_type>(std::move(build_procedure(*type_expression)));
this->current_type = type(result_type);
}
void name_analysis_visitor::visit(enumeration_type_expression *type_expression)
{
std::shared_ptr<enumeration_type> result_type = std::make_shared<enumeration_type>(type_expression->members);
this->current_type = type(result_type);
}
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);
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());
}
}
}
void name_analysis_visitor::visit(constant_declaration *definition)
{
definition->body().accept(this);
auto constant_symbol = std::make_shared<constant_info>(this->current_literal);
constant_symbol->exported = definition->identifier.exported;
this->bag.enter(definition->identifier.name, constant_symbol);
}
void name_analysis_visitor::visit(procedure_declaration *definition)
{
std::shared_ptr<procedure_info> info;
auto heading = build_procedure(definition->heading());
if (definition->body.has_value())
{
info = std::make_shared<procedure_info>(heading, definition->parameter_names, this->bag.enter());
for (constant_declaration *const constant : definition->body.value().constants())
{
constant->accept(this);
}
for (variable_declaration *const variable : definition->body.value().variables())
{
variable->accept(this);
}
for (statement *const statement : definition->body.value().body())
{
statement->accept(this);
}
this->bag.leave();
}
else
{
info = std::make_shared<procedure_info>(heading, definition->parameter_names);
}
info->exported = definition->identifier.exported;
this->bag.enter(definition->identifier.name, info);
}
void name_analysis_visitor::visit(assign_statement *statement)
{
statement->lvalue().accept(this);
statement->rvalue().accept(this);
}
void name_analysis_visitor::visit(if_statement *statement)
{
statement->body().prerequisite().accept(this);
for (struct statement *const statement : statement->body().statements)
{
statement->accept(this);
}
for (const auto branch : statement->branches)
{
branch->prerequisite().accept(this);
for (struct statement *const statement : branch->statements)
{
statement->accept(this);
}
}
if (statement->alternative != nullptr)
{
for (struct statement *const statement : *statement->alternative)
{
statement->accept(this);
}
}
}
void name_analysis_visitor::visit(import_declaration *)
{
}
void name_analysis_visitor::visit(while_statement *statement)
{
statement->body().prerequisite().accept(this);
for (struct statement *const statement : statement->body().statements)
{
statement->accept(this);
}
for (const auto branch : statement->branches)
{
branch->prerequisite().accept(this);
for (struct statement *const statement : branch->statements)
{
statement->accept(this);
}
}
}
void name_analysis_visitor::visit(return_statement *statement)
{
statement->return_expression().accept(this);
}
void name_analysis_visitor::visit(defer_statement *statement)
{
for (struct statement *const statement : statement->statements)
{
statement->accept(this);
}
}
void name_analysis_visitor::visit(case_statement *statement)
{
statement->condition().accept(this);
for (const switch_case& case_block : statement->cases)
{
for (expression *const case_label : case_block.labels)
{
case_label->accept(this);
}
for (struct statement *const statement : case_block.statements)
{
statement->accept(this);
}
}
if (statement->alternative != nullptr)
{
for (struct statement *const statement : *statement->alternative)
{
statement->accept(this);
}
}
}
void name_analysis_visitor::visit(procedure_call *call)
{
call->callable().accept(this);
for (expression *const argument: call->arguments)
{
argument->accept(this);
}
}
void name_analysis_visitor::visit(unit *unit)
{
for (type_declaration *const type : unit->types)
{
type->accept(this);
}
for (variable_declaration *const variable : unit->variables)
{
variable->accept(this);
}
for (procedure_declaration *const procedure : unit->procedures)
{
procedure->accept(this);
}
}
void name_analysis_visitor::visit(traits_expression *trait)
{
if (!trait->parameters.empty())
{
trait->parameters.front()->accept(this);
trait->types.push_back(this->current_type);
}
}
void name_analysis_visitor::visit(cast_expression *expression)
{
expression->value().accept(this);
expression->target().accept(this);
expression->expression_type = this->current_type;
}
void name_analysis_visitor::visit(binary_expression *expression)
{
expression->lhs().accept(this);
expression->rhs().accept(this);
}
void name_analysis_visitor::visit(unary_expression *expression)
{
expression->operand().accept(this);
}
void name_analysis_visitor::visit(variable_expression *)
{
}
void name_analysis_visitor::visit(array_access_expression *expression)
{
expression->base().accept(this);
expression->index().accept(this);
}
void name_analysis_visitor::visit(field_access_expression *expression)
{
expression->base().accept(this);
}
void name_analysis_visitor::visit(dereference_expression *expression)
{
expression->base().accept(this);
}
void name_analysis_visitor::visit(literal<std::int32_t> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<std::uint32_t> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<double> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<bool> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<unsigned char> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<std::nullptr_t> *literal)
{
this->current_literal = literal->value;
}
void name_analysis_visitor::visit(literal<std::string> *literal)
{
this->current_literal = literal->value;
}
declaration_visitor::declaration_visitor(const char *path)
: error_container(path)
{
}
void declaration_visitor::visit(program *program)
{
visit(static_cast<unit *>(program));
}
void declaration_visitor::visit(import_declaration *)
{
}
void declaration_visitor::visit(unit *unit)
{
for (import_declaration *const _import : unit->imports)
{
_import->accept(this);
}
for (type_declaration *const type : unit->types)
{
type->accept(this);
}
for (variable_declaration *const variable : unit->variables)
{
variable->accept(this);
}
for (procedure_declaration *const procedure : unit->procedures)
{
procedure->accept(this);
}
}
void declaration_visitor::visit(type_declaration *definition)
{
const std::string& type_identifier = definition->identifier.name;
if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second)
{
add_error<already_declared_error>(definition->identifier.name, this->input_file,
definition->position());
}
}
void declaration_visitor::visit(variable_declaration *declaration)
{
if (declaration->has_initializer() && declaration->identifiers.size() > 1)
{
add_error<variable_initializer_error>(this->input_file, declaration->position());
}
}
void declaration_visitor::visit(procedure_declaration *definition)
{
if (!definition->body.has_value())
{
return;
}
for (variable_declaration *const variable : definition->body.value().variables())
{
variable->accept(this);
}
}
}

427
frontend/symbol.cc Normal file
View File

@@ -0,0 +1,427 @@
/* Symbol definitions.
Copyright (C) 2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "elna/frontend/symbol.h"
namespace elna::frontend
{
type::type()
{
}
type::type(std::shared_ptr<alias_type> alias)
: tag(type_tag::alias), alias(alias)
{
}
type::type(std::shared_ptr<primitive_type> primitive)
: tag(type_tag::primitive), primitive(primitive)
{
}
type::type(std::shared_ptr<record_type> record)
: tag(type_tag::record), record(record)
{
}
type::type(std::shared_ptr<union_type> _union)
: tag(type_tag::_union), _union(_union)
{
}
type::type(std::shared_ptr<pointer_type> pointer)
: tag(type_tag::pointer), pointer(pointer)
{
}
type::type(std::shared_ptr<array_type> array)
: tag(type_tag::array), array(array)
{
}
type::type(std::shared_ptr<procedure_type> procedure)
: tag(type_tag::procedure), procedure(procedure)
{
}
type::type(std::shared_ptr<enumeration_type> enumeration)
: tag(type_tag::enumeration), enumeration(enumeration)
{
}
void type::copy(const type& other)
{
switch (other.tag)
{
case type_tag::empty:
break;
case type_tag::alias:
new (&alias) std::weak_ptr<alias_type>(other.alias);
break;
case type_tag::primitive:
new (&primitive) std::shared_ptr<primitive_type>(other.primitive);
break;
case type_tag::record:
new (&record) std::shared_ptr<record_type>(other.record);
break;
case type_tag::_union:
new (&_union) std::shared_ptr<union_type>(other._union);
break;
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(other.pointer);
break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(other.array);
break;
case type_tag::procedure:
new (&procedure) std::shared_ptr<procedure_type>(other.procedure);
break;
case type_tag::enumeration:
new (&enumeration) std::shared_ptr<enumeration_type>(other.enumeration);
break;
}
}
type::type(const type& other)
: tag(other.tag)
{
copy(other);
}
void type::move(type&& other)
{
switch (other.tag)
{
case type_tag::empty:
break;
case type_tag::alias:
new (&alias) std::weak_ptr<alias_type>(std::move(other.alias));
break;
case type_tag::primitive:
new (&primitive) std::shared_ptr<primitive_type>(std::move(other.primitive));
break;
case type_tag::record:
new (&record) std::shared_ptr<record_type>(std::move(other.record));
break;
case type_tag::_union:
new (&_union) std::shared_ptr<union_type>(std::move(other._union));
break;
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(std::move(other.pointer));
break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(std::move(other.array));
break;
case type_tag::procedure:
new (&procedure) std::shared_ptr<procedure_type>(std::move(other.procedure));
break;
case type_tag::enumeration:
new (&enumeration) std::shared_ptr<enumeration_type>(std::move(other.enumeration));
break;
}
}
type& type::operator=(const type& other)
{
this->~type();
this->tag = other.tag;
copy(other);
return *this;
}
type::type(type&& other)
: tag(other.tag)
{
move(std::move(other));
}
type& type::operator=(type&& other)
{
this->~type();
this->tag = other.tag;
move(std::move(other));
return *this;
}
bool type::operator==(const std::nullptr_t&)
{
return empty();
}
type::~type()
{
switch (tag)
{
case type_tag::empty:
break;
case type_tag::alias:
this->alias.~weak_ptr<alias_type>();
break;
case type_tag::primitive:
this->primitive.~shared_ptr<primitive_type>();
break;
case type_tag::record:
this->record.~shared_ptr<record_type>();
break;
case type_tag::_union:
this->_union.~shared_ptr<union_type>();
break;
case type_tag::pointer:
this->pointer.~shared_ptr<pointer_type>();
break;
case type_tag::array:
this->array.~shared_ptr<array_type>();
break;
case type_tag::procedure:
this->procedure.~shared_ptr<procedure_type>();
break;
case type_tag::enumeration:
this->enumeration.~shared_ptr<enumeration_type>();
break;
}
}
template<>
std::shared_ptr<alias_type> type::get<alias_type>() const
{
return tag == type_tag::alias ? this->alias.lock() : nullptr;
}
template<>
std::shared_ptr<primitive_type> type::get<primitive_type>() const
{
return tag == type_tag::primitive ? this->primitive : nullptr;
}
template<>
std::shared_ptr<record_type> type::get<record_type>() const
{
return tag == type_tag::record ? this->record : nullptr;
}
template<>
std::shared_ptr<union_type> type::get<union_type>() const
{
return tag == type_tag::_union ? this->_union : nullptr;
}
template<>
std::shared_ptr<pointer_type> type::get<pointer_type>() const
{
return tag == type_tag::pointer ? this->pointer : nullptr;
}
template<>
std::shared_ptr<array_type> type::get<array_type>() const
{
return tag == type_tag::array ? this->array : nullptr;
}
template<>
std::shared_ptr<procedure_type> type::get<procedure_type>() const
{
return tag == type_tag::procedure ? this->procedure : nullptr;
}
template<>
std::shared_ptr<enumeration_type> type::get<enumeration_type>() const
{
return tag == type_tag::enumeration ? this->enumeration : nullptr;
}
bool type::empty() const
{
return tag == type_tag::empty;
}
alias_type::alias_type(const std::string& name)
: name(name), reference()
{
}
pointer_type::pointer_type(type base)
: base(base)
{
}
array_type::array_type(type base, std::uint64_t size)
: base(base), size(size)
{
}
primitive_type::primitive_type(const std::string& identifier)
: identifier(identifier)
{
}
procedure_type::procedure_type(return_t return_type)
: return_type(return_type)
{
}
enumeration_type::enumeration_type(const std::vector<std::string>& members)
: members(members)
{
}
info::~info()
{
}
std::shared_ptr<type_info> info::is_type()
{
return nullptr;
}
std::shared_ptr<procedure_info> info::is_procedure()
{
return nullptr;
}
std::shared_ptr<constant_info> info::is_constant()
{
return nullptr;
}
std::shared_ptr<variable_info> info::is_variable()
{
return nullptr;
}
type_info::type_info(const type symbol)
: symbol(symbol)
{
}
std::shared_ptr<type_info> type_info::is_type()
{
return std::static_pointer_cast<type_info>(shared_from_this());
}
procedure_info::procedure_info(const procedure_type symbol, const std::vector<std::string> names,
std::shared_ptr<symbol_table> scope)
: symbol(symbol), names(names), scope(scope)
{
}
std::shared_ptr<procedure_info> procedure_info::is_procedure()
{
return std::static_pointer_cast<procedure_info>(shared_from_this());
}
bool procedure_info::is_extern() const
{
return this->scope == nullptr;
}
constant_info::constant_info(const variant& symbol)
: symbol(symbol)
{
}
std::shared_ptr<constant_info> constant_info::is_constant()
{
return std::static_pointer_cast<constant_info>(shared_from_this());
}
variable_info::variable_info(const type symbol, bool is_extern)
: symbol(symbol), is_extern(is_extern)
{
}
std::shared_ptr<variable_info> variable_info::is_variable()
{
return std::static_pointer_cast<variable_info>(shared_from_this());
}
std::shared_ptr<symbol_table> builtin_symbol_table()
{
auto result = std::make_shared<symbol_table>();
result->enter("Int", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Int"))));
result->enter("Word", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Word"))));
result->enter("Char", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Char"))));
result->enter("Bool", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Bool"))));
result->enter("Pointer", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Pointer"))));
result->enter("Float", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Float"))));
result->enter("String", std::make_shared<type_info>(type(std::make_shared<primitive_type>("String"))));
return result;
}
symbol_bag::symbol_bag(forward_table&& unresolved, std::shared_ptr<symbol_table> global_table)
: unresolved(unresolved)
{
this->symbols = std::make_shared<symbol_table>(global_table);
}
std::shared_ptr<info> symbol_bag::lookup(const std::string& name)
{
for (auto import_bag : this->imports)
{
if (auto result = import_bag->lookup(name))
{
return result;
}
}
return this->symbols->lookup(name);
}
bool symbol_bag::enter(const std::string& name, std::shared_ptr<info> entry)
{
return this->symbols->enter(name, entry);
}
std::shared_ptr<symbol_table> symbol_bag::enter()
{
this->symbols = std::make_shared<symbol_table>(this->symbols);
return this->symbols;
}
void symbol_bag::enter(std::shared_ptr<symbol_table> child)
{
this->symbols = child;
}
std::shared_ptr<symbol_table> symbol_bag::leave()
{
std::shared_ptr<symbol_table> result = this->symbols;
this->symbols = result->scope();
return result;
}
std::shared_ptr<alias_type> symbol_bag::declared(const std::string& symbol_name)
{
auto unresolved_alias = this->unresolved.find(symbol_name);
return unresolved_alias == this->unresolved.end() ? std::shared_ptr<alias_type>() : unresolved_alias->second;
}
std::shared_ptr<alias_type> symbol_bag::resolve(const std::string& symbol_name, type& resolution)
{
auto unresolved_declaration = this->unresolved.at(symbol_name);
unresolved_declaration->reference = resolution;
return unresolved_declaration;
}
void symbol_bag::add_import(const symbol_bag& bag)
{
this->imports.push_front(bag.symbols);
}
}