summaryrefslogtreecommitdiff
path: root/frontend/parser.yy
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2025-12-02 10:22:06 +0100
committerEugen Wissner <belka@caraus.de>2025-12-02 17:14:18 +0100
commit23b6f074c7f560d701e9a1fa5713a965af3a18a3 (patch)
tree87549a4eba3da8d8ed6e3fbb2e337e152a8bc96a /frontend/parser.yy
parent5f7d83974114c73327ce9fff3635927df050b5e4 (diff)
downloadelna-23b6f074c7f560d701e9a1fa5713a965af3a18a3.tar.gz
Merge GCC frontend into the branch
Diffstat (limited to 'frontend/parser.yy')
-rw-r--r--frontend/parser.yy594
1 files changed, 594 insertions, 0 deletions
diff --git a/frontend/parser.yy b/frontend/parser.yy
new file mode 100644
index 0000000..bace8d7
--- /dev/null
+++ b/frontend/parser.yy
@@ -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);
+}