Mercurial > hg > index.cgi
annotate lwcc/cc-parse.c @ 502:14a40f8bb4eb
Add various operators to lwcc
Add various binary and ternary operators to lwcc, but only those which can
work with constant operands. Seems like variables are probably required
next.
author | William Astle <lost@l-w.ca> |
---|---|
date | Wed, 25 Sep 2019 20:23:49 -0600 |
parents | f3e9732973f1 |
children | 7e8298f7bc0a |
rev | line source |
---|---|
498 | 1 /* |
2 lwcc/cc-parse.c | |
3 | |
4 Copyright © 2019 William Astle | |
5 | |
6 This file is part of LWTOOLS. | |
7 | |
8 LWTOOLS is free software: you can redistribute it and/or modify it under the | |
9 terms of the GNU General Public License as published by the Free Software | |
10 Foundation, either version 3 of the License, or (at your option) any later | |
11 version. | |
12 | |
13 This program is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 more details. | |
17 | |
18 You should have received a copy of the GNU General Public License along with | |
19 this program. If not, see <http://www.gnu.org/licenses/>. | |
20 */ | |
21 | |
22 #include <string.h> | |
23 | |
24 #include <lw_alloc.h> | |
25 #include <lw_string.h> | |
26 | |
27 #include "cpp.h" | |
28 #include "tree.h" | |
29 | |
30 #define TOK_KW_IF -1 | |
31 #define TOK_KW_ELSE -2 | |
32 #define TOK_KW_WHILE -3 | |
33 #define TOK_KW_DO -4 | |
34 #define TOK_KW_FOR -5 | |
35 #define TOK_KW_VOID -6 | |
36 #define TOK_KW_INT -7 | |
37 #define TOK_KW_CHAR -8 | |
38 #define TOK_KW_SHORT -9 | |
39 #define TOK_KW_LONG -10 | |
40 #define TOK_KW_UNSIGNED -11 | |
41 #define TOK_KW_SIGNED -12 | |
42 #define TOK_KW_FLOAT -13 | |
43 #define TOK_KW_DOUBLE -14 | |
44 #define TOK_KW_STRUCT -15 | |
45 #define TOK_KW_UNION -16 | |
46 #define TOK_KW_TYPEDEF -17 | |
47 #define TOK_KW_STATIC -18 | |
48 #define TOK_KW_SWITCH -19 | |
49 #define TOK_KW_CASE -20 | |
50 #define TOK_KW_DEFAULT -21 | |
51 #define TOK_KW_BREAK -22 | |
52 #define TOK_KW_CONTINUE -23 | |
53 #define TOK_KW_CONST -24 | |
54 #define TOK_KW_AUTO -25 | |
55 #define TOK_KW_ENUM -26 | |
56 #define TOK_KW_REGISTER -27 | |
57 #define TOK_KW_SIZEOF -28 | |
58 #define TOK_KW_VOLATILE -29 | |
59 #define TOK_KW_RETURN -30 | |
60 #define TOK_KW_EXTERN -31 | |
61 #define TOK_KW_GOTO -32 | |
62 #define TOK_TYPENAME -100 | |
63 #define TOK_CONST_INT -150 | |
64 | |
65 static struct { int tok; char *word; } keyword_list[] = { | |
66 { TOK_KW_IF, "if" }, | |
67 { TOK_KW_ELSE, "else" }, | |
68 { TOK_KW_WHILE, "while" }, | |
69 { TOK_KW_DO, "do" }, | |
70 { TOK_KW_FOR, "for" }, | |
71 { TOK_KW_VOID, "void" }, | |
72 { TOK_KW_INT, "int" }, | |
73 { TOK_KW_CHAR, "char" }, | |
74 { TOK_KW_SHORT, "short" }, | |
75 { TOK_KW_LONG, "long" }, | |
76 { TOK_KW_UNSIGNED, "unsigned" }, | |
77 { TOK_KW_SIGNED, "signed" }, | |
78 { TOK_KW_FLOAT, "float" }, | |
79 { TOK_KW_DOUBLE, "double" }, | |
80 { TOK_KW_STRUCT, "struct" }, | |
81 { TOK_KW_UNION, "union" }, | |
82 { TOK_KW_TYPEDEF, "typedef" }, | |
83 { TOK_KW_STATIC, "static" }, | |
84 { TOK_KW_SWITCH, "switch" }, | |
85 { TOK_KW_CASE, "case" }, | |
86 { TOK_KW_DEFAULT, "default" }, | |
87 { TOK_KW_BREAK, "break" }, | |
88 { TOK_KW_CONTINUE, "continue" }, | |
89 { TOK_KW_CONST, "const" }, | |
90 { TOK_KW_AUTO, "auto" }, | |
91 { TOK_KW_ENUM, "enum" }, | |
92 { TOK_KW_REGISTER, "register" }, | |
93 { TOK_KW_SIZEOF, "sizeof" }, | |
94 { TOK_KW_VOLATILE, "volatile" }, | |
95 { TOK_KW_RETURN, "return" }, | |
96 { TOK_KW_EXTERN, "extern" }, | |
97 { TOK_KW_GOTO, "goto" }, | |
98 { TOK_NONE, "" } | |
99 }; | |
100 | |
101 | |
102 struct parser_state | |
103 { | |
104 struct preproc_info *pp; // preprocessor data | |
105 struct token *curtok; // the current token | |
106 }; | |
107 | |
108 | |
109 struct token *parse_next(struct parser_state *ps) | |
110 { | |
111 struct token *tok; | |
112 int i; | |
113 | |
114 for (;;) | |
115 { | |
116 tok = preproc_next(ps -> pp); | |
117 if (tok -> ttype == TOK_WSPACE) | |
118 continue; | |
119 if (tok -> ttype == TOK_EOL) | |
120 continue; | |
121 if (tok -> ttype == TOK_CHAR) | |
122 { | |
123 // random character | |
124 fprintf(stderr, "Random character %02x\n", tok -> strval[0]); | |
125 if (tok -> strval[0] < 32 || tok -> strval[0] > 126) | |
126 continue; | |
127 } | |
128 break; | |
129 } | |
130 if (tok -> ttype == TOK_IDENT) | |
131 { | |
132 // convert identifier tokens to their respective meanings | |
133 for (i = 0; keyword_list[i].tok != TOK_NONE; i++) | |
134 { | |
135 if (strcmp(keyword_list[i].word, tok -> strval) == 0) | |
136 { | |
137 tok -> ttype = keyword_list[i].tok; | |
138 goto out; | |
139 } | |
140 } | |
141 // check for registered types here | |
142 } | |
143 else if (tok -> ttype == TOK_NUMBER) | |
144 { | |
145 // look for anything that isn't 0-9 | |
146 for (i = 0; tok -> strval[i]; i++) | |
147 { | |
148 if (tok -> strval[i] < '0' || tok -> strval[i] > '9') | |
149 break; | |
150 } | |
151 if (tok -> strval[i] == 0) | |
152 tok -> ttype = TOK_CONST_INT; | |
153 } | |
154 out: | |
155 fprintf(stderr, "Lexed: "); | |
156 token_print(tok, stderr); | |
157 fprintf(stderr, " (%d)\n", tok -> ttype); | |
158 if (ps -> curtok) | |
159 token_free(ps -> curtok); | |
160 ps -> curtok = tok; | |
161 return tok; | |
162 } | |
163 | |
164 void parse_generr(struct parser_state *ps, char *tag) | |
165 { | |
166 fprintf(stderr, "(%s) Unexpected token (%d): ", tag, ps -> curtok -> ttype); | |
167 token_print(ps -> curtok, stderr); | |
168 fprintf(stderr, "\n"); | |
169 | |
170 } | |
171 | |
502 | 172 node_t *parse_expr_real(struct parser_state *ps, int prec); |
173 | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
174 node_t *parse_term_real(struct parser_state *ps) |
498 | 175 { |
176 node_t *rv; | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
177 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
178 switch (ps -> curtok -> ttype) |
498 | 179 { |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
180 case TOK_CONST_INT: |
498 | 181 rv = node_create(NODE_CONST_INT, ps -> curtok -> strval); |
182 parse_next(ps); | |
183 return rv; | |
184 } | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
185 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
186 parse_generr(ps, "term"); |
498 | 187 return NULL; |
188 } | |
189 | |
502 | 190 node_t *parse_expr_fncall(struct parser_state *ps, node_t *term1) |
191 { | |
192 if (ps -> curtok -> ttype != TOK_CPAREN) | |
193 { | |
194 node_destroy(term1); | |
195 parse_generr(ps, "missing )"); | |
196 return NULL; | |
197 } | |
198 parse_next(ps); | |
199 return node_create(NODE_OPER_FNCALL, term1, NULL); | |
200 } | |
201 | |
202 node_t *parse_expr_postinc(struct parser_state *ps, node_t *term1) | |
203 { | |
204 return node_create(NODE_OPER_POSTINC, term1); | |
205 } | |
206 | |
207 node_t *parse_expr_postdec(struct parser_state *ps, node_t *term1) | |
208 { | |
209 return node_create(NODE_OPER_POSTDEC, term1); | |
210 } | |
211 | |
212 node_t *parse_expr_subscript(struct parser_state *ps, node_t *term1) | |
213 { | |
214 node_t *term2; | |
215 term2 = parse_expr_real(ps, 0); | |
216 if (!term2) | |
217 { | |
218 node_destroy(term1); | |
219 return NULL; | |
220 } | |
221 if (ps -> curtok -> ttype != TOK_CSQUARE) | |
222 { | |
223 node_destroy(term2); | |
224 node_destroy(term1); | |
225 parse_generr(ps, "missing ]"); | |
226 return NULL; | |
227 } | |
228 parse_next(ps); | |
229 return node_create(NODE_OPER_SUBSCRIPT, term1, term2); | |
230 } | |
231 | |
232 node_t *parse_expr_cond(struct parser_state *ps, node_t *term1) | |
233 { | |
234 node_t *term2, *term3; | |
235 // conditional operator | |
236 // NOTE: the middle operand is evaluated as though it is its own | |
237 // independent expression because the : must appear. The third | |
238 // operand is evaluated at the ternary operator precedence so that | |
239 // subsequent operand binding behaves correctly (if surprisingly). This | |
240 // would be less confusing if the ternary operator was fully bracketed | |
241 // (that is, had a terminator) | |
242 term2 = parse_expr_real(ps, 0); | |
243 if (!term2) | |
244 { | |
245 node_destroy(term1); | |
246 return NULL; | |
247 } | |
248 if (ps -> curtok -> ttype == TOK_COLON) | |
249 { | |
250 parse_next(ps); | |
251 term3 = parse_expr_real(ps, 25); | |
252 if (!term3) | |
253 { | |
254 node_destroy(term1); | |
255 node_destroy(term2); | |
256 return NULL; | |
257 } | |
258 return node_create(NODE_OPER_COND, term1, term2, term3); | |
259 } | |
260 else | |
261 { | |
262 node_destroy(term1); | |
263 node_destroy(term2); | |
264 parse_generr(ps, "missing :"); | |
265 return NULL; | |
266 } | |
267 } | |
268 | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
269 node_t *parse_expr_real(struct parser_state *ps, int prec) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
270 { |
502 | 271 static struct { int tok; int nodetype; int prec; int ra; node_t *(*spec)(struct parser_state *, node_t *); } operlist[] = { |
272 // { TOK_OPAREN, NODE_OPER_FNCALL, 200, 0, parse_expr_fncall }, | |
273 // { TOK_OSQUARE, NODE_OPER_SUBSCRIPT, 200, 0, parse_expr_subscript }, | |
274 // { TOK_ARROW, NODE_OPER_PTRMEM, 200, 0 }, | |
275 // { TOK_DOT, NODE_OPER_OBJMEM, 200, 0 }, | |
276 // { TOK_DBLADD, NODE_OPER_POSTINC, 200, 0, parse_expr_postinc }, | |
277 // { TOK_DBLSUB, NODE_OPER_POSTDEC, 200, 0, parse_expr_postdec }, | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
278 { TOK_STAR, NODE_OPER_TIMES, 150 }, |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
279 { TOK_DIV, NODE_OPER_DIVIDE, 150 }, |
502 | 280 { TOK_MOD, NODE_OPER_MOD, 150 }, |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
281 { TOK_ADD, NODE_OPER_PLUS, 100 }, |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
282 { TOK_SUB, NODE_OPER_MINUS, 100 }, |
502 | 283 { TOK_LSH, NODE_OPER_LSH, 90 }, |
284 { TOK_RSH, NODE_OPER_RSH, 90 }, | |
285 { TOK_LT, NODE_OPER_LT, 80 }, | |
286 { TOK_LE, NODE_OPER_LE, 80 }, | |
287 { TOK_GT, NODE_OPER_GT, 80 }, | |
288 { TOK_GE, NODE_OPER_GE, 80 }, | |
289 { TOK_EQ, NODE_OPER_EQ, 70 }, | |
290 { TOK_NE, NODE_OPER_NE, 70 }, | |
291 { TOK_BWAND, NODE_OPER_BWAND, 60}, | |
292 { TOK_XOR, NODE_OPER_BWXOR, 55 }, | |
293 { TOK_BWOR, NODE_OPER_BWOR, 50 }, | |
294 { TOK_BAND, NODE_OPER_BAND, 40 }, | |
295 { TOK_BOR, NODE_OPER_BOR, 35 }, | |
296 { TOK_QMARK, NODE_OPER_COND, 25, 1, parse_expr_cond }, | |
297 // { TOK_ASS, NODE_OPER_ASS, 20, 1 }, | |
298 // { TOK_ADDASS, NODE_OPER_ADDASS, 20, 1 }, | |
299 // { TOK_SUBASS, NODE_OPER_SUBASS, 20, 1 }, | |
300 // { TOK_MULASS, NODE_OPER_MULASS, 20, 1 }, | |
301 // { TOK_DIVASS, NODE_OPER_DIVASS, 20, 1 }, | |
302 // { TOK_MODASS, NODE_OPER_MODASS, 20, 1 }, | |
303 // { TOK_LSHASS, NODE_OPER_LSHASS, 20, 1 }, | |
304 // { TOK_RSHASS, NODE_OPER_RSHASS, 20, 1 }, | |
305 // { TOK_BWANDASS, NODE_OPER_BWANDASS, 20, 1}, | |
306 // { TOK_BWORASS, NODE_OPER_BWORASS, 20, 1 }, | |
307 // { TOK_XORASS, NODE_OPER_BWXORASS, 20, 1 }, | |
308 { TOK_COMMA, NODE_OPER_COMMA, 1 }, | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
309 { 0, 0, 0 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
310 }; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
311 node_t *term1, *term2; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
312 int i; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
313 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
314 term1 = parse_term_real(ps); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
315 if (!term1) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
316 return NULL; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
317 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
318 nextoper: |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
319 for (i = 0; operlist[i].tok; i++) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
320 if (operlist[i].tok == ps -> curtok -> ttype) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
321 break; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
322 fprintf(stderr, "Matched operator: %d, %d\n", operlist[i].tok, operlist[i].prec); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
323 // if we hit the end of the expression, return |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
324 if (operlist[i].tok == 0) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
325 return term1; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
326 |
502 | 327 // is previous operation higher precedence? If so, just return the first term |
328 if (operlist[i].prec < prec) | |
329 return term1; | |
330 | |
331 // is this operator left associative and previous operation is same precedence? | |
332 // if so, just return the first term | |
333 if (operlist[i].ra == 0 && operlist[i].prec == prec) | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
334 return term1; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
335 |
502 | 336 // consume the operator |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
337 parse_next(ps); |
502 | 338 |
339 // special handling | |
340 if (operlist[i].spec) | |
341 { | |
342 term2 = (operlist[i].spec)(ps, term1); | |
343 if (!term2) | |
344 { | |
345 node_destroy(term1); | |
346 return NULL; | |
347 } | |
348 term1 = term2; | |
349 goto nextoper; | |
350 } | |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
351 term2 = parse_expr_real(ps, operlist[i].prec); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
352 if (!term2) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
353 { |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
354 parse_generr(ps, "expr"); |
502 | 355 node_destroy(term1); |
501
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
356 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
357 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
358 term1 = node_create(operlist[i].nodetype, term1, term2); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
359 term2 = NULL; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
360 goto nextoper; |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
361 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
362 |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
363 node_t *parse_expr(struct parser_state *ps) |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
364 { |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
365 return parse_expr_real(ps, 0); |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
366 } |
f3e9732973f1
Add basic integer operations to lwcc
William Astle <lost@l-w.ca>
parents:
498
diff
changeset
|
367 |
498 | 368 node_t *parse_statement(struct parser_state *ps) |
369 { | |
370 node_t *rv; | |
371 node_t *n; | |
372 | |
373 switch (ps -> curtok -> ttype) | |
374 { | |
375 case TOK_KW_RETURN: | |
376 parse_next(ps); | |
377 n = parse_expr(ps); | |
378 if (!n) | |
379 { | |
380 parse_generr(ps, "statement"); | |
381 return NULL; | |
382 } | |
383 rv = node_create(NODE_STMT_RETURN); | |
384 node_addchild(rv, n); | |
385 break; | |
386 | |
387 default: | |
388 return NULL; | |
389 } | |
390 | |
391 if (ps -> curtok -> ttype != TOK_EOS) | |
392 parse_generr(ps, "statement"); | |
393 else | |
394 parse_next(ps); | |
395 return rv; | |
396 } | |
397 | |
398 node_t *parse_globaldecl(struct parser_state *ps) | |
399 { | |
400 node_t *rv = NULL; | |
401 node_t *stmt; | |
402 char *fnname = NULL; | |
403 if (ps -> curtok -> ttype == TOK_KW_INT) | |
404 { | |
405 // variable name | |
406 parse_next(ps); | |
407 if (ps -> curtok -> ttype != TOK_IDENT) | |
408 goto error; | |
409 fnname = lw_strdup(ps -> curtok -> strval); | |
410 parse_next(ps); | |
411 if (ps -> curtok -> ttype != TOK_OPAREN) | |
412 goto error; | |
413 parse_next(ps); | |
414 if (ps -> curtok -> ttype != TOK_CPAREN) | |
415 goto error; | |
416 parse_next(ps); | |
417 if (ps -> curtok -> ttype != TOK_OBRACE) | |
418 goto error; | |
419 parse_next(ps); | |
420 stmt = parse_statement(ps); | |
421 if (!stmt) | |
422 goto error; | |
423 rv = node_create(NODE_FUNDEF, node_create(NODE_TYPE_INT), node_create(NODE_IDENT, fnname), node_create(NODE_FUNARGS), stmt); | |
424 if (ps -> curtok -> ttype != TOK_CBRACE) | |
425 goto error; | |
426 parse_next(ps); | |
427 lw_free(fnname); | |
428 return rv; | |
429 } | |
430 | |
431 | |
432 error: | |
433 if (fnname) | |
434 lw_free(fnname); | |
435 parse_generr(ps, "globaldecl"); | |
436 return rv; | |
437 } | |
438 | |
439 node_t *parse_program(struct preproc_info *pp) | |
440 { | |
441 node_t *rv; | |
442 node_t *node; | |
443 struct parser_state ps; | |
444 | |
445 ps.pp = pp; | |
446 ps.curtok = NULL; | |
447 | |
448 rv = node_create(NODE_PROGRAM); | |
449 | |
450 // prime the parser | |
451 parse_next(&ps); | |
452 while (ps.curtok -> ttype != TOK_EOF) | |
453 { | |
454 node = parse_globaldecl(&ps); | |
455 if (!node) | |
456 break; | |
457 node_addchild(rv, node); | |
458 } | |
459 | |
460 return rv; | |
461 } |