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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since caad59a was 074444f, checked in by Jiri Svoboda <jiri@…>, 15 years ago

Update SBI to rev. 184.

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