%require "3.2" %language "c++" %code requires { #include #include #include "elna/source/driver.hpp" #if !defined(yyFlexLexerOnce) #include #endif namespace elna::source { class lexer; } } %code provides { namespace elna::source { class lexer: public yyFlexLexer { public: yy::location location; lexer(std::istream& arg_yyin) : yyFlexLexer(&arg_yyin) { } yy::parser::symbol_type lex(); }; } } %define api.token.raw %define api.token.constructor %define api.value.type variant %define parse.assert %parse-param {elna::source::lexer& lexer} %parse-param {elna::source::driver& driver} %locations %header %code { #define yylex lexer.lex } %start program; %token IDENTIFIER "identifier" %token NUMBER "number" %token BOOLEAN %token IF THEN WHILE DO %token CONST VAR PROCEDURE %token BEGIN_BLOCK END_BLOCK %token TRUE FALSE %token LEFT_PAREN RIGHT_PAREN SEMICOLON DOT COMMA %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS %token PLUS MINUS MULTIPLICATION DIVISION %token ASSIGNMENT COLON HAT AT %type > integer_literal; %type > boolean_literal; %type > constant_definition; %type >> constant_definition_part constant_definitions; %type > variable_declaration; %type >> variable_declarations variable_declaration_part formal_parameter_list; %type > type_expression; %type > expression pointer summand factor address; %type >> expressions actual_parameter_list; %type > variable_expression; %type > compound_statement; %type > assign_statement; %type > call_statement; %type > while_statement; %type > if_statement; %type > statement; %type >> statements optional_statements; %type > procedure_definition; %type >> procedure_definitions; %type > block; %% program: constant_definition_part variable_declaration_part procedure_definitions statement DOT { std::vector> definitions($1.size() + $3.size()); std::vector>::iterator definition = definitions.begin(); for (auto& constant : $1) { *definition++ = std::move(constant); } for (auto& constant : $3) { *definition++ = std::move(constant); } driver.tree = std::make_unique(elna::source::position{}, std::move(definitions), std::move($2), std::move($4)); } block: constant_definition_part variable_declaration_part statement { std::vector> definitions($1.size()); std::vector>::iterator definition = definitions.begin(); for (auto& constant : $1) { *definition++ = std::move(constant); } $$ = std::make_unique(elna::source::position{}, std::move(definitions), std::move($2), std::move($3)); }; procedure_definition: PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON { $$ = std::make_unique(elna::source::position{}, std::move($2), std::move($5)); std::swap($$->parameters(), $3); }; procedure_definitions: procedure_definition procedure_definitions { std::swap($$, $2); $$.emplace($$.cbegin(), std::move($1)); } | procedure_definition { $$.emplace_back(std::move($1)); } integer_literal: NUMBER { $$ = std::make_unique(elna::source::make_position(@1), $1); }; boolean_literal: BOOLEAN { $$ = std::make_unique(elna::source::make_position(@1), $1); }; compound_statement: BEGIN_BLOCK optional_statements END_BLOCK { $$ = std::make_unique(elna::source::make_position(@1)); std::swap($$->statements(), $2); } assign_statement: IDENTIFIER ASSIGNMENT expression { $$ = std::make_unique(elna::source::make_position(@1), $1, std::move($3)); } call_statement: IDENTIFIER actual_parameter_list { $$ = std::make_unique(elna::source::make_position(@1), $1); std::swap($$->arguments(), $2); } while_statement: WHILE expression DO statement { $$ = std::make_unique(elna::source::make_position(@1), std::move($2), std::move($4)); } if_statement: IF expression THEN statement { $$ = std::make_unique(elna::source::make_position(@1), std::move($2), std::move($4)); } pointer: integer_literal { $$ = std::move($1); } | boolean_literal { $$ = std::move($1); } | variable_expression { $$ = std::move($1); } | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); } summand: factor { $$ = std::move($1); } | factor MULTIPLICATION factor { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), '*'); } | factor DIVISION factor { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), '/'); } address: pointer HAT { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), '^'); } | pointer { $$ = std::move($1); } factor: AT address { $$ = std::make_unique(elna::source::make_position(@1), std::move($2), '@'); } | address { $$ = std::move($1); } expression: summand EQUALS summand { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), '='); } | summand NOT_EQUAL summand { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), 'n'); } | summand LESS_THAN summand { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), '<'); } | summand GREATER_THAN summand { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), '>'); } | summand LESS_EQUAL summand { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), '<'); } | summand GREATER_EQUAL summand { $$ = std::make_unique(elna::source::make_position(@1), std::move($1), std::move($3), '>'); } | summand { $$ = std::move($1); } expressions: expression COMMA expressions { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); } | expression { $$.emplace_back(std::move($1)); } variable_expression: IDENTIFIER { $$ = std::make_unique(elna::source::make_position(@1), $1); } statement: compound_statement { $$ = std::move($1); } | assign_statement { $$ = std::move($1); } | call_statement { $$ = std::move($1); } | while_statement { $$ = std::move($1); } | if_statement { $$ = std::move($1); } statements: statement SEMICOLON statements { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); } | statement { $$.emplace_back(std::move($1)); } optional_statements: statements { std::swap($$, $1); } | /* no statements */ {} type_expression: HAT IDENTIFIER { $$ = std::make_unique(elna::source::make_position(@1), $2, true); } | IDENTIFIER { $$ = std::make_unique(elna::source::make_position(@1), $1, false); } variable_declaration: IDENTIFIER COLON type_expression { $$ = std::make_unique(elna::source::make_position(@1), $1, std::move($3)); }; variable_declarations: variable_declaration COMMA variable_declarations { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); } | variable_declaration { $$.emplace_back(std::move($1)); } variable_declaration_part: /* no variable declarations */ {} | VAR variable_declarations SEMICOLON { std::swap($$, $2); } constant_definition: IDENTIFIER EQUALS integer_literal { $$ = std::make_unique(elna::source::make_position(@1), $1, std::move($3)); }; constant_definitions: constant_definition COMMA constant_definitions { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); } | constant_definition { $$.emplace_back(std::move($1)); } constant_definition_part: /* no constant definitions */ {} | CONST constant_definitions SEMICOLON { std::swap($$, $2); }; formal_parameter_list: LEFT_PAREN RIGHT_PAREN {} | LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); } actual_parameter_list: LEFT_PAREN RIGHT_PAREN {} | LEFT_PAREN expressions RIGHT_PAREN { std::swap($$, $2); } %% void yy::parser::error(const location_type& loc, const std::string& message) { driver.error(loc, message); }