/* * 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 THEN ELSE RETURN %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD POINTER TO UNION %token BEGIN_BLOCK END_BLOCK EXTERN %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA %token AND OR NOT %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS %token PLUS MINUS MULTIPLICATION DIVISION %token ASSIGNMENT COLON HAT AT %type 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 logical_operand; %type > expressions actual_parameter_list; %type designator_expression; %type assign_statement; %type call_expression; %type while_statement; %type if_statement; %type return_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; %type > field_declaration; %type >> field_list; %% program: type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT { std::vector definitions($1.size() + $3.size()); std::vector::iterator definition = definitions.begin(); std::vector value_definitions($2.size() + $4.size()); std::vector::iterator value_definition = value_definitions.begin(); for (auto type : $1) { *definition++ = type; } for (auto constant : $2) { *value_definition++ = constant; } for (auto procedure : $3) { *definition++ = procedure; } for (auto variable : $4) { *value_definition++ = variable; } auto tree = new elna::source::program(elna::source::position{}, std::move(definitions), std::move(value_definitions), std::move($6)); driver.tree.reset(tree); } block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK { std::vector definitions($1.size() + $2.size()); std::vector::iterator definition = definitions.begin(); for (auto constant : $1) { *definition++ = constant; } for (auto variable : $2) { *definition++ = variable; } $$ = new elna::source::block(elna::source::position{}, std::move(definitions), std::move($4)); } procedure_definition: PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON { $$ = new elna::source::procedure_definition(elna::source::position{}, $2, std::move($3), nullptr, $5); } | PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON { $$ = new elna::source::procedure_definition(elna::source::position{}, $2, std::move($3), nullptr, nullptr); } | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON { $$ = new elna::source::procedure_definition(elna::source::position{}, $2, std::move($3), $5, $7); } | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON { $$ = new elna::source::procedure_definition(elna::source::position{}, $2, std::move($3), $5, nullptr); } 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); } assign_statement: designator_expression ASSIGNMENT expression { $$ = new elna::source::assign_statement(elna::source::make_position(@1), $1, $3); } call_expression: IDENTIFIER actual_parameter_list { $$ = new elna::source::call_expression(elna::source::make_position(@1), $1); std::swap($$->arguments(), $2); } while_statement: WHILE expression DO optional_statements END_BLOCK { auto body = new elna::source::compound_statement(elna::source::make_position(@3), std::move($4)); $$ = new elna::source::while_statement(elna::source::make_position(@1), $2, body); } if_statement: IF expression THEN optional_statements END_BLOCK { auto then = new elna::source::compound_statement(elna::source::make_position(@3), std::move($4)); $$ = new elna::source::if_statement(elna::source::make_position(@1), $2, then); } | IF expression THEN optional_statements ELSE optional_statements END_BLOCK { auto then = new elna::source::compound_statement(elna::source::make_position(@3), std::move($4)); auto _else = new elna::source::compound_statement(elna::source::make_position(@5), std::move($6)); $$ = new elna::source::if_statement(elna::source::make_position(@1), $2, then, _else); } return_statement: RETURN expression { $$ = new elna::source::return_statement(elna::source::make_position(@1), $2); } literal: INTEGER { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); } | FLOAT { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); } | BOOLEAN { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); } | CHARACTER { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1.at(0)); } | STRING { $$ = new elna::source::string_literal(elna::source::make_position(@1), $1); } pointer: 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, '@'); } | NOT 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); } logical_operand: 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 { $$ = $1; } expression: logical_operand AND logical_operand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'a'); } | logical_operand OR logical_operand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'o'); } | logical_operand { $$ = $1; } | call_expression { $$ = $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: assign_statement { $$ = $1; } | while_statement { $$ = $1; } | if_statement { $$ = $1; } | return_statement { $$ = $1; } | expression { $$ = new elna::source::expression_statement(elna::source::make_position(@1), $1); } statements: statement SEMICOLON statements { std::swap($$, $3); $$.emplace($$.cbegin(), $1); } | statement { $$.push_back($1); } optional_statements: statements { std::swap($$, $1); } | /* no statements */ {} field_declaration: IDENTIFIER COLON type_expression { $$ = std::make_pair($1, $3); } field_list: field_declaration SEMICOLON field_list { std::swap($$, $3); $$.emplace($$.cbegin(), $1); } | field_declaration { $$.emplace_back($1); } type_expression: ARRAY INTEGER OF type_expression { $$ = new elna::source::array_type_expression(elna::source::make_position(@1), $4, $2); } | POINTER TO type_expression { $$ = new elna::source::pointer_type_expression(elna::source::make_position(@1), $3); } | RECORD field_list END_BLOCK { $$ = new elna::source::record_type_expression(elna::source::make_position(@1), std::move($2)); } | UNION field_list END_BLOCK { $$ = new elna::source::union_type_expression(elna::source::make_position(@1), std::move($2)); } | IDENTIFIER { $$ = new elna::source::basic_type_expression(elna::source::make_position(@1), $1); } variable_declaration: IDENTIFIER COLON type_expression { $$ = new elna::source::variable_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 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); }