/* * This Source Code Form is subject to the terms of the Mozilla Public License * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. */ %require "3.2" %language "c++" %code requires { #include #include #include "elna/source/driver.h" #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(elna::source::driver& driver); }; } } %define api.token.raw %define api.token.constructor %define api.value.type variant %parse-param {elna::source::lexer& lexer} %param {elna::source::driver& driver} %locations %header %code { #define yylex lexer.lex } %start program; %token IDENTIFIER "identifier" %token INTEGER "integer" %token FLOAT "float" %token CHARACTER "character" %token STRING "string" %token BOOLEAN %token IF WHILE DO %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD %token BEGIN_BLOCK END_BLOCK %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE 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 %precedence THEN %precedence ELSE %type *> integer_literal; %type *> float_literal; %type *> boolean_literal; %type character_literal; %type string_literal; %type constant_definition; %type > constant_part constant_definitions; %type variable_declaration; %type > variable_declarations variable_part formal_parameter_list; %type type_expression; %type expression pointer summand factor comparand; %type > expressions actual_parameter_list; %type designator_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 procedure_part; %type type_definition; %type > type_definitions type_part; %type block; %% program: type_part constant_part procedure_part variable_part compound_statement DOT { std::vector definitions($1.size() + $2.size() + $3.size()); std::vector::iterator definition = definitions.begin(); for (auto& type : $1) { *definition++ = type; } for (auto& constant : $2) { *definition++ = constant; } for (auto& procedure : $3) { *definition++ = procedure; } driver.tree = std::make_unique(elna::source::position{}, std::move(definitions), std::move($4), std::move($5)); } block: constant_part variable_part statement { std::vector definitions($1.size()); std::vector::iterator definition = definitions.begin(); for (auto& constant : $1) { *definition++ = constant; } $$ = new elna::source::block(elna::source::position{}, std::move(definitions), std::move($2), std::move($3)); }; procedure_definition: PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON { $$ = new elna::source::procedure_definition(elna::source::position{}, std::move($2), $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)); } procedure_part: /* no procedure definitions */ {} | procedure_definitions { std::swap($$, $1); } integer_literal: INTEGER { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); }; float_literal: FLOAT { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); }; character_literal: CHARACTER { $$ = new elna::source::char_literal(elna::source::make_position(@1), $1.at(0)); }; string_literal: STRING { $$ = new elna::source::string_literal(elna::source::make_position(@1), $1); }; boolean_literal: BOOLEAN { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); }; compound_statement: BEGIN_BLOCK optional_statements END_BLOCK { $$ = new elna::source::compound_statement(elna::source::make_position(@1)); std::swap($$->statements(), $2); } assign_statement: designator_expression ASSIGNMENT expression { $$ = new elna::source::assign_statement(elna::source::make_position(@1), $1, $3); } call_statement: IDENTIFIER actual_parameter_list { $$ = new elna::source::call_statement(elna::source::make_position(@1), $1); std::swap($$->arguments(), $2); } while_statement: WHILE expression DO statement { $$ = new elna::source::while_statement(elna::source::make_position(@1), $2, $4); } if_statement: IF expression THEN statement { $$ = new elna::source::if_statement(elna::source::make_position(@1), $2, $4); } | IF expression THEN statement ELSE statement { $$ = new elna::source::if_statement(elna::source::make_position(@1), $2, $4, $6); } pointer: integer_literal { $$ = $1; } | float_literal { $$ = $1; } | boolean_literal { $$ = $1; } | character_literal { $$ = $1; } | string_literal { $$ = $1; } | designator_expression { $$ = $1; } | LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); } summand: factor { $$ = std::move($1); } | factor MULTIPLICATION factor { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '*'); } | factor DIVISION factor { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '/'); } factor: AT pointer { $$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '@'); } | pointer { $$ = $1; } comparand: summand PLUS summand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '+'); } | summand MINUS summand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '-'); } | summand { $$ = std::move($1); } expression: comparand EQUALS comparand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '='); } | comparand NOT_EQUAL comparand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'n'); } | comparand LESS_THAN comparand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '<'); } | comparand GREATER_THAN comparand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '>'); } | comparand LESS_EQUAL comparand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '<'); } | comparand GREATER_EQUAL comparand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '>'); } | comparand { $$ = std::move($1); } expressions: expression COMMA expressions { std::swap($$, $3); $$.emplace($$.cbegin(), $1); } | expression { $$.emplace_back(std::move($1)); } designator_expression: designator_expression LEFT_SQUARE expression RIGHT_SQUARE { $$ = new elna::source::array_access_expression(elna::source::make_position(@1), $1, $3); } | designator_expression DOT IDENTIFIER { $$ = new elna::source::field_access_expression(elna::source::make_position(@1), $1, $3); } | designator_expression HAT { $$ = new elna::source::dereference_expression(elna::source::make_position(@1), $1); } | IDENTIFIER { $$ = new elna::source::variable_expression(elna::source::make_position(@1), $1); } statement: compound_statement { $$ = $1; } | assign_statement { $$ = $1; } | call_statement { $$ = $1; } | while_statement { $$ = $1; } | if_statement { $$ = $1; } statements: statement SEMICOLON statements { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); } | statement { $$.emplace_back($1); } optional_statements: statements { std::swap($$, $1); } | /* no statements */ {} type_expression: ARRAY INTEGER OF type_expression { $$ = new elna::source::array_type_expression(elna::source::make_position(@1), $4, $2); } | HAT type_expression { $$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $2); } | IDENTIFIER { $$ = new elna::source::basic_type_expression(elna::source::make_position(@1), $1); } variable_declaration: IDENTIFIER COLON type_expression { $$ = new elna::source::declaration(elna::source::make_position(@1), $1, $3); }; variable_declarations: variable_declaration COMMA variable_declarations { std::swap($$, $3); $$.emplace($$.cbegin(), $1); } | variable_declaration { $$.emplace_back(std::move($1)); } variable_part: /* no variable declarations */ {} | VAR variable_declarations SEMICOLON { std::swap($$, $2); } constant_definition: IDENTIFIER EQUALS integer_literal { $$ = new elna::source::constant_definition(elna::source::make_position(@1), $1, $3); } constant_definitions: constant_definition COMMA constant_definitions { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); } | constant_definition { $$.emplace_back(std::move($1)); } constant_part: /* no constant definitions */ {} | CONST constant_definitions SEMICOLON { std::swap($$, $2); } type_definition: IDENTIFIER EQUALS type_expression { $$ = new elna::source::type_definition(elna::source::make_position(@1), $1, $3); } type_definitions: type_definition COMMA type_definitions { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); } | type_definition { $$.emplace_back(std::move($1)); } type_part: /* no type definitions */ {} | TYPE type_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); }