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

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);
}