bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 4/4] glr2.cc: examples: use values to represent the AST


From: Akim Demaille
Subject: [PATCH 4/4] glr2.cc: examples: use values to represent the AST
Date: Fri, 18 Dec 2020 07:42:04 +0100

Currently we are using pointers.  The whole point of
glr2.cc (vs. glr.cc) is precisely to allow genuine C++ objects to be
semantic values.  Let's make that work.

* data/skeletons/glr2.cc (glr_state::glr_state): Be sure to initialize
yysval.
(glr_state): Add copy-ctor, assignment and dtor.
(glr_state::copyFrom): Be sure to initialize the destination if it was
not.
* examples/c++/glr/ast.hh: Rewrite so that we use genuine objects,
rather than a traditional OOP hierarchy that requires to deal with
pointers.
With help from Bruno Belanyi <bruno.belanyi@epita.fr>.
* examples/c++/glr/c++-types.yy: Remove memory management.
Use true objects.
(main): Don't reach yydebug directly.
---
 THANKS                        |   1 +
 TODO                          |  17 ++++
 data/skeletons/glr2.cc        |  46 +++++++---
 examples/c++/glr/ast.hh       | 157 +++++++++++++++++++++++-----------
 examples/c++/glr/c++-types.yy |  69 ++++++++-------
 5 files changed, 192 insertions(+), 98 deletions(-)

diff --git a/THANKS b/THANKS
index 195153a6..a5a99f12 100644
--- a/THANKS
+++ b/THANKS
@@ -34,6 +34,7 @@ Bob Rossi                 bob@brasko.net
 Brandon Lucia             blucia@gmail.com
 Brooks Moses              bmoses@google.com
 Bruce Lilly               blilly@erols.com
+Bruno Belanyi             bruno.belanyi@epita.fr
 Bruno Haible              bruno@clisp.org
 Charles-Henri de Boysson  de-boy_c@epita.fr
 Christian Burger          cburger@sunysb.edu
diff --git a/TODO b/TODO
index b857199a..7992d2ba 100644
--- a/TODO
+++ b/TODO
@@ -9,6 +9,23 @@ Clarify that rule numbers in the skeletons are 1-based.
 There are many macros that should obey api.prefix: YY_CPLUSPLUS, YY_MOVE,
 etc.
 
+** YYDEBUG etc. in C++
+Discourage the use of YYDEBUG in C++ (see thread with Jot).  Stop supporting
+#define YYSTYPE by the user.
+
+Add value_type as a synonym for semantic_type.
+
+** Asymmetries
+In glr_state, we have yysval and yylloc.  It should be yyval/yyloc (and
+yylval/yylloc when referring to the lookahead).  glr.c should
+s/yysval/yyval/.
+
+Also
+
+    yystack.yyglrShift (create_state_set_index(0), 0, 0, yylval, &yylloc);
+
+Why are yylval and yylloc treated differently?
+
 ** yyerrok in Java
 And add tests in calc.at, to prepare work for D.
 
diff --git a/data/skeletons/glr2.cc b/data/skeletons/glr2.cc
index e6d4717d..98275515 100644
--- a/data/skeletons/glr2.cc
+++ b/data/skeletons/glr2.cc
@@ -779,16 +779,15 @@ public:
   {}
 
   /// Build with a semantic value.
