-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse.y
286 lines (238 loc) · 6.42 KB
/
parse.y
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/* %define parse.error verbose */
%parse-param { AstWrapper &parsed_result }
%code top{
#include <cstdio>
#include <cstdarg>
#include <iostream>
#include "lexer.hpp"
}
%code requires {
#include <qpg/ast.hpp>
#include <qpg/qpg.hpp>
void yyerror(AstWrapper &parsed_result, const char *s, ...);
}
%union {
int ival;
double fval;
char *sval;
bool bval;
OperationType optype;
DataType dtype;
Ast* nterm;
}
%destructor { if ($$) { delete $$; } } <nterm>
%destructor { if ($$) { free($$); } } <sval>
/* parameters */
%token <sval> NAME
%token <sval> STRING
%token <ival> INTNUM
%token <bval> BOOLEAN
%token <fval> FLOATNUM
/* reserved keywords */
%token SELECT UPDATE DELETE INSERT
%token CREATE DROP
%token TABLE
%token ';'
%token FROM
%token JOIN
%token WHERE
%token AS
%token SET
%token INTO
%token VALUES
%token CROSS_JOIN
%token <dtype> DTYPE;
%token ','
%token '.'
%token '('
%token ')'
%token '*'
/* operators with precedence */
%left <optype> COMPARE /* = != > < <= >= and or not */
%nterm <nterm> value value_list column column_list column_list_h table_source table_ref join_table table_subquery statement assign_column_list create_definition create_loc_list
%nterm <nterm> stmt stmt_list select_stmt update_stmt delete_stmt insert_stmt drop_stmt create_stmt stmt_list_h
%nterm <sval> table_name column_name opt_as_alias as_alias
%start stmt_list
%%
stmt_list:
stmt_list_h YYEOF {
auto lst = (AstList<Ast>*)$1;
parsed_result.list = lst;
$$ = nullptr;
}
stmt_list_h:
stmt ';' { $$ = new AstList<Ast>($1, AstType::QUERY_LIST); }
| stmt_list_h stmt ';' {
auto lst = (AstList<Ast>*) $1;
$$ = new AstList<Ast>(lst, $2);
delete $1;
}
;
stmt:
select_stmt { $$ = $1; }
| update_stmt { $$ = $1; }
| delete_stmt { $$ = $1; }
| insert_stmt { $$ = $1; }
| drop_stmt { $$ = $1; }
| create_stmt { $$ = $1; }
/* SELECT */
select_stmt:
SELECT column_list FROM table_ref WHERE statement {
$$ = new AstSelect((AstColumnList*)$2, $4, (AstStatement*)$6);
}
| SELECT column_list FROM table_ref {$$ = new AstSelect((AstColumnList*)$2, $4, nullptr); }
;
table_ref:
table_source { $$ = $1; }
| join_table { $$ = $1; }
;
table_source:
table_name opt_as_alias { $$ = new AstTable(std::string($1), $2); free($1); free($2); }
| table_subquery as_alias { $$ = $1; ((AstSubquery*)$1)->setAlias($2); free($2); }
;
table_subquery:
'(' select_stmt ')' { $$ = new AstSubquery((AstSelect*)$2); }
;
// left ast
join_table:
table_ref CROSS_JOIN table_source{ $$ = new AstJoin($1, JoinType::CROSS_JOIN, $3); }
;
opt_as_alias:
as_alias { $$ = $1; }
| /* nil */ { $$ = nullptr; }
;
as_alias:
AS table_name { $$ = $2; }
;
/* UPDATE */
update_stmt:
UPDATE table_name SET assign_column_list WHERE statement {
$$ = new AstUpdate($2, (AstList<AstColumnValue>*)$4, (AstStatement*)$6);
free($2);
}
| UPDATE table_name SET assign_column_list {
$$ = new AstUpdate($2, (AstList<AstColumnValue>*)$4, nullptr);
free($2);
}
;
/* DELETE */
delete_stmt:
DELETE FROM table_name {
$$ = new AstDelete($3, nullptr);
free($3);
}
| DELETE FROM table_name WHERE statement {
$$ = new AstDelete($3, (AstStatement*)$5);
free($3);
}
;
/* INSERT */
insert_stmt:
INSERT INTO table_name '(' column_list ')' VALUES '(' value_list ')' {
$$ = new AstInsert($3, (AstColumnList*)$5, (AstList<AstValue>*)$9);
free($3);
}
| INSERT INTO table_name VALUES '(' value_list ')' {
$$ = new AstInsert($3, new AstColumnList(), (AstList<AstValue>*)$6);
free($3);
}
;
/* DROP */
drop_stmt:
DROP TABLE table_name { $$ = new AstDrop($3); free($3); }
;
/* CREATE */
create_stmt:
CREATE TABLE table_name '(' create_loc_list ')' {
$$ = new AstCreate($3, (AstList<AstColumnType>*)$5);
free($3);
}
;
create_loc_list:
create_definition {
$$ = new AstList<AstColumnType>((AstColumnType*)$1, AstType::COLUMN_TYPE_LIST);
}
| create_loc_list ',' create_definition {
auto collist = (AstList<AstColumnType> *)$1;
$$ = new AstList<AstColumnType>(collist, (AstColumnType*)$3);
delete $1;
}
;
create_definition:
column_name DTYPE { $$ = new AstColumnType(new AstColumn($1), $2); free($1); }
;
assign_column_list:
column_name COMPARE value
{ if ($2 != OperationType::EQ) {
yyerror(parsed_result, "bad update assignment to '%s', $1"); YYERROR;
}
auto colval = new AstColumnValue($1, (AstValue*)$3);
$$ = new AstList<AstColumnValue>(colval, AstType::COLUMN_VALUE_LIST);
free($1);
}
| assign_column_list ',' column_name COMPARE value
{ if ($4 != OperationType::EQ) {
yyerror(parsed_result, "bad update assignment to '%s', $1"); YYERROR;
}
auto colval = new AstColumnValue($3, (AstValue*)$5);
auto collist = (AstList<AstColumnValue>*)$1;
$$ = new AstList<AstColumnValue>(collist, colval);
delete $1;
}
;
column_list:
'*' { $$ = new AstColumnList(); }
| column_list_h { $$ = $1; }
;
column_list_h:
column { $$ = new AstColumnList((AstColumn*)$1); }
| column_list_h ',' column {
$$ = new AstColumnList((AstColumnList*)$1, (AstColumn*)$3);
delete $1;
}
;
column:
table_name '.' column_name { $$ = new AstColumn($1, $3); free($1); free($3); }
| column_name { $$ = new AstColumn($1); free($1); }
;
column_name:
NAME { $$ = $1; }
;
table_name:
NAME { $$ = $1; }
;
statement:
value { $$ = new AstStatementConst((AstValue*)$1); }
| column { $$ = new AstStatementColumn((AstColumn*)$1); }
| '(' statement ')' { $$ = $2; }
| statement COMPARE statement {
$$ = new AstStatementBinary((AstStatement*)$1, (AstStatement*)$3, $2);
}
| COMPARE statement {
$$ = new AstStatementUnary((AstStatement*)$2, $1);
}
;
value_list:
value { $$ = new AstList<AstValue>((AstValue*)$1, AstType::VARIABLE_LIST); }
| value_list ',' value
{ $$ = new AstList<AstValue>((AstList<AstValue>*)$1, (AstValue*)$3); delete $1; }
;
value:
INTNUM { $$ = new AstValue((int32_t)$1, DataType::INT32); }
| BOOLEAN { $$ = new AstValue((bool)$1, DataType::BOOL); }
| FLOATNUM { $$ = new AstValue((double)$1, DataType::DOUBLE); }
| STRING { $$ = new AstValue(std::string($1), DataType::STR); free($1); }
;
%%
void yyerror(AstWrapper &parsed_result, const char *s, ...){
extern int yylineno;
char buffer[100];
int cx = 0;
cx = snprintf(buffer + cx, 100 - cx, "%d: error: ", yylineno);
va_list lst;
va_start(lst, s);
cx += vsnprintf(buffer + cx, 100 - cx, s, lst);
va_end(lst);
snprintf(buffer + cx, 100 - cx, "\n");
parsed_result.err_msg = std::string(buffer, cx);
}