changeset 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
files command-window.cpp interpreter.cpp interpreter.h make-log parser.h parser.yy qt-interpreter.h tty-main.cpp
diffstat 8 files changed, 129 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/command-window.cpp	Thu May 23 13:42:57 2019 -0400
+++ b/command-window.cpp	Thu May 23 17:57:20 2019 -0400
@@ -209,8 +209,11 @@
   {
     erase_line ();
 
+    interpreter& interp = m_interpreter->get_interpreter ();
+    parser& parser = interp.get_parser ();
+
     std::string line = rl_line_buffer ? rl_line_buffer : "";
-    std::string prompt = (rl_prompt && parser::beg_of_stmt) ? rl_prompt : "";
+    std::string prompt = (rl_prompt && parser.beg_of_stmt ()) ? rl_prompt : "";
 
     insert_line (prompt, line);
 
--- a/interpreter.cpp	Thu May 23 13:42:57 2019 -0400
+++ b/interpreter.cpp	Thu May 23 17:57:20 2019 -0400
@@ -14,7 +14,8 @@
   interpreter *interpreter::the_interpreter = nullptr;
 
   interpreter::interpreter (void)
-    : m_error_handler ([] (const char *msg)
+    : m_parser (*this),
+      m_error_handler ([] (const char *msg)
                        { std::cerr << "error: " << msg << std::endl; }),
       m_result_handler ([] (double value)
                         { std::cout << "ans = " << value << std::endl; })
@@ -26,21 +27,14 @@
       }
 
     the_interpreter = this;
-
-    parser::init ();
-  }
-
-  interpreter::~interpreter (void)
-  {
-    parser::fini ();
   }
 
   int interpreter::parse_and_execute (const std::string& line)
   {
-    return parser::parse_and_execute (line);
+    return m_parser.parse_and_execute (line);
   }
 
-  void interpreter::emit_result (double value)
+  void interpreter::emit_result (double value) const
   {
     // Simulate a delay in calculation.
     sleep (1);
@@ -48,7 +42,7 @@
     m_result_handler (value);
   }
 
-  void interpreter::emit_error (const char *msg)
+  void interpreter::emit_error (const char *msg) const
   {
     m_error_handler (msg);
   }
--- a/interpreter.h	Thu May 23 13:42:57 2019 -0400
+++ b/interpreter.h	Thu May 23 17:57:20 2019 -0400
@@ -3,6 +3,8 @@
 
 #include <functional>
 
+#include "parser.h"
+
 namespace calc
 {
   class interpreter
@@ -17,7 +19,9 @@
 
     interpreter& operator = (const interpreter&) = delete;
 
-    ~interpreter (void);
+    ~interpreter (void) = default;
+
+    parser& get_parser (void) { return m_parser; }
 
     int parse_and_execute (const std::string& line);
 
@@ -37,12 +41,14 @@
       return tmp;
     }
 
-    void emit_error (const char *msg);
+    void emit_error (const char *msg) const;
 
-    void emit_result (double value);
+    void emit_result (double value) const;
 
   private:
 
+    parser m_parser;
+
     std::function<void (const char *)> m_error_handler;
     std::function<void (double)> m_result_handler;
   };
--- a/make-log	Thu May 23 13:42:57 2019 -0400
+++ b/make-log	Thu May 23 17:57:20 2019 -0400
@@ -1,14 +1,15 @@
 bison -o parser.cpp parser.yy
-parser.yy:1.1-3: error: syntax error, unexpected identifier
- beg// Infix notation calculator.
- ^~~
-parser.yy:59.1-4: error: syntax error, unexpected identifier:
- line    :     ';'
- ^~~~
-parser.yy:68.1-3: error: syntax error, unexpected identifier:
- exp     : NUM
- ^~~
-parser.yy:118.3-202.0: error: syntax error, unexpected epilogue
- %%
-   ^
-make: *** [Makefile:4: parser.cpp] Error 1
+g++ -c -pipe -g -Wall -W -D_REENTRANT -fPIC -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -isystem /usr/include/libdrm -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o parser.o parser.cpp
+parser.yy:22:15: warning: ‘void calc::yyerror(calc::parser&, const char*)’ declared ‘static’ but never defined [-Wunused-function]
+   static void yyerror (calc::parser&, char const *);
+               ^~~~~~~
+parser.yy:22:15: warning: ‘void calc::yyerror(calc::parser&, const char*)’ used but never defined
+parser.yy:195:13: warning: ‘void yyerror(calc::parser&, const char*)’ defined but not used [-Wunused-function]
+ static void yyerror (calc::parser& parser, char const *msg)
+             ^~~~~~~
+g++ -c -pipe -g -Wall -W -D_REENTRANT -fPIC -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -isystem /usr/include/libdrm -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o tty-main.o tty-main.cpp
+tty-main.cpp: In function ‘int calc::tty_main(int, char**)’:
+tty-main.cpp:29:61: error: cannot resolve overloaded function ‘beg_of_stmt’ based on conversion to type ‘bool’
+         char *tmp = readline (parser::beg_of_stmt ? ">> " : "");
+                                                             ^~
+make: *** [calc.mk:454: tty-main.o] Error 1
--- a/parser.h	Thu May 23 13:42:57 2019 -0400
+++ b/parser.h	Thu May 23 17:57:20 2019 -0400
@@ -1,14 +1,40 @@
 #if ! defined (calc_parse_h)
 #define calc_parse_h 1
 
-namespace parser
+namespace calc
 {
-  extern bool beg_of_stmt;
+  class interpreter;
+
+  class parser
+  {
+  public:
+
+    parser (interpreter&);
+
+    parser (const parser&) = delete;
+
+    parser& operator = (const parser&) = delete;
+
+    ~parser (void);
 
-  extern void init (void);
-  extern void fini (void);
+    bool beg_of_stmt (void) const { return m_beg_of_stmt; }
+
+    void beg_of_stmt (bool flag) { m_beg_of_stmt = flag; }
+
+    int parse_and_execute (const std::string& line);
+
+    void emit_error (const char *msg) const;
 
-  extern int parse_and_execute (const std::string& line);
+    void emit_result (double value) const;
+
+  private:
+
+    interpreter& m_interpreter;
+
+    void *m_parser_state;
+
+    bool m_beg_of_stmt;
+  };
 }
 
 #endif
--- 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
--- a/qt-interpreter.h	Thu May 23 13:42:57 2019 -0400
+++ b/qt-interpreter.h	Thu May 23 17:57:20 2019 -0400
@@ -22,6 +22,8 @@
 
     qt_interpreter& operator = (const qt_interpreter&) = delete;
 
+    interpreter& get_interpreter (void) { return m_interpreter; }
+
   signals:
 
     void result_ready (double);
--- a/tty-main.cpp	Thu May 23 13:42:57 2019 -0400
+++ b/tty-main.cpp	Thu May 23 17:57:20 2019 -0400
@@ -24,9 +24,11 @@
 
     calc::interpreter interp;
 
+    calc::parser& parser = interp.get_parser ();
+
     for (;;)
       {
-        char *tmp = readline (parser::beg_of_stmt ? ">> " : "");
+        char *tmp = readline (parser.beg_of_stmt () ? ">> " : "");
 
         if (! tmp)
           {