-  glr_state(state_num lrState, size_t posn, YYSTYPE sval]b4_locations_if([[, 
YYLTYPE loc]])[)
-    : yyresolved(true)
-    , yylrState(lrState)
-    , yyposn(posn)
-    , yypred(0)]b4_locations_if([[
-    , yyloc(loc)]])[]b4_parse_assert_if([[
+  glr_state (state_num lrState, size_t posn, YYSTYPE sval]b4_locations_if([[, 
YYLTYPE loc]])[)
+    : yyresolved (true)
+    , yylrState (lrState)
+    , yyposn (posn)
+    , yypred (0)
+    , yysval (sval)]b4_locations_if([[
+    , yyloc (loc)]])[]b4_parse_assert_if([[
     , magic_ (MAGIC)]])[
-  {
-    semanticVal() = sval;
-  }
+  {}
 
   /// Build with a semantic option.
   glr_state(state_num lrState, size_t posn)
@@ -800,17 +799,42 @@ public:
     , magic_ (MAGIC)]])[
   {}
 
+  glr_state (const glr_state& other)]b4_parse_assert_if([[
+    : magic_ (MAGIC)]])[
+  {
+    // FIXME: Do it right.
+    copyFrom (other);
+  }
+
+  ~glr_state ()
+  {]b4_parse_assert_if([[
+    check_ ();
+    magic_ = 0;]])[
+    // FIXME: destroy the value.
+  }
+
+  glr_state& operator= (const glr_state& other)
+  {
+    copyFrom (other);
+    return *this;
+  }
+
   void copyFrom (const glr_state& other)
   {]b4_parse_assert_if([[
     check_ ();
     other.check_ ();]])[
-    *this = other;
+    if (!yyresolved && other.yyresolved)
+      new (&yysval) YYSTYPE;
+    yyresolved = other.yyresolved;
+    yylrState = other.yylrState;
+    yyposn = other.yyposn;
     setPred(other.pred());
     if (other.yyresolved) {
       semanticVal() = other.semanticVal();
     } else {
       setFirstVal(other.firstVal());
-    }
+    }]b4_locations_if([[
+    yyloc = other.yyloc;]])[
   }
 
   /** Type tag for the semantic value.  If true, yysval applies, otherwise
diff --git a/examples/c++/glr/ast.hh b/examples/c++/glr/ast.hh
index 223fc119..b5d125ee 100644
--- a/examples/c++/glr/ast.hh
+++ b/examples/c++/glr/ast.hh
@@ -16,102 +16,155 @@
 */
 
 #include <iostream>
+#include <memory>
 
-#if __cplusplus < 201103L
-# define nullptr 0
-#endif
+// Type erasure 101 <https://stackoverflow.com/a/26199467/1353549>.
+class NodeInterface;
 
 class Node
 {
 public:
-  Node ()
-    : parents_ (0)
-  {}
+  Node (const Node& node) = default;
+  Node (Node&& node) = default;
+  Node () = default;
+  ~Node () = default;
 
-  virtual ~Node ()
-  {}
+  template <typename T,
+            // SFINAE block using this ctor as a copy/move ctor:
+            std::enable_if_t<!std::is_same<Node, std::decay_t<T>>::value, 
int>* = nullptr>
+  Node (T&& t);
 
-  void free ()
+  Node& operator= (const Node& node) = default;
+  Node& operator= (Node&& node) = default;
+
+  explicit operator bool () const
   {
-    parents_ -= 1;
-    /* Free only if 0 (last parent) or -1 (no parents).  */
-    if (parents_ <= 0)
-      delete this;
+    return impl_ != nullptr;
   }
 
-  virtual std::ostream& print (std::ostream& o) const = 0;
+  std::ostream& print (std::ostream& o) const;
 
-protected:
-  friend class Nterm;
-  friend class Term;
-  int parents_;
+  std::shared_ptr<NodeInterface> impl_;
 };
 
-
 static std::ostream&
 operator<< (std::ostream& o, const Node &node)
 {
   return node.print (o);
 }
 
