-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathparser.y
More file actions
289 lines (255 loc) · 6.79 KB
/
parser.y
File metadata and controls
289 lines (255 loc) · 6.79 KB
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
287
288
289
%{
#include <stdio.h>
#include <stdlib.h>
#include "ast.h"
#include "errmsg.h"
#include "symbol.h"
#include "utils.h"
int yylex(void);
void yyerror(char *msg);
%}
%union {
int pos;
int num;
string_t str;
list_t list;
symbol_t sym;
ast_decl_t decl;
ast_expr_t expr;
ast_type_t type;
ast_var_t var;
ast_func_t func;
}
%{
static void print_token_value(FILE *fp, int type, YYSTYPE value);
#define YYPRINT(fp, type, value) print_token_value(fp, type, value)
#define LIST_ACTION(target, prev, elem) \
do \
{ \
list_t p, e = list((elem), NULL); \
(target) = p = (prev); \
if (p) \
{ \
while (p->next) \
p = p->next; \
p->next = e; \
} \
else \
(target) = e; \
} \
while (false)
#define LVALUE_ACTION(target, prev, elem) \
do \
{ \
ast_var_t p, var = (elem); \
(target) = p = (prev); \
if (p) \
{ \
while (p->u.field.var) \
p = p->u.field.var; \
p->u.field.var = var; \
} \
else \
(target) = var; \
} \
while (false)
static ast_expr_t _program;
%}
%debug
%token <str> TK_ID TK_STRING
%token <num> TK_INT
%token <pos>
TK_COMMA TK_COLON TK_LPARAN TK_RPARAN TK_LBRACK TK_RBRACK
TK_LBRACE TK_RBRACE TK_DOT
TK_ARRAY TK_IF TK_THEN TK_ELSE TK_WHILE TK_FOR TK_TO TK_LET TK_IN
TK_END TK_OF TK_BREAK TK_NIL
TK_FUNCTION TK_VAR TK_TYPE
%left <pos> TK_SEMICOLON
%nonassoc <pos> TK_DO
%nonassoc <pos> TK_ASSIGN
%left <pos> TK_OR
%left <pos> TK_AND
%nonassoc <pos> TK_EQ TK_NEQ TK_LT TK_LE TK_GT TK_GE
%left <pos> TK_PLUS TK_MINUS
%left <pos> TK_TIMES TK_DIVIDE
%left <pos> TK_UMINUS
%type <decl> decl var_decl
%type <expr> program expr
%type <type> type
%type <var> lvalue lvalue_
%type <list> expr_seq arg_seq efield_seq decls funcs_decl types_decl fields
%type <list> field_seq
%type <func> func_decl
%type <sym> id
%start program
%%
program:
expr
{ _program = $1; }
expr:
lvalue
{ $$ = ast_var_expr($1->pos, $1); }
| TK_NIL
{ $$ = ast_nil_expr($1); }
| expr expr_seq
{ $$ = ast_seq_expr($1->pos, list($1, $2)); }
| TK_LPARAN TK_RPARAN
{ $$ = ast_seq_expr($1, NULL); }
| TK_LPARAN expr TK_RPARAN
{ $$ = $2; }
| TK_INT
{ $$ = ast_num_expr(em_tok_pos, $1); }
| TK_STRING
{ $$ = ast_string_expr(em_tok_pos, $1); }
| TK_MINUS expr %prec TK_UMINUS
{ $$ = ast_op_expr($1, ast_num_expr($1, 0), AST_MINUS, $2); }
| id TK_LPARAN TK_RPARAN
{ $$ = ast_call_expr($2, $1, NULL); }
| id TK_LPARAN expr arg_seq TK_RPARAN
{ $$ = ast_call_expr($2, $1, list($3, $4)); }
| expr TK_PLUS expr
{ $$ = ast_op_expr($2, $1, AST_PLUS, $3); }
| expr TK_MINUS expr
{ $$ = ast_op_expr($2, $1, AST_MINUS, $3); }
| expr TK_TIMES expr
{ $$ = ast_op_expr($2, $1, AST_TIMES, $3); }
| expr TK_DIVIDE expr
{ $$ = ast_op_expr($2, $1, AST_DIVIDE, $3); }
| expr TK_EQ expr
{ $$ = ast_op_expr($2, $1, AST_EQ, $3); }
| expr TK_NEQ expr
{ $$ = ast_op_expr($2, $1, AST_NEQ, $3); }
| expr TK_LT expr
{ $$ = ast_op_expr($2, $1, AST_LT, $3); }
| expr TK_LE expr
{ $$ = ast_op_expr($2, $1, AST_LE, $3); }
| expr TK_GT expr
{ $$ = ast_op_expr($2, $1, AST_GT, $3); }
| expr TK_GE expr
{ $$ = ast_op_expr($2, $1, AST_GE, $3); }
| expr TK_AND expr
{ $$ = ast_if_expr($2, $1, $3, ast_num_expr($2, 0)); }
| expr TK_OR expr
{ $$ = ast_if_expr($2, $1, ast_num_expr($2, 1), $3); }
| id TK_LBRACE TK_RBRACE
{ $$ = ast_record_expr($2, $1, NULL); }
| id TK_LBRACE id TK_EQ expr efield_seq TK_RBRACE
{ $$ = ast_record_expr($2, $1, list(ast_efield($4, $3, $5), $6)); }
| id TK_LBRACK expr TK_RBRACK TK_OF expr
{ $$ = ast_array_expr($2, $1, $3, $6); }
| lvalue TK_ASSIGN expr
{ $$ = ast_assign_expr($2, $1, $3); }
| TK_IF expr TK_THEN expr
{ $$ = ast_if_expr($1, $2, $4, NULL); }
| TK_IF expr TK_THEN expr TK_ELSE expr
{ $$ = ast_if_expr($1, $2, $4, $6); }
| TK_WHILE expr TK_DO expr
{ $$ = ast_while_expr($1, $2, $4); }
| TK_FOR id TK_ASSIGN expr TK_TO expr TK_DO expr
{ $$ = ast_for_expr($1, $2, $4, $6, $8); }
| TK_BREAK
{ $$ = ast_break_expr($1); }
| TK_LET decls TK_IN expr TK_END
{ $$ = ast_let_expr($1, $2, $4); }
decls:
/* empty */
{ $$ = NULL; }
| decls decl
{ LIST_ACTION($$, $1, $2); }
decl:
types_decl
{ $$ = ast_types_decl(((ast_type_t) $1->data)->pos, $1); }
| var_decl
| funcs_decl
{ $$ = ast_funcs_decl(((ast_func_t) $1->data)->pos, $1); }
types_decl:
TK_TYPE id TK_EQ type
{ $$ = list(ast_nametype($2, $4), NULL); }
| types_decl TK_TYPE id TK_EQ type
{ LIST_ACTION($$, $1, ast_nametype($3, $5)); }
type:
id
{ $$ = ast_name_type(em_tok_pos, $1); }
| TK_LBRACE fields TK_RBRACE
{ $$ = ast_record_type($1, $2); }
| TK_ARRAY TK_OF id
{ $$ = ast_array_type($1, $3); }
fields:
/* empty */
{ $$ = NULL; }
| id TK_COLON id field_seq
{ $$ = list(ast_field($1, $3), $4); }
var_decl:
TK_VAR id TK_ASSIGN expr
{ $$ = ast_var_decl($1, $2, NULL, $4); }
| TK_VAR id TK_COLON id TK_ASSIGN expr
{ $$ = ast_var_decl($1, $2, $4, $6); }
funcs_decl:
func_decl
{ $$ = list($1, NULL); }
| funcs_decl func_decl
{ LIST_ACTION($$, $1, $2); }
func_decl:
TK_FUNCTION id TK_LPARAN fields TK_RPARAN TK_EQ expr
{ $$ = ast_func($1, $2, $4, NULL, $7); }
| TK_FUNCTION id TK_LPARAN fields TK_RPARAN TK_COLON id TK_EQ expr
{ $$ = ast_func($1, $2, $4, $7, $9); }
expr_seq:
TK_SEMICOLON expr
{ $$ = list($2, NULL); }
| expr_seq TK_SEMICOLON expr
{ LIST_ACTION($$, $1, $3); }
arg_seq:
/* empty */
{ $$ = NULL; }
| arg_seq TK_COMMA expr
{ LIST_ACTION($$, $1, $3); }
efield_seq:
/* empty */
{ $$ = NULL; }
| efield_seq TK_COMMA id TK_EQ expr
{ LIST_ACTION($$, $1, ast_efield($4, $3, $5)); }
field_seq:
/* empty */
{ $$ = NULL; }
| field_seq TK_COMMA id TK_COLON id
{ LIST_ACTION($$, $1, ast_field($3, $5)); }
lvalue:
id lvalue_
{ LVALUE_ACTION($$, $2, ast_simple_var(em_tok_pos, $1)); }
lvalue_:
/* empty */
{ $$ = NULL; }
| TK_DOT id lvalue_
{ LVALUE_ACTION($$, $3, ast_field_var($1, NULL, $2)); }
| TK_LBRACK expr TK_RBRACK lvalue_
{ LVALUE_ACTION($$, $4, ast_sub_var($1, NULL, $2)); }
id:
TK_ID
{ $$ = symbol($1); }
%%
void yyerror(char *msg)
{
em_error(em_tok_pos, "%s", msg);
}
static void print_token_value(FILE *fp, int type, YYSTYPE value)
{
switch (type)
{
case TK_ID:
case TK_STRING:
fprintf(fp, "%s", value.str);
break;
case TK_INT:
fprintf(fp, "%d", value.num);
break;
}
}
ast_expr_t parse(string_t filename)
{
em_reset(filename);
if (yyparse() == 0)
return _program;
else
return NULL;
}