Mercurial > jwe > qt-gui-with-push-parser
view parser.yy @ 12:894be158b32d
define parser as a class and eliminate some global variables
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 23 May 2019 17:57:20 -0400 |
parents | b652a5528fb1 |
children | d179b0bb85e4 |
line wrap: on
line source
// Infix notation calculator. %{ #define YYSTYPE double #include <iostream> #include <string> #include <cctype> #include <cmath> #include <cstdio> #include "interpreter.h" #include "parser.h" namespace calc { static void *create_parser_state (void); static void delete_parser_state (void *); parser::parser (interpreter& interp) : m_interpreter (interp), m_parser_state (create_parser_state ()), m_beg_of_stmt (true) { } parser::~parser (void) { delete_parser_state (m_parser_state); } void parser::emit_error (const char *msg) const { m_interpreter.emit_error (msg); } void parser::emit_result (double value) const { m_interpreter.emit_result (value); } // For communication between the lexer and parser. size_t bufptr = 0; size_t chunk_size = 0; const char *buf; static int yylex (YYSTYPE& token_value); } static void yyerror (calc::parser&, char const *); %} %define api.pure full %define api.push-pull push %parse-param {calc::parser& parser} // Bison declarations. %token NUM %left '-' '+' %left '*' '/' %left NEG // negation--unary minus %right '^' // exponentiation %% input : // empty { } | input line | error { YYABORT; } ; line : ';' { } | exp ';' { parser.emit_result ($1); parser.beg_of_stmt (true); } ; exp : NUM { $$ = $1; parser.beg_of_stmt (false); } | exp '+' exp { $$ = $1 + $3; parser.beg_of_stmt (false); } | exp '-' exp { $$ = $1 - $3; parser.beg_of_stmt (false); } | exp '*' exp { $$ = $1 * $3; parser.beg_of_stmt (false); } | exp '/' exp { $$ = $1 / $3; parser.beg_of_stmt (false); } | '-' exp %prec NEG { $$ = -$2; parser.beg_of_stmt (false); } | exp '^' exp { $$ = std::pow ($1, $3); parser.beg_of_stmt (false); } | '(' exp ')' { $$ = $2; parser.beg_of_stmt (false); } ; %% namespace calc { // The lexical analyzer returns a double floating point number on the // stack and the token NUM, or the numeric code of the character read // if not a number. It skips all blanks and tabs, and returns -1 for // end-of-input. static int yylex (YYSTYPE& token_value) { int c; if (bufptr >= chunk_size) return -1; // Skip white space. while ((c = buf[bufptr++]) == ' ' || c == '\t' || c == '\n') ; // Process numbers. if (c == '.' || isdigit (c)) { int chars_read = 0; bufptr--; sscanf (&buf[bufptr], "%lf%n", &token_value, &chars_read); bufptr += chars_read; return NUM; } // Return a single char. return c; } int parser::parse_and_execute (const std::string& line) { bufptr = 0; chunk_size = line.length (); buf = line.c_str (); int status; do { YYSTYPE token_value; int input_char = yylex (token_value); if (input_char < 0) return -1; status = yypush_parse (static_cast<yypstate *> (m_parser_state), input_char, &token_value, *this); } while (status == YYPUSH_MORE); return -2; } static void *create_parser_state (void) { return yypstate_new (); } static void delete_parser_state (void *parser_state) { return yypstate_delete (static_cast<yypstate *> (parser_state)); } } static void yyerror (calc::parser& parser, char const *msg) { parser.emit_error (msg); }