stela/parser.y

126 lines
3.6 KiB
Plaintext

%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 <iostream>
#include <string>
#include <vector>
#include <cstdint>
#include "command.hpp"
namespace stela {
class Lexer;
class Interpreter;
}
}
%code top {
#include <iostream>
#include <cstdint>
#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 <std::string> STRING "string";
%token <uint64_t> NUMBER "number";
%token LEFTPAR "leftpar";
%token RIGHTPAR "rightpar";
%token SEMICOLON "semicolon";
%token COMMA "comma";
%type <stela::Command> command;
%type <std::vector<uint64_t>> 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<uint64_t> &args = $3;
std::cout << "function: " << id << ", " << args.size() << '\n';
$$ = Command(id, args);
}
;
arguments : NUMBER {
uint64_t number = $1;
$$ = std::vector<uint64_t>();
$$.push_back(number);
std::cout << "first argument: " << number << '\n';
}
| arguments COMMA NUMBER {
uint64_t number = $3;
std::vector<uint64_t> &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