source: mainline/uspace/app/sbi/src/parse.c@ 883fedc

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

Update SBI to rev. 207.

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