Skip to content

Commit 734eb80

Browse files
committed
glr2.cc: example: use objects (not pointers) to represent the AST
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 <[email protected]>. * examples/c++/glr/c++-types.yy: Remove memory management. Use true objects. (main): Don't reach yydebug directly.
1 parent c2e5124 commit 734eb80

File tree

5 files changed

+192
-98
lines changed

5 files changed

+192
-98
lines changed

THANKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Bob Rossi [email protected]
3434
Brandon Lucia [email protected]
3535
Brooks Moses [email protected]
3636
Bruce Lilly [email protected]
37+
Bruno Belanyi [email protected]
3738
Bruno Haible [email protected]
3839
Charles-Henri de Boysson [email protected]
3940
Christian Burger [email protected]

TODO

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,23 @@ Clarify that rule numbers in the skeletons are 1-based.
99
There are many macros that should obey api.prefix: YY_CPLUSPLUS, YY_MOVE,
1010
etc.
1111

12+
** YYDEBUG etc. in C++
13+
Discourage the use of YYDEBUG in C++ (see thread with Jot). Stop supporting
14+
#define YYSTYPE by the user.
15+
16+
Add value_type as a synonym for semantic_type.
17+
18+
** Asymmetries
19+
In glr_state, we have yysval and yylloc. It should be yyval/yyloc (and
20+
yylval/yylloc when referring to the lookahead). glr.c should
21+
s/yysval/yyval/.
22+
23+
Also
24+
25+
yystack.yyglrShift (create_state_set_index(0), 0, 0, yylval, &yylloc);
26+
27+
Why are yylval and yylloc treated differently?
28+
1229
** yyerrok in Java
1330
And add tests in calc.at, to prepare work for D.
1431

data/skeletons/glr2.cc

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -779,16 +779,15 @@ class glr_state
779779
{}
780780

781781
/// Build with a semantic value.
782-
glr_state(state_num lrState, size_t posn, YYSTYPE sval]b4_locations_if([[, YYLTYPE loc]])[)
783-
: yyresolved(true)
784-
, yylrState(lrState)
785-
, yyposn(posn)
786-
, yypred(0)]b4_locations_if([[
787-
, yyloc(loc)]])[]b4_parse_assert_if([[
782+
glr_state (state_num lrState, size_t posn, YYSTYPE sval]b4_locations_if([[, YYLTYPE loc]])[)
783+
: yyresolved (true)
784+
, yylrState (lrState)
785+
, yyposn (posn)
786+
, yypred (0)
787+
, yysval (sval)]b4_locations_if([[
788+
, yyloc (loc)]])[]b4_parse_assert_if([[
788789
, magic_ (MAGIC)]])[
789-
{
790-
semanticVal() = sval;
791-
}
790+
{}
792791

793792
/// Build with a semantic option.
794793
glr_state(state_num lrState, size_t posn)
@@ -800,17 +799,42 @@ class glr_state
800799
, magic_ (MAGIC)]])[
801800
{}
802801

802+
glr_state (const glr_state& other)]b4_parse_assert_if([[
803+
: magic_ (MAGIC)]])[
804+
{
805+
// FIXME: Do it right.
806+
copyFrom (other);
807+
}
808+
809+
~glr_state ()
810+
{]b4_parse_assert_if([[
811+
check_ ();
812+
magic_ = 0;]])[
813+
// FIXME: destroy the value.
814+
}
815+
816+
glr_state& operator= (const glr_state& other)
817+
{
818+
copyFrom (other);
819+
return *this;
820+
}
821+
803822
void copyFrom (const glr_state& other)
804823
{]b4_parse_assert_if([[
805824
check_ ();
806825
other.check_ ();]])[
807-
*this = other;
826+
if (!yyresolved && other.yyresolved)
827+
new (&yysval) YYSTYPE;
828+
yyresolved = other.yyresolved;
829+
yylrState = other.yylrState;
830+
yyposn = other.yyposn;
808831
setPred(other.pred());
809832
if (other.yyresolved) {
810833
semanticVal() = other.semanticVal();
811834
} else {
812835
setFirstVal(other.firstVal());
813-
}
836+
}]b4_locations_if([[
837+
yyloc = other.yyloc;]])[
814838
}
815839

816840
/** Type tag for the semantic value. If true, yysval applies, otherwise

examples/c++/glr/ast.hh

Lines changed: 105 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,102 +16,155 @@
1616
*/
1717

1818
#include <iostream>
19+
#include <memory>
1920

20-
#if __cplusplus < 201103L
21-
# define nullptr 0
22-
#endif
21+
// Type erasure 101 <https://stackoverflow.com/a/26199467/1353549>.
22+
class NodeInterface;
2323

