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);
+}