source: mainline/uspace/app/sbi/src/parse.c@ 0a72efc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0a72efc was 23de644, checked in by Jiri Svoboda <jiri@…>, 16 years ago

Update SBI to rev. 174.

  • Property mode set to 100644
File size: 24.0 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file Parser
30 *
31 * Consumes a sequence of lexical elements and produces a syntax tree (stree).
32 * Parsing primitives, module members, statements.
33 */
34
35#include <assert.h>
36#include <stdlib.h>
37#include "debug.h"
38#include "lex.h"
39#include "list.h"
40#include "mytypes.h"
41#include "p_expr.h"
42#include "p_type.h"
43#include "stree.h"
44#include "strtab.h"
45#include "symbol.h"
46
47#include "parse.h"
48
49/*
50 * Module members
51 */
52static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
53 stree_csi_t *outer_csi);
54static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi);
55
56static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi);
57static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi);
58static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi);
59
60static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse);
61
62static stree_proc_arg_t *parse_proc_arg(parse_t *parse);
63static stree_arg_attr_t *parse_arg_attr(parse_t *parse);
64
65/*
66 * Statements
67 */
68static stree_block_t *parse_block(parse_t *parse);
69
70static stree_vdecl_t *parse_vdecl(parse_t *parse);
71static stree_if_t *parse_if(parse_t *parse);
72static stree_while_t *parse_while(parse_t *parse);
73static stree_for_t *parse_for(parse_t *parse);
74static stree_raise_t *parse_raise(parse_t *parse);
75static stree_return_t *parse_return(parse_t *parse);
76static stree_wef_t *parse_wef(parse_t *parse);
77static stree_exps_t *parse_exps(parse_t *parse);
78
79static stree_except_t *parse_except(parse_t *parse);
80
81/** Initialize parser object.
82 *
83 * Set up parser @a parse to use lexer @a lex for input and to store
84 * output (i.e. new declarations) to program @a prog. @a prog is not
85 * necessarily empty, the declarations being parsed are simply added
86 * to it.
87 *
88 * @param parse Parser object.
89 * @param prog Destination program stree.
90 * @param lex Input lexer.
91 */
92void parse_init(parse_t *parse, stree_program_t *prog, struct lex *lex)
93{
94 parse->program = prog;
95 parse->cur_mod = parse->program->module;
96 parse->lex = lex;
97
98 parse->error = b_false;
99 parse->error_bailout = b_false;
100
101 lex_next(parse->lex);
102}
103
104/** Parse module.
105 *
106 * Parse a program module.
107 *
108 * The input is read using the lexer associated with @a parse. The resulting
109 * declarations are added to existing declarations in the program associated
110 * with @a parse.
111 *
112 * If any parse error occurs, parse->error will @c b_true when this function
113 * returns. parse->error_bailout will be @c b_true if the error has not
114 * been recovered yet. Similar holds for other parsing functions in this
115 * module.
116 *
117 * @param parse Parser object.
118 */
119void parse_module(parse_t *parse)
120{
121 stree_csi_t *csi;
122 stree_modm_t *modm;
123
124 while (lcur_lc(parse) != lc_eof && !parse_is_error(parse)) {
125 switch (lcur_lc(parse)) {
126 case lc_class:
127 case lc_struct:
128 case lc_interface:
129 csi = parse_csi(parse, lcur_lc(parse), NULL);
130 modm = stree_modm_new(mc_csi);
131 modm->u.csi = csi;
132
133 list_append(&parse->cur_mod->members, modm);
134 break;
135 default:
136 lunexpected_error(parse);
137 lex_next(parse->lex);
138 break;
139 }
140
141 }
142}
143
144/** Parse class, struct or interface declaration.
145 *
146 * @param parse Parser object.
147 * @param dclass What to parse: @c lc_class, @c lc_struct or @c lc_csi.
148 * @param outer_csi CSI containing this declaration or @c NULL if global.
149 * @return New syntax tree node.
150 */
151static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
152 stree_csi_t *outer_csi)
153{
154 stree_csi_t *csi;
155 csi_class_t cc;
156 stree_csimbr_t *csimbr;
157 stree_symbol_t *symbol;
158
159 switch (dclass) {
160 case lc_class: cc = csi_class; break;
161 case lc_struct: cc = csi_struct; break;
162 case lc_interface: cc = csi_interface; break;
163 default: assert(b_false);
164 }
165
166 lskip(parse);
167
168 csi = stree_csi_new(cc);
169 csi->name = parse_ident(parse);
170
171 symbol = stree_symbol_new(sc_csi);
172 symbol->u.csi = csi;
173 symbol->outer_csi = outer_csi;
174 csi->symbol = symbol;
175
176#ifdef DEBUG_PARSE_TRACE
177 printf("parse_csi: csi=%p, csi->name = %p (%s)\n", csi, csi->name,
178 strtab_get_str(csi->name->sid));
179#endif
180 if (lcur_lc(parse) == lc_colon) {
181 /* Inheritance list */
182 lskip(parse);
183 csi->base_csi_ref = parse_texpr(parse);
184 } else {
185 csi->base_csi_ref = NULL;
186 }
187
188 lmatch(parse, lc_is);
189 list_init(&csi->members);
190
191 /* Parse class, struct or interface members. */
192 while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
193 csimbr = parse_csimbr(parse, csi);
194 list_append(&csi->members, csimbr);
195 }
196
197 lmatch(parse, lc_end);
198
199 return csi;
200}
201
202/** Parse class, struct or interface member.
203 *
204 * @param parse Parser object.
205 * @param outer_csi CSI containing this declaration or @c NULL if global.
206 * @return New syntax tree node.
207 */
208static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi)
209{
210 stree_csimbr_t *csimbr;
211
212 stree_csi_t *csi;
213 stree_fun_t *fun;
214 stree_var_t *var;
215 stree_prop_t *prop;
216
217 switch (lcur_lc(parse)) {
218 case lc_class:
219 case lc_struct:
220 case lc_interface:
221 csi = parse_csi(parse, lcur_lc(parse), outer_csi);
222 csimbr = stree_csimbr_new(csimbr_csi);
223 csimbr->u.csi = csi;
224 break;
225 case lc_fun:
226 fun = parse_fun(parse, outer_csi);
227 csimbr = stree_csimbr_new(csimbr_fun);
228 csimbr->u.fun = fun;
229 break;
230 case lc_var:
231 var = parse_var(parse, outer_csi);
232 csimbr = stree_csimbr_new(csimbr_var);
233 csimbr->u.var = var;
234 break;
235 case lc_prop:
236 prop = parse_prop(parse, outer_csi);
237 csimbr = stree_csimbr_new(csimbr_prop);
238 csimbr->u.prop = prop;
239 break;
240 default:
241 lunexpected_error(parse);
242 lex_next(parse->lex);
243 }
244
245 return csimbr;
246}
247
248
249/** Parse member function.
250 *
251 * @param parse Parser object.
252 * @param outer_csi CSI containing this declaration or @c NULL if global.
253 * @return New syntax tree node.
254 */
255static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi)
256{
257 stree_fun_t *fun;
258 stree_proc_arg_t *arg;
259 stree_symbol_t *symbol;
260 stree_symbol_attr_t *attr;
261
262 fun = stree_fun_new();
263 symbol = stree_symbol_new(sc_fun);
264
265 symbol->u.fun = fun;
266 symbol->outer_csi = outer_csi;
267 fun->symbol = symbol;
268
269 lmatch(parse, lc_fun);
270 fun->name = parse_ident(parse);
271 lmatch(parse, lc_lparen);
272
273#ifdef DEBUG_PARSE_TRACE
274 printf("Parsing function '%s'.\n", strtab_get_str(fun->name->sid));
275#endif
276
277 list_init(&fun->args);
278
279 if (lcur_lc(parse) != lc_rparen) {
280
281 /* Parse formal parameters. */
282 while (!parse_is_error(parse)) {
283 arg = parse_proc_arg(parse);
284
285 if (stree_arg_has_attr(arg, aac_packed)) {
286 fun->varg = arg;
287 break;
288 } else {
289 list_append(&fun->args, arg);
290 }
291
292 if (lcur_lc(parse) == lc_rparen)
293 break;
294
295 lmatch(parse, lc_scolon);
296 }
297 }
298
299 lmatch(parse, lc_rparen);
300
301 if (lcur_lc(parse) == lc_colon) {
302 lskip(parse);
303 fun->rtype = parse_texpr(parse);
304 } else {
305 fun->rtype = NULL;
306 }
307
308 list_init(&symbol->attr);
309
310 /* Parse attributes. */
311 while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
312 lskip(parse);
313 attr = parse_symbol_attr(parse);
314 list_append(&symbol->attr, attr);
315 }
316
317 fun->proc = stree_proc_new();
318 fun->proc->outer_symbol = symbol;
319
320 if (lcur_lc(parse) == lc_scolon) {
321 lskip(parse);
322
323 /* This function has no body. */
324 if (!stree_symbol_has_attr(symbol, sac_builtin)) {
325 printf("Error: Function '");
326 symbol_print_fqn(symbol);
327 printf("' has no body.\n");
328 parse_note_error(parse);
329 }
330 fun->proc->body = NULL;
331 } else {
332 lmatch(parse, lc_is);
333 fun->proc->body = parse_block(parse);
334 lmatch(parse, lc_end);
335 }
336
337 return fun;
338}
339
340/** Parse member variable.
341 *
342 * @param parse Parser object.
343 * @param outer_csi CSI containing this declaration or @c NULL if global.
344 * @return New syntax tree node.
345 */
346static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi)
347{
348 stree_var_t *var;
349 stree_symbol_t *symbol;
350
351 var = stree_var_new();
352 symbol = stree_symbol_new(sc_var);
353 symbol->u.var = var;
354 symbol->outer_csi = outer_csi;
355 var->symbol = symbol;
356
357 lmatch(parse, lc_var);
358 var->name = parse_ident(parse);
359 lmatch(parse, lc_colon);
360 var->type = parse_texpr(parse);
361 lmatch(parse, lc_scolon);
362
363 return var;
364}
365
366/** Parse member property.
367 *
368 * @param parse Parser object.
369 * @param outer_csi CSI containing this declaration or @c NULL if global.
370 * @return New syntax tree node.
371 */
372static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi)
373{
374 stree_prop_t *prop;
375 stree_symbol_t *symbol;
376
377 stree_ident_t *ident;
378 stree_proc_arg_t *arg;
379
380 prop = stree_prop_new();
381 list_init(&prop->args);
382
383 symbol = stree_symbol_new(sc_prop);
384 symbol->u.prop = prop;
385 symbol->outer_csi = outer_csi;
386 prop->symbol = symbol;
387
388 lmatch(parse, lc_prop);
389
390 if (lcur_lc(parse) == lc_self) {
391 /* Indexed property set */
392
393 /* Use some name that is impossible as identifier. */
394 ident = stree_ident_new();
395 ident->sid = strtab_get_sid(INDEXER_IDENT);
396 prop->name = ident;
397
398 lskip(parse);
399 lmatch(parse, lc_lsbr);
400
401 /* Parse formal parameters. */
402 while (!parse_is_error(parse)) {
403 arg = parse_proc_arg(parse);
404 if (stree_arg_has_attr(arg, aac_packed)) {
405 prop->varg = arg;
406 break;
407 } else {
408 list_append(&prop->args, arg);
409 }
410
411 if (lcur_lc(parse) == lc_rsbr)
412 break;
413
414 lmatch(parse, lc_scolon);
415 }
416
417 lmatch(parse, lc_rsbr);
418 } else {
419 /* Named property */
420 prop->name = parse_ident(parse);
421 }
422
423 lmatch(parse, lc_colon);
424 prop->type = parse_texpr(parse);
425 lmatch(parse, lc_is);
426
427 while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
428 switch (lcur_lc(parse)) {
429 case lc_get:
430 lskip(parse);
431 lmatch(parse, lc_is);
432 if (prop->getter != NULL) {
433 printf("Error: Duplicate getter.\n");
434 (void) parse_block(parse); /* XXX Free */
435 lmatch(parse, lc_end);
436 parse_note_error(parse);
437 break;
438 }
439
440 /* Create setter procedure */
441 prop->getter = stree_proc_new();
442 prop->getter->body = parse_block(parse);
443 prop->getter->outer_symbol = symbol;
444
445 lmatch(parse, lc_end);
446 break;
447 case lc_set:
448 lskip(parse);
449 prop->setter_arg = stree_proc_arg_new();
450 prop->setter_arg->name = parse_ident(parse);
451 prop->setter_arg->type = prop->type;
452 lmatch(parse, lc_is);
453 if (prop->setter != NULL) {
454 printf("Error: Duplicate setter.\n");
455 (void) parse_block(parse); /* XXX Free */
456 lmatch(parse, lc_end);
457 parse_note_error(parse);
458 }
459
460 /* Create setter procedure */
461 prop->setter = stree_proc_new();
462 prop->setter->body = parse_block(parse);
463 prop->setter->outer_symbol = symbol;
464
465 lmatch(parse, lc_end);
466 break;
467 default:
468 lunexpected_error(parse);
469 }
470 }
471
472 lmatch(parse, lc_end);
473
474 return prop;
475}
476
477/** Parse symbol attribute.
478 *
479 * @param parse Parser object.
480 * @param outer_csi CSI containing this declaration or @c NULL if global.
481 * @return New syntax tree node.
482 */
483static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse)
484{
485 stree_symbol_attr_t *attr;
486
487 if (lcur_lc(parse) != lc_builtin) {
488 printf("Error: Unexpected attribute '");
489 lem_print(lcur(parse));
490 printf("'.\n");
491 parse_note_error(parse);
492 }
493
494 lskip(parse);
495
496 attr = stree_symbol_attr_new(sac_builtin);
497 return attr;
498}
499
500/** Parse formal function argument.
501 *
502 * @param parse Parser object.
503 * @return New syntax tree node.
504 */
505static stree_proc_arg_t *parse_proc_arg(parse_t *parse)
506{
507 stree_proc_arg_t *arg;
508 stree_arg_attr_t *attr;
509
510 arg = stree_proc_arg_new();
511 arg->name = parse_ident(parse);
512 lmatch(parse, lc_colon);
513 arg->type = parse_texpr(parse);
514
515 list_init(&arg->attr);
516
517 /* Parse attributes. */
518 while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
519 lskip(parse);
520 attr = parse_arg_attr(parse);
521 list_append(&arg->attr, attr);
522 }
523
524#ifdef DEBUG_PARSE_TRACE
525 printf("Parsed arg attr, type=%p.\n", arg->type);
526#endif
527 return arg;
528}
529
530/** Parse argument attribute.
531 *
532 * @param parse Parser object.
533 * @return New syntax tree node.
534 */
535static stree_arg_attr_t *parse_arg_attr(parse_t *parse)
536{
537 stree_arg_attr_t *attr;
538
539 if (lcur_lc(parse) != lc_packed) {
540 printf("Error: Unexpected attribute '");
541 lem_print(lcur(parse));
542 printf("'.\n");
543 parse_note_error(parse);
544 }
545
546 lskip(parse);
547
548 attr = stree_arg_attr_new(aac_packed);
549 return attr;
550}
551
552/** Parse statement block.
553 *
554 * @param parse Parser object.
555 * @return New syntax tree node.
556 */
557static stree_block_t *parse_block(parse_t *parse)
558{
559 stree_block_t *block;
560 stree_stat_t *stat;
561
562 block = stree_block_new();
563 list_init(&block->stats);
564
565 /* Avoid peeking if there is an error condition. */
566 if (parse_is_error(parse))
567 return block;
568
569 while (terminates_block(lcur_lc(parse)) != b_true &&
570 !parse_is_error(parse)) {
571
572 stat = parse_stat(parse);
573 list_append(&block->stats, stat);
574 }
575
576 return block;
577}
578
579/** Parse statement.
580 *
581 * @param parse Parser object.
582 * @return New syntax tree node.
583 */
584stree_stat_t *parse_stat(parse_t *parse)
585{
586 stree_stat_t *stat;
587
588 stree_vdecl_t *vdecl_s;
589 stree_if_t *if_s;
590 stree_while_t *while_s;
591 stree_for_t *for_s;
592 stree_raise_t *raise_s;
593 stree_return_t *return_s;
594 stree_wef_t *wef_s;
595 stree_exps_t *exp_s;
596
597#ifdef DEBUG_PARSE_TRACE
598 printf("Parse statement.\n");
599#endif
600 switch (lcur_lc(parse)) {
601 case lc_var:
602 vdecl_s = parse_vdecl(parse);
603 stat = stree_stat_new(st_vdecl);
604 stat->u.vdecl_s = vdecl_s;
605 break;
606 case lc_if:
607 if_s = parse_if(parse);
608 stat = stree_stat_new(st_if);
609 stat->u.if_s = if_s;
610 break;
611 case lc_while:
612 while_s = parse_while(parse);
613 stat = stree_stat_new(st_while);
614 stat->u.while_s = while_s;
615 break;
616 case lc_for:
617 for_s = parse_for(parse);
618 stat = stree_stat_new(st_for);
619 stat->u.for_s = for_s;
620 break;
621 case lc_raise:
622 raise_s = parse_raise(parse);
623 stat = stree_stat_new(st_raise);
624 stat->u.raise_s = raise_s;
625 break;
626 case lc_return:
627 return_s = parse_return(parse);
628 stat = stree_stat_new(st_return);
629 stat->u.return_s = return_s;
630 break;
631 case lc_do:
632 case lc_with:
633 wef_s = parse_wef(parse);
634 stat = stree_stat_new(st_wef);
635 stat->u.wef_s = wef_s;
636 break;
637 default:
638 exp_s = parse_exps(parse);
639 stat = stree_stat_new(st_exps);
640 stat->u.exp_s = exp_s;
641 break;
642 }
643
644#ifdef DEBUG_PARSE_TRACE
645 printf("Parsed statement %p\n", stat);
646#endif
647 return stat;
648}
649
650/** Parse variable declaration statement.
651 *
652 * @param parse Parser object.
653 * @return New syntax tree node.
654 */
655static stree_vdecl_t *parse_vdecl(parse_t *parse)
656{
657 stree_vdecl_t *vdecl;
658
659 vdecl = stree_vdecl_new();
660
661 lmatch(parse, lc_var);
662 vdecl->name = parse_ident(parse);
663 lmatch(parse, lc_colon);
664 vdecl->type = parse_texpr(parse);
665
666 if (lcur_lc(parse) == lc_assign) {
667 lskip(parse);
668 (void) parse_expr(parse);
669 }
670
671 lmatch(parse, lc_scolon);
672
673#ifdef DEBUG_PARSE_TRACE
674 printf("Parsed vdecl for '%s'\n", strtab_get_str(vdecl->name->sid));
675 printf("vdecl = %p, vdecl->name = %p, sid=%d\n",
676 vdecl, vdecl->name, vdecl->name->sid);
677#endif
678 return vdecl;
679}
680
681/** Parse @c if statement.
682 *
683 * @param parse Parser object.
684 * @return New syntax tree node.
685 */
686static stree_if_t *parse_if(parse_t *parse)
687{
688 stree_if_t *if_s;
689
690#ifdef DEBUG_PARSE_TRACE
691 printf("Parse 'if' statement.\n");
692#endif
693 if_s = stree_if_new();
694
695 lmatch(parse, lc_if);
696 if_s->cond = parse_expr(parse);
697 lmatch(parse, lc_then);
698 if_s->if_block = parse_block(parse);
699
700 if (lcur_lc(parse) == lc_else) {
701 lskip(parse);
702 if_s->else_block = parse_block(parse);
703 } else {
704 if_s->else_block = NULL;
705 }
706
707 lmatch(parse, lc_end);
708 return if_s;
709}
710
711/** Parse @c while statement.
712 *
713 * @param parse Parser object.
714 */
715static stree_while_t *parse_while(parse_t *parse)
716{
717 stree_while_t *while_s;
718
719#ifdef DEBUG_PARSE_TRACE
720 printf("Parse 'while' statement.\n");
721#endif
722 while_s = stree_while_new();
723
724 lmatch(parse, lc_while);
725 while_s->cond = parse_expr(parse);
726 lmatch(parse, lc_do);
727 while_s->body = parse_block(parse);
728 lmatch(parse, lc_end);
729
730 return while_s;
731}
732
733/** Parse @c for statement.
734 *
735 * @param parse Parser object.
736 * @return New syntax tree node.
737 */
738static stree_for_t *parse_for(parse_t *parse)
739{
740 stree_for_t *for_s;
741
742#ifdef DEBUG_PARSE_TRACE
743 printf("Parse 'for' statement.\n");
744#endif
745 for_s = stree_for_new();
746
747 lmatch(parse, lc_for);
748 lmatch(parse, lc_ident);
749 lmatch(parse, lc_colon);
750 (void) parse_texpr(parse);
751 lmatch(parse, lc_in);
752 (void) parse_expr(parse);
753 lmatch(parse, lc_do);
754 for_s->body = parse_block(parse);
755 lmatch(parse, lc_end);
756
757 return for_s;
758}
759
760/** Parse @c raise statement.
761 *
762 * @param parse Parser object.
763 */
764static stree_raise_t *parse_raise(parse_t *parse)
765{
766 stree_raise_t *raise_s;
767
768#ifdef DEBUG_PARSE_TRACE
769 printf("Parse 'raise' statement.\n");
770#endif
771 raise_s = stree_raise_new();
772 lmatch(parse, lc_raise);
773 raise_s->expr = parse_expr(parse);
774 lmatch(parse, lc_scolon);
775
776 return raise_s;
777}
778
779/** Parse @c return statement.
780 *
781 * @param parse Parser object.
782 * @return New syntax tree node.
783 */
784static stree_return_t *parse_return(parse_t *parse)
785{
786 stree_return_t *return_s;
787
788#ifdef DEBUG_PARSE_TRACE
789 printf("Parse 'return' statement.\n");
790#endif
791 return_s = stree_return_new();
792
793 lmatch(parse, lc_return);
794 return_s->expr = parse_expr(parse);
795 lmatch(parse, lc_scolon);
796
797 return return_s;
798}
799
800/* Parse @c with-except-finally statement.
801 *
802 * @param parse Parser object.
803 * @return New syntax tree node.
804 */
805static stree_wef_t *parse_wef(parse_t *parse)
806{
807 stree_wef_t *wef_s;
808 stree_except_t *except_c;
809
810#ifdef DEBUG_PARSE_TRACE
811 printf("Parse WEF statement.\n");
812#endif
813 wef_s = stree_wef_new();
814 list_init(&wef_s->except_clauses);
815
816 if (lcur_lc(parse) == lc_with) {
817 lmatch(parse, lc_with);
818 lmatch(parse, lc_ident);
819 lmatch(parse, lc_colon);
820 (void) parse_texpr(parse);
821 lmatch(parse, lc_assign);
822 (void) parse_expr(parse);
823 }
824
825 lmatch(parse, lc_do);
826 wef_s->with_block = parse_block(parse);
827
828 while (lcur_lc(parse) == lc_except && !parse_is_error(parse)) {
829 except_c = parse_except(parse);
830 list_append(&wef_s->except_clauses, except_c);
831 }
832
833 if (lcur_lc(parse) == lc_finally) {
834 lmatch(parse, lc_finally);
835 lmatch(parse, lc_do);
836 wef_s->finally_block = parse_block(parse);
837 } else {
838 wef_s->finally_block = NULL;
839 }
840
841 lmatch(parse, lc_end);
842
843 return wef_s;
844}
845
846/* Parse expression statement.
847 *
848 * @param parse Parser object.
849 * @return New syntax tree node.
850 */
851static stree_exps_t *parse_exps(parse_t *parse)
852{
853 stree_expr_t *expr;
854 stree_exps_t *exps;
855
856#ifdef DEBUG_PARSE_TRACE
857 printf("Parse expression statement.\n");
858#endif
859 expr = parse_expr(parse);
860 lmatch(parse, lc_scolon);
861
862 exps = stree_exps_new();
863 exps->expr = expr;
864
865 return exps;
866}
867
868/* Parse @c except clause.
869 *
870 * @param parse Parser object.
871 * @return New syntax tree node.
872 */
873static stree_except_t *parse_except(parse_t *parse)
874{
875 stree_except_t *except_c;
876
877#ifdef DEBUG_PARSE_TRACE
878 printf("Parse 'except' statement.\n");
879#endif
880 except_c = stree_except_new();
881
882 lmatch(parse, lc_except);
883 except_c->evar = parse_ident(parse);
884 lmatch(parse, lc_colon);
885 except_c->etype = parse_texpr(parse);
886 lmatch(parse, lc_do);
887
888 except_c->block = parse_block(parse);
889
890 return except_c;
891}
892
893/** Parse identifier.
894 *
895 * @param parse Parser object.
896 * @return New syntax tree node.
897 */
898stree_ident_t *parse_ident(parse_t *parse)
899{
900 stree_ident_t *ident;
901
902#ifdef DEBUG_PARSE_TRACE
903 printf("Parse identifier.\n");
904#endif
905 lcheck(parse, lc_ident);
906 ident = stree_ident_new();
907 ident->sid = lcur(parse)->u.ident.sid;
908 lskip(parse);
909
910 return ident;
911}
912
913/** Signal a parse error, start bailing out from parser.
914 *
915 * @param parse Parser object.
916 */
917void parse_raise_error(parse_t *parse)
918{
919 parse->error = b_true;
920 parse->error_bailout = b_true;
921}
922
923/** Note a parse error that has been immediately recovered.
924 *
925 * @param parse Parser object.
926 */
927void parse_note_error(parse_t *parse)
928{
929 parse->error = b_true;
930}
931
932/** Check if we are currently bailing out of parser due to a parse error.
933 *
934 * @param parse Parser object.
935 */
936bool_t parse_is_error(parse_t *parse)
937{
938 return parse->error_bailout;
939}
940
941/** Recover from parse error bailout.
942 *
943 * Still remember that there was an error, but stop bailing out.
944 *
945 * @param parse Parser object.
946 */
947void parse_recover_error(parse_t *parse)
948{
949 assert(parse->error == b_true);
950 assert(parse->error_bailout == b_true);
951
952 parse->error_bailout = b_false;
953}
954
955/** Return current lem.
956 *
957 * @param parse Parser object.
958 * @return Pointer to current lem. Only valid until the lexing
959 * position is advanced.
960 */
961lem_t *lcur(parse_t *parse)
962{
963#ifdef DEBUG_LPARSE_TRACE
964 printf("lcur()\n");
965#endif
966 return lex_get_current(parse->lex);
967}
968
969/** Return current lem lclass.
970 *
971 * @param parse Parser object.
972 * @return Lclass of the current lem.
973 */
974lclass_t lcur_lc(parse_t *parse)
975{
976 lem_t *lem;
977
978 /*
979 * This allows us to skip error checking in many places. If there is an
980 * active error, lcur_lc() returns lc_invalid without reading input.
981 *
982 * Without this measure we would have to check for error all the time
983 * or risk requiring extra input from the user (in interactive mode)
984 * before actually bailing out from the parser.
985 */
986 if (parse_is_error(parse))
987 return lc_invalid;
988
989 lem = lcur(parse);
990 return lem->lclass;
991}
992
993/** Skip to next lem.
994 *
995 * @param parse Parser object.
996 */
997void lskip(parse_t *parse)
998{
999#ifdef DEBUG_LPARSE_TRACE
1000 printf("lskip()\n");
1001#endif
1002 lex_next(parse->lex);
1003}
1004
1005/** Verify that lclass of current lem is @a lc.
1006 *
1007 * If a lem of different lclass is found, a parse error is raised and
1008 * a message is printed.
1009 *
1010 * @param parse Parser object.
1011 * @param lc Expected lclass.
1012 */
1013void lcheck(parse_t *parse, lclass_t lc)
1014{
1015#ifdef DEBUG_LPARSE_TRACE
1016 printf("lcheck(");
1017 lclass_print(lc);
1018 printf(")\n");
1019#endif
1020 if (lcur(parse)->lclass != lc) {
1021 lem_print_coords(lcur(parse));
1022 printf(" Error: expected '"); lclass_print(lc);
1023 printf("', got '"); lem_print(lcur(parse));
1024 printf("'.\n");
1025 parse_raise_error(parse);
1026 }
1027}
1028
1029/** Verify that lclass of current lem is @a lc and go to next lem.
1030 *
1031 * If a lem of different lclass is found, a parse error is raised and
1032 * a message is printed.
1033 *
1034 * @param parse Parser object.
1035 * @param lc Expected lclass.
1036 */
1037void lmatch(parse_t *parse, lclass_t lc)
1038{
1039#ifdef DEBUG_LPARSE_TRACE
1040 printf("lmatch(");
1041 lclass_print(lc);
1042 printf(")\n");
1043#endif
1044 /*
1045 * This allows us to skip error checking in many places. If there is an
1046 * active error, lmatch() does nothing (similar to parse_block(), etc.
1047 *
1048 * Without this measure we would have to check for error all the time
1049 * or risk requiring extra input from the user (in interactive mode)
1050 * before actually bailing out from the parser.
1051 */
1052 if (parse_is_error(parse))
1053 return;
1054
1055 lcheck(parse, lc);
1056 lskip(parse);
1057}
1058
1059/** Raise and display generic parsing error.
1060 *
1061 * @param parse Parser object.
1062 */
1063void lunexpected_error(parse_t *parse)
1064{
1065 lem_print_coords(lcur(parse));
1066 printf(" Error: unexpected token '");
1067 lem_print(lcur(parse));
1068 printf("'.\n");
1069 parse_raise_error(parse);
1070}
1071
1072/** Determine whether @a lclass is in follow(block).
1073 *
1074 * Tests whether @a lclass belongs to the follow(block) set, i.e. if it is
1075 * lclass of a lem that can follow a block in the program.
1076 *
1077 * @param lclass Lclass.
1078 */
1079bool_t terminates_block(lclass_t lclass)
1080{
1081 switch (lclass) {
1082 case lc_else:
1083 case lc_end:
1084 case lc_except:
1085 case lc_finally:
1086 return b_true;
1087 default:
1088 return b_false;
1089 }
1090}
Note: See TracBrowser for help on using the repository browser.