/* See https://www.gnu.org/software/bison/manual/html_node/Calc_002b_002b-Scanner.html */ %{ /* -*- C++ -*- */ # include # include # include # include // strerror # include # include "driver.hh" # include "parser.hh" %} %{ #if defined __clang__ # define CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) #endif // Clang and ICC like to pretend they are GCC. #if defined __GNUC__ && !defined __clang__ && !defined __ICC # define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #endif // Pacify warnings in yy_init_buffer (observed with Flex 2.6.4) // and GCC 6.4.0, 7.3.0 with -O3. #if defined GCC_VERSION && 600 <= GCC_VERSION # pragma GCC diagnostic ignored "-Wnull-dereference" #endif // This example uses Flex's C backend, yet compiles it as C++. // So expect warnings about C style casts and NULL. #if defined CLANG_VERSION && 500 <= CLANG_VERSION # pragma clang diagnostic ignored "-Wold-style-cast" # pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #elif defined GCC_VERSION && 407 <= GCC_VERSION # pragma GCC diagnostic ignored "-Wold-style-cast" # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #endif #define FLEX_VERSION (YY_FLEX_MAJOR_VERSION * 100 + YY_FLEX_MINOR_VERSION) // Old versions of Flex (2.5.35) generate an incomplete documentation comment. // // In file included from src/scan-code-c.c:3: // src/scan-code.c:2198:21: error: empty paragraph passed to '@param' command // [-Werror,-Wdocumentation] // * @param line_number // ~~~~~~~~~~~~~~~~~^ // 1 error generated. #if FLEX_VERSION < 206 && defined CLANG_VERSION # pragma clang diagnostic ignored "-Wdocumentation" #endif // Old versions of Flex (2.5.35) use 'register'. Warnings introduced in // GCC 7 and Clang 6. #if FLEX_VERSION < 206 # if defined CLANG_VERSION && 600 <= CLANG_VERSION # pragma clang diagnostic ignored "-Wdeprecated-register" # elif defined GCC_VERSION && 700 <= GCC_VERSION # pragma GCC diagnostic ignored "-Wregister" # endif #endif #if FLEX_VERSION < 206 # if defined CLANG_VERSION # pragma clang diagnostic ignored "-Wconversion" # pragma clang diagnostic ignored "-Wdocumentation" # pragma clang diagnostic ignored "-Wshorten-64-to-32" # pragma clang diagnostic ignored "-Wsign-conversion" # elif defined GCC_VERSION # pragma GCC diagnostic ignored "-Wconversion" # pragma GCC diagnostic ignored "-Wsign-conversion" # endif #endif %} %option noyywrap nounput noinput batch debug %{ // A number symbol corresponding to the value in S. yy::parser::symbol_type make_NUMBER (const std::string &s, const yy::parser::location_type& loc); // Note: the symbol_type is definded in parser.yy by declaring // %define api.token.constructor and following lines. See explanation there or // https://www.gnu.org/software/bison/manual/html_node/Complete-Symbols.html %} id [a-zA-Z][a-zA-Z_0-9]* int [0-9]+ blank [ \t\r] %{ // Code run each time a pattern is matched. // The macro YY_USER_ACTION can be defined to provide an action which is always executed prior to the matched rule's action. // http://dinosaur.compilertools.net/flex/flex_14.html // yyleng is a lex global variable that is always the length of the token you just read in # define YY_USER_ACTION loc.columns (yyleng); %} %% %{ // A handy shortcut to the location held by the driver. yy::location& loc = drv.location; // Code run each time yylex is called. // The lexical analyzer function, yylex, recognizes tokens from the input stream and returns them to the parser. loc.step (); %} {blank}+ loc.step (); \n+ loc.lines (yyleng); loc.step (); "-" return yy::parser::make_MINUS (loc); "+" return yy::parser::make_PLUS (loc); "*" return yy::parser::make_STAR (loc); "/" return yy::parser::make_SLASH (loc); "(" return yy::parser::make_LPAREN (loc); ")" return yy::parser::make_RPAREN (loc); ":=" return yy::parser::make_ASSIGN (loc); {int} return make_NUMBER (yytext, loc); // make_NUMBER is defined below and overwrites the bison generated one {id} return yy::parser::make_IDENTIFIER (yytext, loc); // the function is generated by bison . { throw yy::parser::syntax_error (loc, "invalid character: " + std::string(yytext)); } <> return yy::parser::make_END (loc); %% // overwrite the bison generated make_NUMBER function, because we want to add some functionality yy::parser::symbol_type make_NUMBER (const std::string &s, const yy::parser::location_type& loc) { errno = 0; long n = strtol (s.c_str(), NULL, 10); if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) throw yy::parser::syntax_error (loc, "integer is out of range: " + s); return yy::parser::make_NUMBER ((int) n, loc); } void driver::scan_begin () { yy_flex_debug = trace_scanning; if (file.empty () || file == "-") yyin = stdin; else if (!(yyin = fopen (file.c_str (), "r"))) { std::cerr << "cannot open " << file << ": " << strerror(errno) << '\n'; exit (EXIT_FAILURE); } } void driver::scan_end () { fclose (yyin); }