Mercurial > jwe > qt-gui-with-push-parser
diff parser.yy @ 4:0e154787183d
new interpreter and qt_interpreter objects
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Wed, 22 May 2019 17:30:46 -0400 |
parents | parse.yy@08df60a01bc1 |
children | 1b575145197e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parser.yy Wed May 22 17:30:46 2019 -0400 @@ -0,0 +1,201 @@ +// Infix notation calculator. + +%{ + +#define YYSTYPE double + +#include <iostream> +#include <string> + +#include <cctype> +#include <cmath> +#include <cstdio> + +#include "interpreter.h" +#include "main.h" +#include "gui-main.h" +#include "tty-main.h" +#include "parser.h" + +namespace parser +{ + FILE *outfile = 0; + size_t bufptr = 0; + size_t chunk_size = 0; + + const char *buf; + bool beg_of_stmt = true; + + static int yylex (void); + + static void debug_trace (const char *); +} + +static void yyerror (char const *); + +%} + +%define api.push-pull push + +// Bison declarations. +%token NUM +%left '-' '+' +%left '*' '/' +%left NEG // negation--unary minus +%right '^' // exponentiation + +%% + +input : // empty + { } + | input line + | error + { + parser::debug_trace ("ABORT"); + YYABORT; + } + ; + +line : ';' + { } + | exp ';' + { + interpreter::emit_result ($1); + parser::beg_of_stmt = true; + } +; + +exp : NUM + { + parser::debug_trace ("NUM"); + $$ = $1; + parser::beg_of_stmt = false; + } + | exp '+' exp + { + parser::debug_trace ("ADD"); + $$ = $1 + $3; + parser::beg_of_stmt = false; + } + | exp '-' exp + { + parser::debug_trace ("SUB"); + $$ = $1 - $3; + parser::beg_of_stmt = false; + } + | exp '*' exp + { + parser::debug_trace ("MUL"); + $$ = $1 * $3; + parser::beg_of_stmt = false; + } + | exp '/' exp + { + parser::debug_trace ("DIV"); + $$ = $1 / $3; + parser::beg_of_stmt = false; + } + | '-' exp %prec NEG + { + parser::debug_trace ("NEG"); + $$ = -$2; + parser::beg_of_stmt = false; + } + | exp '^' exp + { + parser::debug_trace ("EXP"); + $$ = std::pow ($1, $3); + parser::beg_of_stmt = false; + } + | '(' exp ')' + { + parser::debug_trace ("PAREN"); + $$ = $2; + parser::beg_of_stmt = false; + } + ; + +%% + +namespace parser +{ + // 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 (void) + { + 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", &yylval, &chars_read); + bufptr += chars_read; + return NUM; + } + + // Return a single char. + return c; + } + + static yypstate *ps = 0; + + void init (void) + { + fini (); + + ps = yypstate_new (); + } + + void fini (void) + { + if (ps) + yypstate_delete (ps); + + ps = 0; + } + + int parse_and_execute (const std::string& line) + { + bufptr = 0; + chunk_size = line.length (); + buf = line.c_str (); + + int status; + + do + { + ::yychar = yylex (); + + if (::yychar < 0) + return -1; + + status = yypush_parse (ps); + } + while (status == YYPUSH_MORE); + + return -2; + } + + void debug_trace (const char *msg) + { + if (calc::debug_mode) + std::cerr << msg << std::endl; + } +} + +static void yyerror (char const *msg) +{ + interpreter::emit_error (msg); +}