-class Nterm : public Node
+class NodeInterface
 {
 public:
-  Nterm (char const *form,
-         Node *child0 = nullptr, Node *child1 = nullptr, Node *child2 = 
nullptr)
-    : form_ (form)
+  virtual ~NodeInterface () {}
+  virtual std::ostream& print (std::ostream& o) const = 0;
+};
+
+
+std::ostream& Node::print (std::ostream& o) const
+{
+  if (impl_)
+    impl_->print (o);
+  return o;
+}
+
+
+template <typename T,
+          std::enable_if_t<!std::is_same<nullptr_t, std::decay_t<T>>::value, 
int>* = nullptr>
+struct NodeImpl : public NodeInterface
+{
+  template <typename U>
+  explicit NodeImpl (U&& u)
+    : t{std::forward<U> (u)}
+  {}
+  virtual ~NodeImpl () = default;
+  virtual std::ostream& print (std::ostream& o) const
   {
-    children_[0] = child0;
-    if (child0)
-      child0->parents_ += 1;
-    children_[1] = child1;
-    if (child1)
-      child1->parents_ += 1;
-    children_[2] = child2;
-    if (child2)
-      child2->parents_ += 1;
+    return o << t;
   }
 
-  ~Nterm ()
+  T t;
+};
+
+
+template <typename T,
+          std::enable_if_t<!std::is_same<Node, std::decay_t<T>>::value, int>*>
+Node::Node (T&& t)
+  : impl_ (new NodeImpl<std::decay_t<T>>{std::forward<T> (t)})
+{}
+
+class Nterm
+{
+public:
+  Nterm (std::string form,
+         Node child0 = Node (), Node child1 = Node (), Node child2 = Node ())
+    : form_ (std::move (form))
   {
-    for (int i = 0; i < 3; ++i)
-      if (children_[i])
-        children_[i]->free ();
+    children_[0] = child0;
+    children_[1] = child1;
+    children_[2] = child2;
   }
 
-  std::ostream& print (std::ostream& o) const
+  friend std::ostream& operator<< (std::ostream& o, const Nterm& t)
   {
-    o << form_;
-    if (children_[0])
+    o << t.form_;
+    if (t.children_[0])
       {
-        o << '(' << *children_[0];
-        if (children_[1])
-          o << ", " << *children_[1];
-        if (children_[2])
-            o << ", " << *children_[2];
+        o << '(' << t.children_[0];
+        if (t.children_[1])
+          o << ", " << t.children_[1];
+        if (t.children_[2])
+          o << ", " << t.children_[2];
         o << ')';
       }
     return o;
   }
 
 private:
-  char const *form_;
-  Node *children_[3];
+  std::string form_;
+  Node children_[3];
 };
 
-class Term : public Node
+class Term
 {
 public:
-  Term (const std::string &text)
-    : text_ (text)
+  Term (std::string text)
+    : text_ (std::move (text))
   {}
 
-  std::ostream& print (std::ostream& o) const
+  friend std::ostream& operator<< (std::ostream& o, const Term& t)
   {
-    o << text_;
-    return o;
+    return o << t.text_;
   }
 
 private:
   std::string text_;
 };
+
+#ifdef TEST
+int main ()
+{
+  Node n0;
+  std::cout << n0 << '\n';
+
+  Node n;
+  n = n0;
+  std::cout << n0 << '\n';
+
+  Term t1 = Term ("T");
+  std::cout << t1 << '\n';
+
+  n = t1;
+  std::cout << n << '\n';
+  std::cout << Nterm ("+", t1, t1) << '\n';
+
+  auto n1
+    = Nterm ("<OR>",
+             Nterm ("<declare>", Term ("T"), Term ("x")),
+             Nterm ("<cast>", Term ("x"), Term ("T")));
+  std::cout << n1 << '\n';
+
+  n = n1;
+  std::cout << n1 << '\n';
+}
+#endif
diff --git a/examples/c++/glr/c++-types.yy b/examples/c++/glr/c++-types.yy
index 53262c25..0b20dc8a 100644
--- a/examples/c++/glr/c++-types.yy
+++ b/examples/c++/glr/c++-types.yy
@@ -32,24 +32,25 @@
   #include "ast.hh"
 }
 
-%define api.value.type {Node *}
+%define api.value.type {Node}
 
 %code
 {
+  #include <cassert>
+  #include <cctype>
+  #include <cstdio>
+  #include <cstdlib>
+  #include <cstring>
 
-#include <cassert>
-#include <cctype>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
+  #if __cplusplus < 201103L
+  # define nullptr 0
+  #endif
 
-#if __cplusplus < 201103L
-# define nullptr 0
-#endif
+  static yy::parser::semantic_type
+  stmtMerge (const yy::parser::semantic_type& x0, const 
yy::parser::semantic_type& x1);
 
-  static YYSTYPE stmtMerge (YYSTYPE x0, YYSTYPE x1);
-
-  static int yylex (YYSTYPE *lvalp, YYLTYPE *llocp);
+  static int
+  yylex (yy::parser::semantic_type* val, yy::parser::location_type* loc);
 }
 
 %expect-rr 1
