diff 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 diff
--- a/parser.yy	Thu May 23 13:42:57 2019 -0400
+++ b/parser.yy	Thu May 23 17:57:20 2019 -0400
@@ -14,30 +14,49 @@
 #include "interpreter.h"
 #include "parser.h"
 
-namespace parser
+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;
 
-  // Used to tell readline whether to display the prompt indicating
-  // a continuation line.  Is there any way we could do this job
-  // without a global variable?
-  bool beg_of_stmt = true;
-
-  static int yylex (void);
+  static int yylex (YYSTYPE& token_value);
 }
 
-static void yyerror (char const *);
-
-static void emit_error (const char *msg);
-static void emit_result (double 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 '-' '+'
@@ -60,63 +79,63 @@
           { }
         | exp ';'
           {
-            emit_result ($1);
-            parser::beg_of_stmt = true;
+            parser.emit_result ($1);
+            parser.beg_of_stmt (true);
           }
-;
+        ;
 
 exp     : NUM
           {
             $$ = $1;
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         | exp '+' exp
           {
             $$ = $1 + $3;
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         | exp '-' exp
           {
             $$ = $1 - $3;
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         | exp '*' exp
           {
             $$ = $1 * $3;
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         | exp '/' exp
           {
             $$ = $1 / $3;
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         | '-' exp  %prec NEG
           {
             $$ = -$2;
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         | exp '^' exp
           {
             $$ = std::pow ($1, $3);
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         | '(' exp ')'
           {
             $$ = $2;
-            parser::beg_of_stmt = false;
+            parser.beg_of_stmt (false);
           }
         ;
 
 %%
 
-namespace parser
+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 (void)
+  static int yylex (YYSTYPE& token_value)
   {
     int c;
 
@@ -132,7 +151,7 @@
       {
         int chars_read = 0;
         bufptr--;
-        sscanf (&buf[bufptr], "%lf%n", &yylval, &chars_read);
+        sscanf (&buf[bufptr], "%lf%n", &token_value, &chars_read);
         bufptr += chars_read;
         return NUM;
       }
@@ -141,27 +160,7 @@
     return c;
   }
 
-  // If we defined a parser object, the parser state could be a
-  // member variable of that object.
-
-  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)
+  int parser::parse_and_execute (const std::string& line)
   {
     bufptr = 0;
     chunk_size = line.length ();
@@ -171,30 +170,32 @@
 
     do
       {
-        ::yychar = yylex ();
+        YYSTYPE token_value;
+        int input_char = yylex (token_value);
 
-        if (::yychar < 0)
+        if (input_char < 0)
           return -1;
 
-        status = yypush_parse (ps);
+        status = yypush_parse (static_cast<yypstate *> (m_parser_state),
+                               input_char, &token_value, *this);
       }
     while (status == YYPUSH_MORE);
 
     return -2;
   }
-}
 
-static void yyerror (char const *msg)
-{
-  emit_error (msg);
+  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 emit_error (const char *msg)
+static void yyerror (calc::parser& parser, char const *msg)
 {
-  calc::interpreter::the_interpreter->emit_error (msg);
+  parser.emit_error (msg);
 }
-
-static void emit_result (double value)
-{
-  calc::interpreter::the_interpreter->emit_result (value);
-}
\ No newline at end of file