-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.c
130 lines (118 loc) · 3.32 KB
/
parse.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdio.h>
#include <glib.h>
#include "parse.h"
#include "constant.h"
#include "pt-load.h"
#include "pt-relation.h"
#include "pt-variable.h"
#include "pt-variable-ref.h"
static G_GNUC_MALLOC ParseTree* ptree_alloc(enum PTType type);
/** Accepts a node type, the line number and column it came from, and a list of
* of GNode*'s which should be its children. The list MUST be NULL-terminated,
* even if it is empty. */
G_GNUC_WARN_UNUSED_RESULT G_GNUC_NULL_TERMINATED G_GNUC_MALLOC GNode*
mk_ptree_node(enum PTType type, gsize line, gsize column, ...)
{
va_list ap;
GenericParseTree *gt;
GNode *head, *add;
gt = (GenericParseTree *) ptree_alloc(type);
gt->meta.type = type;
gt->meta.line_no = line;
gt->meta.col_no = column;
head = g_node_new(gt);
va_start(ap, column);
while((add = va_arg(ap, GNode*)) != NULL) {
g_node_append(head, add);
}
va_end(ap);
return head;
}
/* a generic parse-tree print function, that only assumes it is getting a parse
* tree node. */
static void
pr_unknown(const GNode *gn)
{
const ParseTree tdata = PT_META(gn);
switch(tdata.type) {
case PT_QUERY: g_print("query"); break;
case PT_QUIT: g_print("quit"); break;
default: g_print("(unknown type)"); break;
}
#ifdef _LP64
g_print(" at line %lu, column %lu\n", tdata.line_no, tdata.col_no);
#else
g_print(" at line %u, column %u\n", tdata.line_no, tdata.col_no);
#endif
}
static G_GNUC_MALLOC ParseTree*
ptree_alloc(enum PTType type)
{
ParseTree* retval = NULL;
switch(type) {
case PT_LIST: /* special case. */
retval = (ParseTree*) g_new0(GenericParseTree, 1);
retval->vtable.print = pr_unknown;
break;
case PT_QUERY: /* special case */
retval = (ParseTree*) g_new0(GenericParseTree, 1);
retval->vtable.print = pr_unknown;
break;
case PT_QUIT: /* special case. */
retval = (ParseTree*) g_new0(GenericParseTree, 1);
retval->vtable.print = pr_unknown;
break;
case PT_CONSTANT:
retval = (ParseTree*) pt_constant_alloc();
break;
case PT_LOAD:
retval = (ParseTree*) pt_load_alloc();
break;
case PT_RELATION:
retval = (ParseTree*) pt_relation_alloc();
break;
case PT_VARIABLE:
retval = (ParseTree*) pt_variable_alloc();
break;
case PT_VARIABLE_REFERENCE:
retval = (ParseTree*) pt_vref_alloc();
break;
}
g_assert(retval != NULL && "forgot to add alloc case?");
return retval;
}
static const int VISIT_ALL_NODES = -1;
static const gboolean CONTINUE_TRAVERSAL = FALSE;
static const gboolean STOP_TRAVERSAL = TRUE;
static gboolean
destroy_(GNode* node, G_GNUC_UNUSED gpointer udata)
{
if(PT_META(node).vtable.destroy) {
PT_META(node).vtable.destroy(node);
}
g_free(node->data);
return CONTINUE_TRAVERSAL;
}
/** Calls the destructor on every element of the tree. */
void
destroy(GNode* root)
{
g_debug("Destroying %p...", root);
g_node_traverse(root, G_POST_ORDER, G_TRAVERSE_ALL, -1, destroy_, NULL);
g_node_destroy(root);
}
static gboolean
print_(GNode* node, G_GNUC_UNUSED gpointer udata)
{
if(PT_META(node).vtable.print) {
PT_META(node).vtable.print(node);
}
return CONTINUE_TRAVERSAL;
}
void
pt_print(GNode* root)
{
g_node_traverse(root, G_PRE_ORDER, G_TRAVERSE_LEAVES, VISIT_ALL_NODES,
print_, stdout);
g_print("\n");
}