diff options
| author | Eugen Wissner <belka@caraus.de> | 2025-12-02 10:22:06 +0100 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2025-12-02 17:14:18 +0100 |
| commit | 23b6f074c7f560d701e9a1fa5713a965af3a18a3 (patch) | |
| tree | 87549a4eba3da8d8ed6e3fbb2e337e152a8bc96a /frontend/parser.yy | |
| parent | 5f7d83974114c73327ce9fff3635927df050b5e4 (diff) | |
| download | elna-23b6f074c7f560d701e9a1fa5713a965af3a18a3.tar.gz | |
Merge GCC frontend into the branch
Diffstat (limited to 'frontend/parser.yy')
| -rw-r--r-- | frontend/parser.yy | 594 |
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); +} |
