mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
glr2.cc: make the example more C++
Currently the example really looks like C. Instead of a union of structs to implement the AST, use a hierarchy. It would be nice to feature a C++17 version with std variants. * examples/c++/glr/c++-types.yy (Node, free_node, new_nterm) (new_term): Move into... * examples/c++/glr/ast.hh: here, a proper C++ hierarchy.
This commit is contained in:
100
examples/c++/glr/ast.hh
Normal file
100
examples/c++/glr/ast.hh
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#if __cplusplus < 201103L
|
||||||
|
# define nullptr 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Node ()
|
||||||
|
: parents_ (0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~Node ()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void free ()
|
||||||
|
{
|
||||||
|
parents_ -= 1;
|
||||||
|
/* Free only if 0 (last parent) or -1 (no parents). */
|
||||||
|
if (parents_ <= 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::ostream& print (std::ostream& o) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class Nterm;
|
||||||
|
friend class Term;
|
||||||
|
int parents_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static std::ostream&
|
||||||
|
operator<< (std::ostream& o, const Node &node)
|
||||||
|
{
|
||||||
|
return node.print (o);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Nterm : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Nterm (char const *form,
|
||||||
|
Node *child0 = nullptr, Node *child1 = nullptr, Node *child2 = nullptr)
|
||||||
|
: form_ (form)
|
||||||
|
{
|
||||||
|
children_[0] = child0;
|
||||||
|
if (child0)
|
||||||
|
child0->parents_ += 1;
|
||||||
|
children_[1] = child1;
|
||||||
|
if (child1)
|
||||||
|
child1->parents_ += 1;
|
||||||
|
children_[2] = child2;
|
||||||
|
if (child2)
|
||||||
|
child2->parents_ += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Nterm ()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
if (children_[i])
|
||||||
|
children_[i]->free ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& print (std::ostream& o) const
|
||||||
|
{
|
||||||
|
o << form_;
|
||||||
|
if (children_[0])
|
||||||
|
{
|
||||||
|
o << '(' << *children_[0];
|
||||||
|
if (children_[1])
|
||||||
|
o << ", " << *children_[1];
|
||||||
|
if (children_[2])
|
||||||
|
o << ", " << *children_[2];
|
||||||
|
o << ')';
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char const *form_;
|
||||||
|
Node *children_[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Term : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Term (const std::string &text)
|
||||||
|
: text_ (text)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::ostream& print (std::ostream& o) const
|
||||||
|
{
|
||||||
|
o << text_;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string text_;
|
||||||
|
};
|
||||||
@@ -11,24 +11,7 @@
|
|||||||
|
|
||||||
%code requires
|
%code requires
|
||||||
{
|
{
|
||||||
union Node {
|
#include "ast.hh"
|
||||||
struct {
|
|
||||||
int isNterm;
|
|
||||||
int parents;
|
|
||||||
} nodeInfo;
|
|
||||||
struct {
|
|
||||||
int isNterm; /* 1 */
|
|
||||||
int parents;
|
|
||||||
char const *form;
|
|
||||||
union Node *children[3];
|
|
||||||
} nterm;
|
|
||||||
struct {
|
|
||||||
int isNterm; /* 0 */
|
|
||||||
int parents;
|
|
||||||
char *text;
|
|
||||||
} term;
|
|
||||||
};
|
|
||||||
typedef union Node Node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
%define api.value.type {Node *}
|
%define api.value.type {Node *}
|
||||||
@@ -46,10 +29,6 @@
|
|||||||
# define nullptr 0
|
# define nullptr 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Node *new_nterm (char const *form, Node *child0 = nullptr, Node *child1 = nullptr, Node *child2 = nullptr);
|
|
||||||
static Node *new_term (char *);
|
|
||||||
static void free_node (Node *);
|
|
||||||
static std::ostream& operator<< (std::ostream& o, const Node &node);
|
|
||||||
static YYSTYPE stmtMerge (YYSTYPE x0, YYSTYPE x1);
|
static YYSTYPE stmtMerge (YYSTYPE x0, YYSTYPE x1);
|
||||||
|
|
||||||
static int yylex (YYSTYPE *lvalp, YYLTYPE *llocp);
|
static int yylex (YYSTYPE *lvalp, YYLTYPE *llocp);
|
||||||
@@ -64,31 +43,31 @@
|
|||||||
%right '='
|
%right '='
|
||||||
%left '+'
|
%left '+'
|
||||||
|
|
||||||
%destructor { free_node ($$); } stmt expr decl declarator TYPENAME ID
|
%destructor { $$->free (); } stmt expr decl declarator TYPENAME ID
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
prog : %empty
|
prog : %empty
|
||||||
| prog stmt { std::cout << @2 << ": " << *$2 << '\n'; free_node ($2); }
|
| prog stmt { std::cout << @2 << ": " << *$2 << '\n'; $2->free (); }
|
||||||
;
|
;
|
||||||
|
|
||||||
stmt : expr ';' %merge <stmtMerge> { $$ = $1; }
|
stmt : expr ';' %merge <stmtMerge> { $$ = $1; }
|
||||||
| decl %merge <stmtMerge>
|
| decl %merge <stmtMerge>
|
||||||
| error ';' { $$ = new_nterm ("<error>"); }
|
| error ';' { $$ = new Nterm ("<error>"); }
|
||||||
| '@' { $$ = $1; YYACCEPT; }
|
| '@' { $$ = $1; YYACCEPT; }
|
||||||
;
|
;
|
||||||
|
|
||||||
expr : ID
|
expr : ID
|
||||||
| TYPENAME '(' expr ')'
|
| TYPENAME '(' expr ')'
|
||||||
{ $$ = new_nterm ("<cast>", $3, $1); }
|
{ $$ = new Nterm ("<cast>", $3, $1); }
|
||||||
| expr '+' expr { $$ = new_nterm ("+", $1, $3); }
|
| expr '+' expr { $$ = new Nterm ("+", $1, $3); }
|
||||||
| expr '=' expr { $$ = new_nterm ("=", $1, $3); }
|
| expr '=' expr { $$ = new Nterm ("=", $1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
decl : TYPENAME declarator ';'
|
decl : TYPENAME declarator ';'
|
||||||
{ $$ = new_nterm ("<declare>", $1, $2); }
|
{ $$ = new Nterm ("<declare>", $1, $2); }
|
||||||
| TYPENAME declarator '=' expr ';'
|
| TYPENAME declarator '=' expr ';'
|
||||||
{ $$ = new_nterm ("<init-declare>", $1,
|
{ $$ = new Nterm ("<init-declare>", $1,
|
||||||
$2, $4); }
|
$2, $4); }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -98,18 +77,6 @@ declarator
|
|||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
// Enable parse traces on option -p.
|
|
||||||
if (1 < argc && strcmp (argv[1], "-p") == 0)
|
|
||||||
yydebug = 1;
|
|
||||||
yy::parser parser;
|
|
||||||
return !!parser.parse ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* A C error reporting function. */
|
/* 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)
|
||||||
{
|
{
|
||||||
@@ -147,25 +114,21 @@ int yylex (YYSTYPE *lvalp, YYLTYPE *llocp)
|
|||||||
llocp->begin.column = colNum;
|
llocp->begin.column = colNum;
|
||||||
if (isalpha (c))
|
if (isalpha (c))
|
||||||
{
|
{
|
||||||
char buffer[256];
|
std::string form;
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
buffer[i++] = static_cast<char> (c);
|
form += static_cast<char> (c);
|
||||||
colNum += 1;
|
colNum += 1;
|
||||||
assert (i != sizeof buffer - 1);
|
|
||||||
c = getchar ();
|
c = getchar ();
|
||||||
}
|
}
|
||||||
while (isalnum (c) || c == '_');
|
while (isalnum (c) || c == '_');
|
||||||
|
|
||||||
ungetc (c, stdin);
|
ungetc (c, stdin);
|
||||||
buffer[i++] = 0;
|
|
||||||
tok
|
tok
|
||||||
= isupper (static_cast <unsigned char> (buffer[0]))
|
= isupper (static_cast <unsigned char> (form[0]))
|
||||||
? yy::parser::token::TYPENAME
|
? yy::parser::token::TYPENAME
|
||||||
: yy::parser::token::ID;
|
: yy::parser::token::ID;
|
||||||
*lvalp = new_term (strcpy (static_cast<char*> (malloc (i)), buffer));
|
*lvalp = new Term (form);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -180,79 +143,18 @@ int yylex (YYSTYPE *lvalp, YYLTYPE *llocp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Node *
|
|
||||||
new_nterm (char const *form, Node *child0, Node *child1, Node *child2)
|
|
||||||
{
|
|
||||||
Node *res = new Node;
|
|
||||||
res->nterm.isNterm = 1;
|
|
||||||
res->nterm.parents = 0;
|
|
||||||
res->nterm.form = form;
|
|
||||||
res->nterm.children[0] = child0;
|
|
||||||
if (child0)
|
|
||||||
child0->nodeInfo.parents += 1;
|
|
||||||
res->nterm.children[1] = child1;
|
|
||||||
if (child1)
|
|
||||||
child1->nodeInfo.parents += 1;
|
|
||||||
res->nterm.children[2] = child2;
|
|
||||||
if (child2)
|
|
||||||
child2->nodeInfo.parents += 1;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Node *
|
|
||||||
new_term (char *text)
|
|
||||||
{
|
|
||||||
Node *res = new Node;
|
|
||||||
res->term.isNterm = 0;
|
|
||||||
res->term.parents = 0;
|
|
||||||
res->term.text = text;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
free_node (Node *node)
|
|
||||||
{
|
|
||||||
if (!node)
|
|
||||||
return;
|
|
||||||
node->nodeInfo.parents -= 1;
|
|
||||||
/* Free only if 0 (last parent) or -1 (no parents). */
|
|
||||||
if (node->nodeInfo.parents > 0)
|
|
||||||
return;
|
|
||||||
if (node->nodeInfo.isNterm == 1)
|
|
||||||
{
|
|
||||||
free_node (node->nterm.children[0]);
|
|
||||||
free_node (node->nterm.children[1]);
|
|
||||||
free_node (node->nterm.children[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
free (node->term.text);
|
|
||||||
delete node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::ostream&
|
|
||||||
operator<< (std::ostream& o, const Node &node)
|
|
||||||
{
|
|
||||||
if (node.nodeInfo.isNterm == 1)
|
|
||||||
{
|
|
||||||
o << node.nterm.form;
|
|
||||||
if (node.nterm.children[0])
|
|
||||||
{
|
|
||||||
o << '(' << *node.nterm.children[0];
|
|
||||||
if (node.nterm.children[1])
|
|
||||||
o << ", " << *node.nterm.children[1];
|
|
||||||
if (node.nterm.children[2])
|
|
||||||
o << ", " << *node.nterm.children[2];
|
|
||||||
o << ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
o << node.term.text;
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static YYSTYPE
|
static YYSTYPE
|
||||||
stmtMerge (YYSTYPE x0, YYSTYPE x1)
|
stmtMerge (YYSTYPE x0, YYSTYPE x1)
|
||||||
{
|
{
|
||||||
return new_nterm ("<OR>", x0, x1);
|
return new Nterm ("<OR>", x0, x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
// Enable parse traces on option -p.
|
||||||
|
if (1 < argc && strcmp (argv[1], "-p") == 0)
|
||||||
|
yydebug = 1;
|
||||||
|
yy::parser parser;
|
||||||
|
return !!parser.parse ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ $(%C%_c___types_OBJECTS): $(cxx_types_sources_generated)
|
|||||||
if ENABLE_CXX
|
if ENABLE_CXX
|
||||||
check_PROGRAMS += %D%/c++-types
|
check_PROGRAMS += %D%/c++-types
|
||||||
nodist_%C%_c___types_SOURCES = \
|
nodist_%C%_c___types_SOURCES = \
|
||||||
|
%D%/ast.hh \
|
||||||
%D%/c++-types.cc \
|
%D%/c++-types.cc \
|
||||||
%D%/c++-types.hh
|
%D%/c++-types.hh
|
||||||
# Don't use gnulib's system headers.
|
# Don't use gnulib's system headers.
|
||||||
|
|||||||
Reference in New Issue
Block a user