@@ -61,32 +62,29 @@
 %right '='
 %left '+'
 
-%destructor { $$->free (); } stmt expr decl declarator TYPENAME ID
-
 %%
 
 prog : %empty
-     | prog stmt   { std::cout << @2 << ": " << *$2 << '\n'; $2->free (); }
+     | prog stmt   { std::cout << @2 << ": " << $2 << '\n'; }
      ;
 
 stmt : expr ';'  %merge <stmtMerge>     { $$ = $1; }
      | decl      %merge <stmtMerge>
-     | error ';'        { $$ = new Nterm ("<error>"); }
+     | error ';'        { $$ = Nterm ("<error>"); }
      | '@'              { $$ = $1; YYACCEPT; }
      ;
 
 expr : ID
      | TYPENAME '(' expr ')'
-                        { $$ = new Nterm ("<cast>", $3, $1); }
-     | expr '+' expr    { $$ = new Nterm ("+", $1, $3); }
-     | expr '=' expr    { $$ = new Nterm ("=", $1, $3); }
+                        { $$ = Nterm ("<cast>", $3, $1); }
+     | expr '+' expr    { $$ = Nterm ("+", $1, $3); }
+     | expr '=' expr    { $$ = Nterm ("=", $1, $3); }
      ;
 
 decl : TYPENAME declarator ';'
-                        { $$ = new Nterm ("<declare>", $1, $2); }
+                        { $$ = Nterm ("<declare>", $1, $2); }
      | TYPENAME declarator '=' expr ';'
-                        { $$ = new Nterm ("<init-declare>", $1,
-                                          $2, $4); }
+                        { $$ = Nterm ("<init-declare>", $1, $2, $4); }
      ;
 
 declarator
@@ -96,21 +94,22 @@ declarator
 
 %%
 /* A C error reporting function.  */
-void yy::parser::error (const location_type& l, const std::string& m)
+void
+yy::parser::error (const location_type& l, const std::string& m)
 {
   std::cerr << l << ": " << m << '\n';
 }
 
-int yylex (YYSTYPE *lvalp, YYLTYPE *llocp)
+static int
+yylex (yy::parser::semantic_type* lvalp, yy::parser::location_type* llocp)
 {
   static int lineNum = 1;
   static int colNum = 0;
 
   while (1)
     {
-      int c;
       assert (!feof (stdin));
-      c = getchar ();
+      int c = getchar ();
       switch (c)
         {
         case EOF:
@@ -127,9 +126,9 @@ int yylex (YYSTYPE *lvalp, YYLTYPE *llocp)
           break;
         default:
           {
-            int tok;
             llocp->begin.line = llocp->end.line = lineNum;
             llocp->begin.column = colNum;
+            int tok;
             if (isalpha (c))
               {
                 std::string form;
@@ -146,13 +145,13 @@ int yylex (YYSTYPE *lvalp, YYLTYPE *llocp)
                   = isupper (static_cast <unsigned char> (form[0]))
                   ? yy::parser::token::TYPENAME
                   : yy::parser::token::ID;
-                *lvalp = new Term (form);
+                *lvalp = Term (form);
               }
             else
               {
                 colNum += 1;
                 tok = c;
-                *lvalp = nullptr;
+                lvalp = nullptr;
               }
             llocp->end.column = colNum-1;
             return tok;
@@ -161,18 +160,18 @@ int yylex (YYSTYPE *lvalp, YYLTYPE *llocp)
     }
 }
 
-static YYSTYPE
-stmtMerge (YYSTYPE x0, YYSTYPE x1)
+static yy::parser::semantic_type
+stmtMerge (const yy::parser::semantic_type& x0, const 
yy::parser::semantic_type& x1)
 {
-  return new Nterm ("<OR>", x0, x1);
+  return Nterm ("<OR>", x0, x1);
 }
 
 int
 main (int argc, char **argv)
 {
+  yy::parser parse;
   // Enable parse traces on option -p.
   if (1 < argc && strcmp (argv[1], "-p") == 0)
-    yydebug = 1;
-  yy::parser parser;
-  return !!parser.parse ();
+    parse.set_debug_level (1);
+  return parse ();
 }
-- 
2.29.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]