2424
class Node
2525
{
2626
public:
27-
Node ()
28-
: parents_ (0)
29-
{}
27+
Node (const Node& node) = default;
28+
Node (Node&& node) = default;
29+
Node () = default;
30+
~Node () = default;
3031

31-
virtual ~Node ()
32-
{}
32+
template <typename T,
33+
// SFINAE block using this ctor as a copy/move ctor:
34+
std::enable_if_t<!std::is_same<Node, std::decay_t<T>>::value, int>* = nullptr>
35+
Node (T&& t);
3336

34-
void free ()
37+
Node& operator= (const Node& node) = default;
38+
Node& operator= (Node&& node) = default;
39+
40+
explicit operator bool () const
3541
{
36-
parents_ -= 1;
37-
/* Free only if 0 (last parent) or -1 (no parents). */
38-
if (parents_ <= 0)
39-
delete this;
42+
return impl_ != nullptr;
4043
}
4144

42-
virtual std::ostream& print (std::ostream& o) const = 0;
45+
std::ostream& print (std::ostream& o) const;
4346

44-
protected:
45-
friend class Nterm;
46-
friend class Term;
47-
int parents_;
47+
std::shared_ptr<NodeInterface> impl_;
4848
};
4949

50-
5150
static std::ostream&
5251
operator<< (std::ostream& o, const Node &node)
5352
{
5453
return node.print (o);
5554
}
5655

57-
class Nterm : public Node
56+
class NodeInterface
5857
{
5958
public:
60-
Nterm (char const *form,
61-
Node *child0 = nullptr, Node *child1 = nullptr, Node *child2 = nullptr)
62-
: form_ (form)
59+
virtual ~NodeInterface () {}
60+
virtual std::ostream& print (std::ostream& o) const = 0;
61+
};
62+
63+
64+
std::ostream& Node::print (std::ostream& o) const
65+
{
66+
if (impl_)
67+
impl_->print (o);
68+
return o;
69+
}
70+
71+
72+
template <typename T,
73+
std::enable_if_t<!std::is_same<nullptr_t, std::decay_t<T>>::value, int>* = nullptr>
74+
struct NodeImpl : public NodeInterface
75+
{
76+
template <typename U>
77+
explicit NodeImpl (U&& u)
78+
: t{std::forward<U> (u)}
79+
{}
80+
virtual ~NodeImpl () = default;
81+
virtual std::ostream& print (std::ostream& o) const
6382
{
64-
children_[0] = child0;
65-
if (child0)
66-
child0->parents_ += 1;
67-
children_[1] = child1;
68-
if (child1)
69-
child1->parents_ += 1;
70-
children_[2] = child2;
71-
if (child2)
72-
child2->parents_ += 1;
83+
return o << t;
7384
}
7485

75-
~Nterm ()
86+
T t;
87+
};
88+
89+
90+
template <typename T,
91+
std::enable_if_t<!std::is_same<Node, std::decay_t<T>>::value, int>*>
92+
Node::Node (T&& t)
93+
: impl_ (new NodeImpl<std::decay_t<T>>{std::forward<T> (t)})
94+
{}
95+
96+
class Nterm
97+
{
98+
public:
99+
Nterm (std::string form,
100+
Node child0 = Node (), Node child1 = Node (), Node child2 = Node ())
101+
: form_ (std::move (form))
76102
{
77-
for (int i = 0; i < 3; ++i)
78-
if (children_[i])
79-
children_[i]->free ();
103+
children_[0] = child0;
104+
children_[1] = child1;
105+
children_[2] = child2;
80106
}
81107

82-
std::ostream& print (std::ostream& o) const
108+
friend std::ostream& operator<< (std::ostream& o, const Nterm& t)
83109
{
84-
o << form_;
85-
if (children_[0])
110+
o << t.form_;
111+
if (t.children_[0])
86112
{
87-
o << '(' << *children_[0];
88-
if (children_[1])
89-
o << ", " << *children_[1];
90-
if (children_[2])
91-
o << ", " << *children_[2];
113+
o << '(' << t.children_[0];
114+
if (t.children_[1])
115+
o << ", " << t.children_[1];
116+
if (t.children_[2])
117+
o << ", " << t.children_[2];
92118
o << ')';
93119
}
94120
return o;
95121
}
96122

97123
private:
98-
char const *form_;
99-
Node *children_[3];
124+
std::string form_;
125+
Node children_[3];
100126
};
101127

102-
class Term : public Node
128+
class Term
103129
{
104130
public:
105-
Term (const std::string &text)
106-
: text_ (text)
131+
Term (std::string text)
132+
: text_ (std::move (text))
107133
{}
108134

109-
std::ostream& print (std::ostream& o) const
135+
friend std::ostream& operator<< (std::ostream& o, const Term& t)
110136
{
111-
o << text_;
112-
return o;
137+
return o << t.text_;
113138
}
114139

115140
private:
116141
std::string text_;
117142
};
143+
144+
#ifdef TEST
145+
int main ()
146+
{
147+
Node n0;
148+
std::cout << n0 << '\n';
149+
150+
Node n;
151+
n = n0;
152+
std::cout << n0 << '\n';
153+
154+
Term t1 = Term ("T");
155+
std::cout << t1 << '\n';
156+
157+
n = t1;
158+
std::cout << n << '\n';
159+
std::cout << Nterm ("+", t1, t1) << '\n';
160+
161+
auto n1
162+
= Nterm ("<OR>",
163+
Nterm ("<declare>", Term ("T"), Term ("x")),
164+
Nterm ("<cast>", Term ("x"), Term ("T")));
165+
std::cout << n1 << '\n';
166+
167+
n = n1;
168+
std::cout << n1 << '\n';
169+
}
170+
#endif

0 commit comments

Comments
 (0)