%{ #include #include #include "lexer.hpp" #include "interpreter.hpp" #include "parser.hpp" #include "location.hh" // Original yyterminate() macro returns int. Since we're using Bison 3 variants // as tokens, we must redefine it to change type from `int` to `Parser::semantic_type` #define yyterminate() stela::Parser::make_END(stela::location()); // This will track current scanner location. // Action is called when length of the token is known. #define YY_USER_ACTION this->interpreter.increase_location(yyleng); // !!!WARNING!!! // Location API is used, but the location is not initialized, 'cause I'm lazy. When making // a token with make_{something} method you can pass detailed token location. Current location // is accessible with m_driver.location() method. All puzzle elements are there - just // pass location value in every action code block below. I'm going to waste more time writing // this excuse than putting this boilerplate below... // // Location class can be found in location.hh and posistion.hh files. It's just a bit too much // boilerplate for this small example. Bummer. %} %option nodefault noyywrap noyylineno c++ yyclass="Lexer" prefix="stela_" %% [a-z]+ { std::cout << "Scanner: identifier [" << yytext << "]\n"; return stela::Parser::make_STRING(yytext, stela::location()); } \( { std::cout << "Scanner: '('\n"; return stela::Parser::make_LEFTPAR(stela::location()); } \) { std::cout << "Scanner: ')'\n"; return stela::Parser::make_RIGHTPAR(stela::location()); } ; { std::cout << "Scanner: ';'\n"; return stela::Parser::make_SEMICOLON(stela::location()); } , { std::cout << "Scanner: ','\n"; return stela::Parser::make_COMMA(stela::location()); } [\n\t ] { //cout << "Scanner: whitechar (ignored)" << endl; } [1-9][0-9]* { std::cout << "Scanner: decimal number: " << yytext << '\n'; uint64_t number = strtoull(yytext, 0, 10); return stela::Parser::make_NUMBER(number, stela::location()); } . { std::cout << "Scanner: unknown character [" << yytext << "]\n"; } <> { return yyterminate(); } %%