Mercurial > jwe > qt-gui-with-push-parser
view parser.yy @ 13:d179b0bb85e4
make lexer a member function in parser class and eliminate some more global variables
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 23 May 2019 18:26:35 -0400 |
parents | 894be158b32d |
children | 1e5a1e15fa56 |
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); } } 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. int parser::lexer (double& token_value) { int c; if (m_bufptr >= m_chunk_size) return -1; // Skip white space. while ((c = m_buf[m_bufptr++]) == ' ' || c == '\t' || c == '\n') ; // Process numbers. if (c == '.' || isdigit (c)) { int chars_read = 0; m_bufptr--; sscanf (&m_buf[m_bufptr], "%lf%n", &token_value, &chars_read); m_bufptr += chars_read; return NUM; } // Return a single char. return c; } int parser::parse_and_execute (const std::string& line) { m_bufptr = 0; m_chunk_size = line.length (); m_buf = line.c_str (); int status; do { double token_value; int input_char = lexer (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); }