%skeleton "lalr1.cc" %require "3.8" %defines %define api.parser.class { Parser } %define api.token.constructor %define api.value.type variant %define parse.assert %define api.namespace { stela } %code requires { #include #include #include #include #include "command.hpp" namespace stela { class Lexer; class Interpreter; } } %code top { #include #include #include "lexer.hpp" #include "parser.hpp" #include "interpreter.hpp" #include "location.hh" static stela::Parser::symbol_type yylex(stela::Lexer& lexer, stela::Interpreter& interpreter) { return lexer.next_token(); } using namespace stela; } %lex-param { stela::Lexer& lexer } %lex-param { stela::Interpreter& interpreter } %parse-param { stela::Lexer& lexer } %parse-param { stela::Interpreter& interpreter } %locations %define parse.trace %define parse.error verbose %define api.token.prefix {TOKEN_} %token END 0 "end of file" %token STRING "string"; %token NUMBER "number"; %token LEFTPAR "leftpar"; %token RIGHTPAR "rightpar"; %token SEMICOLON "semicolon"; %token COMMA "comma"; %type command; %type > arguments; %start program %% program: { std::cout << "*** RUN ***\n"; std::cout << "Type function with list of parmeters. Parameter list can be empty\n" << "or contain positive integers only. Examples: \n" << " * function()\n" << " * function(1,2,3)\n" << "Terminate listing with ; to see parsed AST\n" << "Terminate parser with Ctrl-D\n"; std::cout << '\n' << "prompt> "; interpreter.clear(); } | program command { const Command &cmd = $2; std::cout << "command parsed, updating AST\n"; interpreter.add_command(cmd); std::cout << '\n' << "prompt> "; } | program SEMICOLON { std::cout << "*** STOP RUN ***\n"; std::cout << interpreter.to_string() << '\n'; } ; command : STRING LEFTPAR RIGHTPAR { std::string &id = $1; std::cout << "ID: " << id << '\n'; $$ = Command(id); } | STRING LEFTPAR arguments RIGHTPAR { std::string &id = $1; const std::vector &args = $3; std::cout << "function: " << id << ", " << args.size() << '\n'; $$ = Command(id, args); } ; arguments : NUMBER { uint64_t number = $1; $$ = std::vector(); $$.push_back(number); std::cout << "first argument: " << number << '\n'; } | arguments COMMA NUMBER { uint64_t number = $3; std::vector &args = $1; args.push_back(number); $$ = args; std::cout << "next argument: " << number << ", arg list size = " << args.size() << '\n'; } ; %% void stela::Parser::error(const location &loc , const std::string &message) { // Location should be initialized inside scanner action, but is not in this example. // Let's grab location directly from driver class. // std::cout << "Error: " << message << '\n' << "Location: " << loc << '\n'; std::cout << "Error: " << message << '\n' << "Error location: " << interpreter.location() << '\n'; } // vim: ts=4 sw=4 et