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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 88ab6e9 was 051b3db8, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Update SBI to rev. 344 from upstream. What's new:

  • Builtin.WriteLine() renamed to Console.WriteLine()
  • Implemented 'switch' statement
  • Significantly reduced memory consumption (also increases execution speed in some cases)
  • Properties can be accessed via unqualified names
  • Exceptions raised during property accesses are now handled correctly
  • Some missing checks against expressions returning no value added
  • Property mode set to 100644
File size: 37.1 KB
Line 
1/*
2 * Copyright (c) 2011 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 "cspan.h"
38#include "debug.h"
39#include "lex.h"
40#include "list.h"
41#include "mytypes.h"
42#include "p_expr.h"
43#include "p_type.h"
44#include "stree.h"
45#include "strtab.h"
46#include "symbol.h"
47
48#include "parse.h"
49
50/*
51 * Module and CSI members
52 */
53static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
54 stree_csi_t *outer_csi);
55static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi);
56
57static stree_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi);
58
59static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi);
60static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum);
61
62static stree_deleg_t *parse_deleg(parse_t *parse, stree_csi_t *outer_csi);
63static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi);
64static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi);
65static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi);
66
67static void parse_symbol_attrs(parse_t *parse, stree_symbol_t *symbol);
68static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse);
69
70static stree_proc_arg_t *parse_proc_arg(parse_t *parse);
71static stree_arg_attr_t *parse_arg_attr(parse_t *parse);
72static stree_fun_sig_t *parse_fun_sig(parse_t *parse);
73
74static void parse_prop_get(parse_t *parse, stree_prop_t *prop);
75static void parse_prop_set(parse_t *parse, stree_prop_t *prop);
76
77/*
78 * Statements
79 */
80static stree_block_t *parse_block(parse_t *parse);
81
82static stree_vdecl_t *parse_vdecl(parse_t *parse);
83static stree_if_t *parse_if(parse_t *parse);
84static stree_switch_t *parse_switch(parse_t *parse);
85static stree_while_t *parse_while(parse_t *parse);
86static stree_for_t *parse_for(parse_t *parse);
87static stree_raise_t *parse_raise(parse_t *parse);
88static stree_break_t *parse_break(parse_t *parse);
89static stree_return_t *parse_return(parse_t *parse);
90static stree_wef_t *parse_wef(parse_t *parse);
91static stree_exps_t *parse_exps(parse_t *parse);
92
93static stree_except_t *parse_except(parse_t *parse);
94
95/** Initialize parser object.
96 *
97 * Set up parser @a parse to use lexer @a lex for input and to store
98 * output (i.e. new declarations) to program @a prog. @a prog is not
99 * necessarily empty, the declarations being parsed are simply added
100 * to it.
101 *
102 * @param parse Parser object.
103 * @param prog Destination program stree.
104 * @param lex Input lexer.
105 */
106void parse_init(parse_t *parse, stree_program_t *prog, struct lex *lex)
107{
108 parse->program = prog;
109 parse->cur_mod = parse->program->module;
110 parse->lex = lex;
111
112 parse->error = b_false;
113 parse->error_bailout = b_false;
114
115 lex_next(parse->lex);
116}
117
118/** Parse module.
119 *
120 * Parse a program module.
121 *
122 * The input is read using the lexer associated with @a parse. The resulting
123 * declarations are added to existing declarations in the program associated
124 * with @a parse.
125 *
126 * If any parse error occurs, parse->error will @c b_true when this function
127 * returns. parse->error_bailout will be @c b_true if the error has not
128 * been recovered yet. Similar holds for other parsing functions in this
129 * module.
130 *
131 * @param parse Parser object.
132 */
133void parse_module(parse_t *parse)
134{
135 stree_csi_t *csi;
136 stree_enum_t *enum_d;
137 stree_modm_t *modm;
138
139 while (lcur_lc(parse) != lc_eof && !parse_is_error(parse)) {
140 switch (lcur_lc(parse)) {
141 case lc_class:
142 case lc_struct:
143 case lc_interface:
144 csi = parse_csi(parse, lcur_lc(parse), NULL);
145 modm = stree_modm_new(mc_csi);
146 modm->u.csi = csi;
147
148 list_append(&parse->cur_mod->members, modm);
149 break;
150 case lc_enum:
151 enum_d = parse_enum(parse, NULL);
152 modm = stree_modm_new(mc_enum);
153 modm->u.enum_d = enum_d;
154
155 list_append(&parse->cur_mod->members, modm);
156 break;
157 default:
158 lunexpected_error(parse);
159 lex_next(parse->lex);
160 break;
161 }
162
163 }
164}
165
166/** Parse class, struct or interface declaration.
167 *
168 * @param parse Parser object.
169 * @param dclass What to parse: @c lc_class, @c lc_struct or @c lc_csi.
170 * @param outer_csi CSI containing this declaration or @c NULL if global.
171 * @return New syntax tree node.
172 */
173static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
174 stree_csi_t *outer_csi)
175{
176 stree_csi_t *csi;
177 csi_class_t cc;
178 stree_csimbr_t *csimbr;
179 stree_symbol_t *symbol;
180 stree_ident_t *targ_name;
181 stree_targ_t *targ;
182 stree_texpr_t *pref;
183
184 switch (dclass) {
185 case lc_class: cc = csi_class; break;
186 case lc_struct: cc = csi_struct; break;
187 case lc_interface: cc = csi_interface; break;
188 default: assert(b_false);
189 }
190
191 lskip(parse);
192
193 csi = stree_csi_new(cc);
194 csi->name = parse_ident(parse);
195
196 list_init(&csi->targ);
197
198 while (lcur_lc(parse) == lc_slash) {
199 lskip(parse);
200 targ_name = parse_ident(parse);
201
202 targ = stree_targ_new();
203 targ->name = targ_name;
204
205 list_append(&csi->targ, targ);
206 }
207
208 symbol = stree_symbol_new(sc_csi);
209 symbol->u.csi = csi;
210 symbol->outer_csi = outer_csi;
211 csi->symbol = symbol;
212
213#ifdef DEBUG_PARSE_TRACE
214 printf("parse_csi: csi=%p, csi->name = %p (%s)\n", csi, csi->name,
215 strtab_get_str(csi->name->sid));
216#endif
217 if (lcur_lc(parse) == lc_colon) {
218 /* Inheritance list */
219 lskip(parse);
220
221 while (b_true) {
222 pref = parse_texpr(parse);
223 if (parse_is_error(parse))
224 break;
225
226 list_append(&csi->inherit, pref);
227 if (lcur_lc(parse) != lc_plus)
228 break;
229
230 lskip(parse);
231 }
232 }
233
234 lmatch(parse, lc_is);
235 list_init(&csi->members);
236
237 /* Parse class, struct or interface members. */
238 while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
239 csimbr = parse_csimbr(parse, csi);
240 if (csimbr == NULL)
241 continue;
242
243 list_append(&csi->members, csimbr);
244 }
245
246 lmatch(parse, lc_end);
247
248 if (outer_csi != NULL) {
249 switch (outer_csi->cc) {
250 case csi_class:
251 case csi_struct:
252 break;
253 case csi_interface:
254 cspan_print(csi->name->cspan);
255 printf(" Error: CSI declared inside interface.\n");
256 parse_note_error(parse);
257 /* XXX Free csi */
258 return NULL;
259 }
260 }
261
262 return csi;
263}
264
265/** Parse class, struct or interface member.
266 *
267 * @param parse Parser object.
268 * @param outer_csi CSI containing this declaration.
269 * @return New syntax tree node. In case of parse error,
270 * @c NULL may (but need not) be returned.
271 */
272static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi)
273{
274 stree_csimbr_t *csimbr;
275
276 stree_csi_t *csi;
277 stree_ctor_t *ctor;
278 stree_deleg_t *deleg;
279 stree_enum_t *enum_d;
280 stree_fun_t *fun;
281 stree_var_t *var;
282 stree_prop_t *prop;
283
284 csimbr = NULL;
285
286 switch (lcur_lc(parse)) {
287 case lc_class:
288 case lc_struct:
289 case lc_interface:
290 csi = parse_csi(parse, lcur_lc(parse), outer_csi);
291 if (csi != NULL) {
292 csimbr = stree_csimbr_new(csimbr_csi);
293 csimbr->u.csi = csi;
294 }
295 break;
296 case lc_new:
297 ctor = parse_ctor(parse, outer_csi);
298 if (ctor != NULL) {
299 csimbr = stree_csimbr_new(csimbr_ctor);
300 csimbr->u.ctor = ctor;
301 }
302 break;
303 case lc_deleg:
304 deleg = parse_deleg(parse, outer_csi);
305 if (deleg != NULL) {
306 csimbr = stree_csimbr_new(csimbr_deleg);
307 csimbr->u.deleg = deleg;
308 }
309 break;
310 case lc_enum:
311 enum_d = parse_enum(parse, outer_csi);
312 if (enum_d != NULL) {
313 csimbr = stree_csimbr_new(csimbr_enum);
314 csimbr->u.enum_d = enum_d;
315 }
316 break;
317 case lc_fun:
318 fun = parse_fun(parse, outer_csi);
319 csimbr = stree_csimbr_new(csimbr_fun);
320 csimbr->u.fun = fun;
321 break;
322 case lc_var:
323 var = parse_var(parse, outer_csi);
324 if (var != NULL) {
325 csimbr = stree_csimbr_new(csimbr_var);
326 csimbr->u.var = var;
327 }
328 break;
329 case lc_prop:
330 prop = parse_prop(parse, outer_csi);
331 csimbr = stree_csimbr_new(csimbr_prop);
332 csimbr->u.prop = prop;
333 break;
334 default:
335 lunexpected_error(parse);
336 lex_next(parse->lex);
337 break;
338 }
339
340 return csimbr;
341}
342
343/** Parse constructor.
344 *
345 * @param parse Parser object.
346 * @param outer_csi CSI containing this declaration or @c NULL if global.
347 * @return New syntax tree node.
348 */
349static stree_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi)
350{
351 stree_ctor_t *ctor;
352 stree_symbol_t *symbol;
353 cspan_t *cspan;
354
355 ctor = stree_ctor_new();
356 symbol = stree_symbol_new(sc_ctor);
357
358 symbol->u.ctor = ctor;
359 symbol->outer_csi = outer_csi;
360 ctor->symbol = symbol;
361
362 lmatch(parse, lc_new);
363 cspan = lprev_span(parse);
364
365 /* Fake identifier. */
366 ctor->name = stree_ident_new();
367 ctor->name->sid = strtab_get_sid(CTOR_IDENT);
368 ctor->name->cspan = lprev_span(parse);
369
370#ifdef DEBUG_PARSE_TRACE
371 printf("Parsing constructor of CSI '");
372 symbol_print_fqn(csi_to_symbol(outer_csi));
373 printf("'.\n");
374#endif
375 ctor->sig = parse_fun_sig(parse);
376 if (ctor->sig->rtype != NULL) {
377 cspan_print(cspan);
378 printf(" Error: Constructor of CSI '");
379 symbol_print_fqn(csi_to_symbol(outer_csi));
380 printf("' has a return type.\n");
381 parse_note_error(parse);
382 }
383
384 /* Parse attributes. */
385 parse_symbol_attrs(parse, symbol);
386
387 ctor->proc = stree_proc_new();
388 ctor->proc->outer_symbol = symbol;
389
390 if (lcur_lc(parse) == lc_scolon) {
391 lskip(parse);
392
393 /* This constructor has no body. */
394 cspan_print(cspan);
395 printf(" Error: Constructor of CSI '");
396 symbol_print_fqn(csi_to_symbol(outer_csi));
397 printf("' has no body.\n");
398 parse_note_error(parse);
399
400 ctor->proc->body = NULL;
401 } else {
402 lmatch(parse, lc_is);
403 ctor->proc->body = parse_block(parse);
404 lmatch(parse, lc_end);
405 }
406
407 switch (outer_csi->cc) {
408 case csi_class:
409 case csi_struct:
410 break;
411 case csi_interface:
412 cspan_print(ctor->name->cspan);
413 printf(" Error: Constructor declared inside interface.\n");
414 parse_note_error(parse);
415 /* XXX Free ctor */
416 return NULL;
417 }
418
419 return ctor;
420}
421
422/** Parse @c enum declaration.
423 *
424 * @param parse Parser object.
425 * @param outer_csi CSI containing this declaration or @c NULL if global.
426 * @return New syntax tree node.
427 */
428static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi)
429{
430 stree_enum_t *enum_d;
431 stree_symbol_t *symbol;
432 stree_embr_t *embr;
433
434 enum_d = stree_enum_new();
435 symbol = stree_symbol_new(sc_enum);
436
437 symbol->u.enum_d = enum_d;
438 symbol->outer_csi = outer_csi;
439 enum_d->symbol = symbol;
440
441 lmatch(parse, lc_enum);
442 enum_d->name = parse_ident(parse);
443 list_init(&enum_d->members);
444
445#ifdef DEBUG_PARSE_TRACE
446 printf("Parse enum '%s'.\n", strtab_get_str(enum_d->name->sid));
447#endif
448 lmatch(parse, lc_is);
449
450 /* Parse enum members. */
451 while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
452 embr = parse_embr(parse, enum_d);
453 if (embr == NULL)
454 break;
455
456 list_append(&enum_d->members, embr);
457 }
458
459 if (list_is_empty(&enum_d->members)) {
460 cspan_print(enum_d->name->cspan);
461 printf("Error: Enum type '%s' has no members.\n",
462 strtab_get_str(enum_d->name->sid));
463 parse_note_error(parse);
464 }
465
466 lmatch(parse, lc_end);
467
468 if (outer_csi != NULL) {
469 switch (outer_csi->cc) {
470 case csi_class:
471 case csi_struct:
472 break;
473 case csi_interface:
474 cspan_print(enum_d->name->cspan);
475 printf(" Error: Enum declared inside interface.\n");
476 parse_note_error(parse);
477 /* XXX Free enum */
478 return NULL;
479 }
480 }
481
482 return enum_d;
483}
484
485/** Parse enum member.
486 *
487 * @param parse Parser object.
488 * @param outer_enum Enum containing this declaration.
489 * @return New syntax tree node. In case of parse error,
490 * @c NULL may (but need not) be returned.
491 */
492static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum)
493{
494 stree_embr_t *embr;
495
496 embr = stree_embr_new();
497 embr->outer_enum = outer_enum;
498 embr->name = parse_ident(parse);
499
500 lmatch(parse, lc_scolon);
501
502 return embr;
503}
504
505/** Parse delegate.
506 *
507 * @param parse Parser object.
508 * @param outer_csi CSI containing this declaration or @c NULL if global.
509 * @return New syntax tree node.
510 */
511static stree_deleg_t *parse_deleg(parse_t *parse, stree_csi_t *outer_csi)
512{
513 stree_deleg_t *deleg;
514 stree_symbol_t *symbol;
515
516 deleg = stree_deleg_new();
517 symbol = stree_symbol_new(sc_deleg);
518
519 symbol->u.deleg = deleg;
520 symbol->outer_csi = outer_csi;
521 deleg->symbol = symbol;
522
523 lmatch(parse, lc_deleg);
524 deleg->name = parse_ident(parse);
525
526#ifdef DEBUG_PARSE_TRACE
527 printf("Parsing delegate '%s'.\n", strtab_get_str(deleg->name->sid));
528#endif
529
530 deleg->sig = parse_fun_sig(parse);
531
532 /* Parse attributes. */
533 parse_symbol_attrs(parse, symbol);
534
535 lmatch(parse, lc_scolon);
536
537 switch (outer_csi->cc) {
538 case csi_class:
539 case csi_struct:
540 break;
541 case csi_interface:
542 cspan_print(deleg->name->cspan);
543 printf(" Error: Delegate declared inside interface.\n");
544 parse_note_error(parse);
545 /* XXX Free deleg */
546 return NULL;
547 }
548
549 return deleg;
550}
551
552/** Parse member function.
553 *
554 * @param parse Parser object.
555 * @param outer_csi CSI containing this declaration or @c NULL if global.
556 * @return New syntax tree node.
557 */
558static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi)
559{
560 stree_fun_t *fun;
561 stree_symbol_t *symbol;
562 bool_t body_expected;
563
564 fun = stree_fun_new();
565 symbol = stree_symbol_new(sc_fun);
566
567 symbol->u.fun = fun;
568 symbol->outer_csi = outer_csi;
569 fun->symbol = symbol;
570
571 lmatch(parse, lc_fun);
572 fun->name = parse_ident(parse);
573
574#ifdef DEBUG_PARSE_TRACE
575 printf("Parsing function '%s'.\n", strtab_get_str(fun->name->sid));
576#endif
577 fun->sig = parse_fun_sig(parse);
578
579 /* Parse attributes. */
580 parse_symbol_attrs(parse, symbol);
581
582 body_expected = !stree_symbol_has_attr(symbol, sac_builtin) &&
583 (outer_csi->cc != csi_interface);
584
585 fun->proc = stree_proc_new();
586 fun->proc->outer_symbol = symbol;
587
588 if (lcur_lc(parse) == lc_scolon) {
589 lskip(parse);
590
591 /* Body not present */
592 if (body_expected) {
593 cspan_print(fun->name->cspan);
594 printf(" Error: Function '");
595 symbol_print_fqn(symbol);
596 printf("' should have a body.\n");
597 parse_note_error(parse);
598 }
599
600 fun->proc->body = NULL;
601 } else {
602 lmatch(parse, lc_is);
603 fun->proc->body = parse_block(parse);
604 lmatch(parse, lc_end);
605
606 /* Body present */
607 if (!body_expected) {
608 cspan_print(fun->name->cspan);
609 printf(" Error: Function declaration '");
610 symbol_print_fqn(symbol);
611 printf("' should not have a body.\n");
612 parse_note_error(parse);
613 }
614 }
615
616 return fun;
617}
618
619/** Parse member variable.
620 *
621 * @param parse Parser object.
622 * @param outer_csi CSI containing this declaration or @c NULL if global.
623 * @return New syntax tree node.
624 */
625static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi)
626{
627 stree_var_t *var;
628 stree_symbol_t *symbol;
629
630 var = stree_var_new();
631 symbol = stree_symbol_new(sc_var);
632 symbol->u.var = var;
633 symbol->outer_csi = outer_csi;
634 var->symbol = symbol;
635
636 lmatch(parse, lc_var);
637 var->name = parse_ident(parse);
638 lmatch(parse, lc_colon);
639 var->type = parse_texpr(parse);
640
641 parse_symbol_attrs(parse, symbol);
642
643 lmatch(parse, lc_scolon);
644
645 switch (outer_csi->cc) {
646 case csi_class:
647 case csi_struct:
648 break;
649 case csi_interface:
650 cspan_print(var->name->cspan);
651 printf(" Error: Variable declared inside interface.\n");
652 parse_note_error(parse);
653 /* XXX Free var */
654 return NULL;
655 }
656
657 return var;
658}
659
660/** Parse member property.
661 *
662 * @param parse Parser object.
663 * @param outer_csi CSI containing this declaration or @c NULL if global.
664 * @return New syntax tree node.
665 */
666static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi)
667{
668 stree_prop_t *prop;
669 stree_symbol_t *symbol;
670
671 stree_ident_t *ident;
672 stree_proc_arg_t *arg;
673
674 prop = stree_prop_new();
675 list_init(&prop->args);
676
677 symbol = stree_symbol_new(sc_prop);
678 symbol->u.prop = prop;
679 symbol->outer_csi = outer_csi;
680 prop->symbol = symbol;
681
682 lmatch(parse, lc_prop);
683
684 if (lcur_lc(parse) == lc_self) {
685 /* Indexed property set */
686
687 /* Use some name that is impossible as identifier. */
688 ident = stree_ident_new();
689 ident->sid = strtab_get_sid(INDEXER_IDENT);
690 prop->name = ident;
691
692 lskip(parse);
693 lmatch(parse, lc_lsbr);
694
695 /* Parse formal parameters. */
696 while (!parse_is_error(parse)) {
697 arg = parse_proc_arg(parse);
698 if (stree_arg_has_attr(arg, aac_packed)) {
699 prop->varg = arg;
700 break;
701 } else {
702 list_append(&prop->args, arg);
703 }
704
705 if (lcur_lc(parse) == lc_rsbr)
706 break;
707
708 lmatch(parse, lc_scolon);
709 }
710
711 lmatch(parse, lc_rsbr);
712 } else {
713 /* Named property */
714 prop->name = parse_ident(parse);
715 }
716
717 lmatch(parse, lc_colon);
718 prop->type = parse_texpr(parse);
719
720 /* Parse attributes. */
721 parse_symbol_attrs(parse, symbol);
722
723 lmatch(parse, lc_is);
724
725 while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
726 switch (lcur_lc(parse)) {
727 case lc_get:
728 parse_prop_get(parse, prop);
729 break;
730 case lc_set:
731 parse_prop_set(parse, prop);
732 break;
733 default:
734 lunexpected_error(parse);
735 }
736 }
737
738 lmatch(parse, lc_end);
739
740 return prop;
741}
742
743/** Parse symbol attributes.
744 *
745 * Parse list of attributes and add them to @a symbol.
746 *
747 * @param parse Parser object
748 * @param symbol Symbol to add these attributes to
749 */
750static void parse_symbol_attrs(parse_t *parse, stree_symbol_t *symbol)
751{
752 stree_symbol_attr_t *attr;
753
754 /* Parse attributes. */
755 while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
756 lskip(parse);
757 attr = parse_symbol_attr(parse);
758 list_append(&symbol->attr, attr);
759 }
760}
761
762/** Parse symbol attribute.
763 *
764 * @param parse Parser object
765 * @return New syntax tree node
766 */
767static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse)
768{
769 stree_symbol_attr_t *attr;
770 symbol_attr_class_t sac;
771
772 /* Make compiler happy. */
773 sac = 0;
774
775 switch (lcur_lc(parse)) {
776 case lc_builtin: sac = sac_builtin; break;
777 case lc_static: sac = sac_static; break;
778 default:
779 cspan_print(lcur_span(parse));
780 printf(" Error: Unexpected attribute '");
781 lem_print(lcur(parse));
782 printf("'.\n");
783 parse_note_error(parse);
784 break;
785 }
786
787 lskip(parse);
788
789 attr = stree_symbol_attr_new(sac);
790 return attr;
791}
792
793/** Parse formal function argument.
794 *
795 * @param parse Parser object.
796 * @return New syntax tree node.
797 */
798static stree_proc_arg_t *parse_proc_arg(parse_t *parse)
799{
800 stree_proc_arg_t *arg;
801 stree_arg_attr_t *attr;
802
803 arg = stree_proc_arg_new();
804 arg->name = parse_ident(parse);
805 lmatch(parse, lc_colon);
806 arg->type = parse_texpr(parse);
807
808#ifdef DEBUG_PARSE_TRACE
809 printf("Parse procedure argument.\n");
810#endif
811 list_init(&arg->attr);
812
813 /* Parse attributes. */
814 while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
815 lskip(parse);
816 attr = parse_arg_attr(parse);
817 list_append(&arg->attr, attr);
818 }
819
820 return arg;
821}
822
823/** Parse argument attribute.
824 *
825 * @param parse Parser object.
826 * @return New syntax tree node.
827 */
828static stree_arg_attr_t *parse_arg_attr(parse_t *parse)
829{
830 stree_arg_attr_t *attr;
831
832 if (lcur_lc(parse) != lc_packed) {
833 cspan_print(lcur_span(parse));
834 printf(" Error: Unexpected attribute '");
835 lem_print(lcur(parse));
836 printf("'.\n");
837 parse_note_error(parse);
838 }
839
840 lskip(parse);
841
842 attr = stree_arg_attr_new(aac_packed);
843 return attr;
844}
845
846/** Parse function signature.
847 *
848 * @param parse Parser object.
849 * @return New syntax tree node.
850 */
851static stree_fun_sig_t *parse_fun_sig(parse_t *parse)
852{
853 stree_fun_sig_t *sig;
854 stree_proc_arg_t *arg;
855
856 sig = stree_fun_sig_new();
857
858 lmatch(parse, lc_lparen);
859
860#ifdef DEBUG_PARSE_TRACE
861 printf("Parsing function signature.\n");
862#endif
863
864 list_init(&sig->args);
865
866 if (lcur_lc(parse) != lc_rparen) {
867
868 /* Parse formal parameters. */
869 while (!parse_is_error(parse)) {
870 arg = parse_proc_arg(parse);
871
872 if (stree_arg_has_attr(arg, aac_packed)) {
873 sig->varg = arg;
874 break;
875 } else {
876 list_append(&sig->args, arg);
877 }
878
879 if (lcur_lc(parse) == lc_rparen)
880 break;
881
882 lmatch(parse, lc_scolon);
883 }
884 }
885
886 lmatch(parse, lc_rparen);
887
888 if (lcur_lc(parse) == lc_colon) {
889 lskip(parse);
890 sig->rtype = parse_texpr(parse);
891 } else {
892 sig->rtype = NULL;
893 }
894
895 return sig;
896}
897
898/** Parse member property getter.
899 *
900 * @param parse Parser object.
901 * @param prop Property containing this declaration.
902 */
903static void parse_prop_get(parse_t *parse, stree_prop_t *prop)
904{
905 cspan_t *cspan;
906 stree_block_t *block;
907 stree_proc_t *getter;
908 bool_t body_expected;
909
910 body_expected = (prop->symbol->outer_csi->cc != csi_interface);
911
912 lskip(parse);
913 cspan = lprev_span(parse);
914
915 if (prop->getter != NULL) {
916 cspan_print(cspan);
917 printf(" Error: Duplicate getter.\n");
918 parse_note_error(parse);
919 return;
920 }
921
922 if (lcur_lc(parse) == lc_scolon) {
923 /* Body not present */
924 lskip(parse);
925 block = NULL;
926
927 if (body_expected) {
928 cspan_print(prop->name->cspan);
929 printf(" Error: Property '");
930 symbol_print_fqn(prop->symbol);
931 printf("' getter should have "
932 "a body.\n");
933 parse_note_error(parse);
934 }
935 } else {
936 /* Body present */
937 lmatch(parse, lc_is);
938 block = parse_block(parse);
939 lmatch(parse, lc_end);
940
941 if (!body_expected) {
942 cspan_print(prop->name->cspan);
943 printf(" Error: Property '");
944 symbol_print_fqn(prop->symbol);
945 printf("' getter declaration should "
946 "not have a body.\n");
947 parse_note_error(parse);
948
949 /* XXX Free block */
950 block = NULL;
951 }
952 }
953
954 /* Create getter procedure */
955 getter = stree_proc_new();
956 getter->body = block;
957 getter->outer_symbol = prop->symbol;
958
959 /* Store getter in property. */
960 prop->getter = getter;
961}
962
963
964/** Parse member property setter.
965 *
966 * @param parse Parser object.
967 * @param prop Property containing this declaration.
968 */
969static void parse_prop_set(parse_t *parse, stree_prop_t *prop)
970{
971 cspan_t *cspan;
972 stree_block_t *block;
973 stree_proc_t *setter;
974 bool_t body_expected;
975
976 body_expected = (prop->symbol->outer_csi->cc != csi_interface);
977
978 lskip(parse);
979 cspan = lprev_span(parse);
980
981 if (prop->setter != NULL) {
982 cspan_print(cspan);
983 printf(" Error: Duplicate setter.\n");
984 parse_note_error(parse);
985 return;
986 }
987
988 prop->setter_arg = stree_proc_arg_new();
989 prop->setter_arg->name = parse_ident(parse);
990 prop->setter_arg->type = prop->type;
991
992 if (lcur_lc(parse) == lc_scolon) {
993 /* Body not present */
994 lskip(parse);
995
996 block = NULL;
997
998 if (body_expected) {
999 cspan_print(prop->name->cspan);
1000 printf(" Error: Property '");
1001 symbol_print_fqn(prop->symbol);
1002 printf("' setter should have "
1003 "a body.\n");
1004 parse_note_error(parse);
1005 }
1006 } else {
1007 /* Body present */
1008 lmatch(parse, lc_is);
1009 block = parse_block(parse);
1010 lmatch(parse, lc_end);
1011
1012 if (!body_expected) {
1013 cspan_print(prop->name->cspan);
1014 printf(" Error: Property '");
1015 symbol_print_fqn(prop->symbol);
1016 printf("' setter declaration should "
1017 "not have a body.\n");
1018 parse_note_error(parse);
1019 }
1020 }
1021
1022
1023 /* Create setter procedure */
1024 setter = stree_proc_new();
1025 setter->body = block;
1026 setter->outer_symbol = prop->symbol;
1027
1028 /* Store setter in property. */
1029 prop->setter = setter;
1030}
1031
1032/** Parse statement block.
1033 *
1034 * @param parse Parser object.
1035 * @return New syntax tree node.
1036 */
1037static stree_block_t *parse_block(parse_t *parse)
1038{
1039 stree_block_t *block;
1040 stree_stat_t *stat;
1041
1042 block = stree_block_new();
1043 list_init(&block->stats);
1044
1045 /* Avoid peeking if there is an error condition. */
1046 if (parse_is_error(parse))
1047 return block;
1048
1049 while (terminates_block(lcur_lc(parse)) != b_true &&
1050 !parse_is_error(parse)) {
1051
1052 stat = parse_stat(parse);
1053 list_append(&block->stats, stat);
1054 }
1055
1056 return block;
1057}
1058
1059/** Parse statement.
1060 *
1061 * @param parse Parser object.
1062 * @return New syntax tree node.
1063 */
1064stree_stat_t *parse_stat(parse_t *parse)
1065{
1066 stree_stat_t *stat;
1067
1068 stree_vdecl_t *vdecl_s;
1069 stree_if_t *if_s;
1070 stree_switch_t *switch_s;
1071 stree_while_t *while_s;
1072 stree_for_t *for_s;
1073 stree_raise_t *raise_s;
1074 stree_break_t *break_s;
1075 stree_return_t *return_s;
1076 stree_wef_t *wef_s;
1077 stree_exps_t *exp_s;
1078
1079#ifdef DEBUG_PARSE_TRACE
1080 printf("Parse statement.\n");
1081#endif
1082 switch (lcur_lc(parse)) {
1083 case lc_var:
1084 vdecl_s = parse_vdecl(parse);
1085 stat = stree_stat_new(st_vdecl);
1086 stat->u.vdecl_s = vdecl_s;
1087 break;
1088 case lc_if:
1089 if_s = parse_if(parse);
1090 stat = stree_stat_new(st_if);
1091 stat->u.if_s = if_s;
1092 break;
1093 case lc_switch:
1094 switch_s = parse_switch(parse);
1095 stat = stree_stat_new(st_switch);
1096 stat->u.switch_s = switch_s;
1097 break;
1098 case lc_while:
1099 while_s = parse_while(parse);
1100 stat = stree_stat_new(st_while);
1101 stat->u.while_s = while_s;
1102 break;
1103 case lc_for:
1104 for_s = parse_for(parse);
1105 stat = stree_stat_new(st_for);
1106 stat->u.for_s = for_s;
1107 break;
1108 case lc_raise:
1109 raise_s = parse_raise(parse);
1110 stat = stree_stat_new(st_raise);
1111 stat->u.raise_s = raise_s;
1112 break;
1113 case lc_break:
1114 break_s = parse_break(parse);
1115 stat = stree_stat_new(st_break);
1116 stat->u.break_s = break_s;
1117 break;
1118 case lc_return:
1119 return_s = parse_return(parse);
1120 stat = stree_stat_new(st_return);
1121 stat->u.return_s = return_s;
1122 break;
1123 case lc_do:
1124 case lc_with:
1125 wef_s = parse_wef(parse);
1126 stat = stree_stat_new(st_wef);
1127 stat->u.wef_s = wef_s;
1128 break;
1129 default:
1130 exp_s = parse_exps(parse);
1131 stat = stree_stat_new(st_exps);
1132 stat->u.exp_s = exp_s;
1133 break;
1134 }
1135
1136#ifdef DEBUG_PARSE_TRACE
1137 printf("Parsed statement %p\n", stat);
1138#endif
1139 return stat;
1140}
1141
1142/** Parse variable declaration statement.
1143 *
1144 * @param parse Parser object.
1145 * @return New syntax tree node.
1146 */
1147static stree_vdecl_t *parse_vdecl(parse_t *parse)
1148{
1149 stree_vdecl_t *vdecl;
1150
1151 vdecl = stree_vdecl_new();
1152
1153 lmatch(parse, lc_var);
1154 vdecl->name = parse_ident(parse);
1155 lmatch(parse, lc_colon);
1156 vdecl->type = parse_texpr(parse);
1157
1158 if (lcur_lc(parse) == lc_assign) {
1159 lskip(parse);
1160 (void) parse_expr(parse);
1161 }
1162
1163 lmatch(parse, lc_scolon);
1164
1165#ifdef DEBUG_PARSE_TRACE
1166 printf("Parsed vdecl for '%s'\n", strtab_get_str(vdecl->name->sid));
1167 printf("vdecl = %p, vdecl->name = %p, sid=%d\n",
1168 vdecl, vdecl->name, vdecl->name->sid);
1169#endif
1170 return vdecl;
1171}
1172
1173/** Parse @c if statement.
1174 *
1175 * @param parse Parser object.
1176 * @return New syntax tree node.
1177 */
1178static stree_if_t *parse_if(parse_t *parse)
1179{
1180 stree_if_t *if_s;
1181 stree_if_clause_t *if_c;
1182
1183#ifdef DEBUG_PARSE_TRACE
1184 printf("Parse 'if' statement.\n");
1185#endif
1186 if_s = stree_if_new();
1187 list_init(&if_s->if_clauses);
1188
1189 /* Parse @c if clause. */
1190 lmatch(parse, lc_if);
1191
1192 if_c = stree_if_clause_new();
1193 if_c->cond = parse_expr(parse);
1194 lmatch(parse, lc_then);
1195 if_c->block = parse_block(parse);
1196
1197 list_append(&if_s->if_clauses, if_c);
1198
1199 /* Parse @c elif clauses. */
1200 while (lcur_lc(parse) == lc_elif) {
1201 lskip(parse);
1202 if_c = stree_if_clause_new();
1203 if_c->cond = parse_expr(parse);
1204 lmatch(parse, lc_then);
1205 if_c->block = parse_block(parse);
1206
1207 list_append(&if_s->if_clauses, if_c);
1208 }
1209
1210 /* Parse @c else clause. */
1211 if (lcur_lc(parse) == lc_else) {
1212 lskip(parse);
1213 if_s->else_block = parse_block(parse);
1214 } else {
1215 if_s->else_block = NULL;
1216 }
1217
1218 lmatch(parse, lc_end);
1219 return if_s;
1220}
1221
1222/** Parse @c switch statement.
1223 *
1224 * @param parse Parser object.
1225 * @return New syntax tree node.
1226 */
1227static stree_switch_t *parse_switch(parse_t *parse)
1228{
1229 stree_switch_t *switch_s;
1230 stree_when_t *when_c;
1231 stree_expr_t *expr;
1232
1233#ifdef DEBUG_PARSE_TRACE
1234 printf("Parse 'switch' statement.\n");
1235#endif
1236 lmatch(parse, lc_switch);
1237
1238 switch_s = stree_switch_new();
1239 list_init(&switch_s->when_clauses);
1240
1241 switch_s->expr = parse_expr(parse);
1242 lmatch(parse, lc_is);
1243
1244 /* Parse @c when clauses. */
1245 while (lcur_lc(parse) == lc_when) {
1246 lskip(parse);
1247 when_c = stree_when_new();
1248 list_init(&when_c->exprs);
1249 while (b_true) {
1250 expr = parse_expr(parse);
1251 list_append(&when_c->exprs, expr);
1252 if (lcur_lc(parse) != lc_comma)
1253 break;
1254 lskip(parse);
1255 }
1256
1257 lmatch(parse, lc_do);
1258 when_c->block = parse_block(parse);
1259
1260 list_append(&switch_s->when_clauses, when_c);
1261 }
1262
1263 /* Parse @c else clause. */
1264 if (lcur_lc(parse) == lc_else) {
1265 lskip(parse);
1266 lmatch(parse, lc_do);
1267 switch_s->else_block = parse_block(parse);
1268 } else {
1269 switch_s->else_block = NULL;
1270 }
1271
1272 lmatch(parse, lc_end);
1273 return switch_s;
1274}
1275
1276/** Parse @c while statement.
1277 *
1278 * @param parse Parser object.
1279 */
1280static stree_while_t *parse_while(parse_t *parse)
1281{
1282 stree_while_t *while_s;
1283
1284#ifdef DEBUG_PARSE_TRACE
1285 printf("Parse 'while' statement.\n");
1286#endif
1287 while_s = stree_while_new();
1288
1289 lmatch(parse, lc_while);
1290 while_s->cond = parse_expr(parse);
1291 lmatch(parse, lc_do);
1292 while_s->body = parse_block(parse);
1293 lmatch(parse, lc_end);
1294
1295 return while_s;
1296}
1297
1298/** Parse @c for statement.
1299 *
1300 * @param parse Parser object.
1301 * @return New syntax tree node.
1302 */
1303static stree_for_t *parse_for(parse_t *parse)
1304{
1305 stree_for_t *for_s;
1306
1307#ifdef DEBUG_PARSE_TRACE
1308 printf("Parse 'for' statement.\n");
1309#endif
1310 for_s = stree_for_new();
1311
1312 lmatch(parse, lc_for);
1313 lmatch(parse, lc_ident);
1314 lmatch(parse, lc_colon);
1315 (void) parse_texpr(parse);
1316 lmatch(parse, lc_in);
1317 (void) parse_expr(parse);
1318 lmatch(parse, lc_do);
1319 for_s->body = parse_block(parse);
1320 lmatch(parse, lc_end);
1321
1322 return for_s;
1323}
1324
1325/** Parse @c raise statement.
1326 *
1327 * @param parse Parser object.
1328 */
1329static stree_raise_t *parse_raise(parse_t *parse)
1330{
1331 stree_raise_t *raise_s;
1332
1333#ifdef DEBUG_PARSE_TRACE
1334 printf("Parse 'raise' statement.\n");
1335#endif
1336 raise_s = stree_raise_new();
1337 lmatch(parse, lc_raise);
1338 raise_s->expr = parse_expr(parse);
1339 lmatch(parse, lc_scolon);
1340
1341 return raise_s;
1342}
1343
1344/** Parse @c break statement.
1345 *
1346 * @param parse Parser object.
1347 * @return New syntax tree node.
1348 */
1349static stree_break_t *parse_break(parse_t *parse)
1350{
1351 stree_break_t *break_s;
1352
1353#ifdef DEBUG_PARSE_TRACE
1354 printf("Parse 'break' statement.\n");
1355#endif
1356 break_s = stree_break_new();
1357
1358 lmatch(parse, lc_break);
1359 lmatch(parse, lc_scolon);
1360
1361 return break_s;
1362}
1363
1364/** Parse @c return statement.
1365 *
1366 * @param parse Parser object.
1367 * @return New syntax tree node.
1368 */
1369static stree_return_t *parse_return(parse_t *parse)
1370{
1371 stree_return_t *return_s;
1372
1373#ifdef DEBUG_PARSE_TRACE
1374 printf("Parse 'return' statement.\n");
1375#endif
1376 return_s = stree_return_new();
1377
1378 lmatch(parse, lc_return);
1379
1380 if (lcur_lc(parse) != lc_scolon)
1381 return_s->expr = parse_expr(parse);
1382
1383 lmatch(parse, lc_scolon);
1384
1385 return return_s;
1386}
1387
1388/* Parse @c with-except-finally statement.
1389 *
1390 * @param parse Parser object.
1391 * @return New syntax tree node.
1392 */
1393static stree_wef_t *parse_wef(parse_t *parse)
1394{
1395 stree_wef_t *wef_s;
1396 stree_except_t *except_c;
1397
1398#ifdef DEBUG_PARSE_TRACE
1399 printf("Parse WEF statement.\n");
1400#endif
1401 wef_s = stree_wef_new();
1402 list_init(&wef_s->except_clauses);
1403
1404 if (lcur_lc(parse) == lc_with) {
1405 lmatch(parse, lc_with);
1406 lmatch(parse, lc_ident);
1407 lmatch(parse, lc_colon);
1408 (void) parse_texpr(parse);
1409 lmatch(parse, lc_assign);
1410 (void) parse_expr(parse);
1411 }
1412
1413 lmatch(parse, lc_do);
1414 wef_s->with_block = parse_block(parse);
1415
1416 while (lcur_lc(parse) == lc_except && !parse_is_error(parse)) {
1417 except_c = parse_except(parse);
1418 list_append(&wef_s->except_clauses, except_c);
1419 }
1420
1421 if (lcur_lc(parse) == lc_finally) {
1422 lmatch(parse, lc_finally);
1423 lmatch(parse, lc_do);
1424 wef_s->finally_block = parse_block(parse);
1425 } else {
1426 wef_s->finally_block = NULL;
1427 }
1428
1429 lmatch(parse, lc_end);
1430
1431 return wef_s;
1432}
1433
1434/* Parse expression statement.
1435 *
1436 * @param parse Parser object.
1437 * @return New syntax tree node.
1438 */
1439static stree_exps_t *parse_exps(parse_t *parse)
1440{
1441 stree_expr_t *expr;
1442 stree_exps_t *exps;
1443
1444#ifdef DEBUG_PARSE_TRACE
1445 printf("Parse expression statement.\n");
1446#endif
1447 expr = parse_expr(parse);
1448 lmatch(parse, lc_scolon);
1449
1450 exps = stree_exps_new();
1451 exps->expr = expr;
1452
1453 return exps;
1454}
1455
1456/* Parse @c except clause.
1457 *
1458 * @param parse Parser object.
1459 * @return New syntax tree node.
1460 */
1461static stree_except_t *parse_except(parse_t *parse)
1462{
1463 stree_except_t *except_c;
1464
1465#ifdef DEBUG_PARSE_TRACE
1466 printf("Parse 'except' statement.\n");
1467#endif
1468 except_c = stree_except_new();
1469
1470 lmatch(parse, lc_except);
1471 except_c->evar = parse_ident(parse);
1472 lmatch(parse, lc_colon);
1473 except_c->etype = parse_texpr(parse);
1474 lmatch(parse, lc_do);
1475
1476 except_c->block = parse_block(parse);
1477
1478 return except_c;
1479}
1480
1481/** Parse identifier.
1482 *
1483 * @param parse Parser object.
1484 * @return New syntax tree node.
1485 */
1486stree_ident_t *parse_ident(parse_t *parse)
1487{
1488 stree_ident_t *ident;
1489
1490#ifdef DEBUG_PARSE_TRACE
1491 printf("Parse identifier.\n");
1492#endif
1493 lcheck(parse, lc_ident);
1494 ident = stree_ident_new();
1495 ident->sid = lcur(parse)->u.ident.sid;
1496 ident->cspan = lcur_span(parse);
1497 lskip(parse);
1498
1499 return ident;
1500}
1501
1502/** Signal a parse error, start bailing out from parser.
1503 *
1504 * @param parse Parser object.
1505 */
1506void parse_raise_error(parse_t *parse)
1507{
1508 parse->error = b_true;
1509 parse->error_bailout = b_true;
1510}
1511
1512/** Note a parse error that has been immediately recovered.
1513 *
1514 * @param parse Parser object.
1515 */
1516void parse_note_error(parse_t *parse)
1517{
1518 parse->error = b_true;
1519}
1520
1521/** Check if we are currently bailing out of parser due to a parse error.
1522 *
1523 * @param parse Parser object.
1524 */
1525bool_t parse_is_error(parse_t *parse)
1526{
1527 return parse->error_bailout;
1528}
1529
1530/** Recover from parse error bailout.
1531 *
1532 * Still remember that there was an error, but stop bailing out.
1533 *
1534 * @param parse Parser object.
1535 */
1536void parse_recover_error(parse_t *parse)
1537{
1538 assert(parse->error == b_true);
1539 assert(parse->error_bailout == b_true);
1540
1541 parse->error_bailout = b_false;
1542}
1543
1544/** Return current lem.
1545 *
1546 * @param parse Parser object.
1547 * @return Pointer to current lem. Only valid until the lexing
1548 * position is advanced.
1549 */
1550lem_t *lcur(parse_t *parse)
1551{
1552#ifdef DEBUG_LPARSE_TRACE
1553 printf("lcur()\n");
1554#endif
1555 return lex_get_current(parse->lex);
1556}
1557
1558/** Return current lem lclass.
1559 *
1560 * @param parse Parser object
1561 * @return Lclass of the current lem
1562 */
1563lclass_t lcur_lc(parse_t *parse)
1564{
1565 lem_t *lem;
1566
1567 /*
1568 * This allows us to skip error checking in many places. If there is an
1569 * active error, lcur_lc() returns lc_invalid without reading input.
1570 *
1571 * Without this measure we would have to check for error all the time
1572 * or risk requiring extra input from the user (in interactive mode)
1573 * before actually bailing out from the parser.
1574 */
1575 if (parse_is_error(parse))
1576 return lc_invalid;
1577
1578 lem = lcur(parse);
1579 return lem->lclass;
1580}
1581
1582/** Return coordinate span of current lem.
1583 *
1584 * @param parse Parser object
1585 * @return Coordinate span of current lem or @c NULL if a
1586 * parse error is active
1587 */
1588cspan_t *lcur_span(parse_t *parse)
1589{
1590 lem_t *lem;
1591
1592 if (parse_is_error(parse))
1593 return NULL;
1594
1595 lem = lcur(parse);
1596 return lem->cspan;
1597}
1598
1599/** Return coordinate span of previous lem.
1600 *
1601 * @param parse Parser object
1602 * @return Coordinate span of previous lem or @c NULL if
1603 * parse error is active or previous lem is not
1604 * available.
1605 */
1606cspan_t *lprev_span(parse_t *parse)
1607{
1608 lem_t *lem;
1609
1610 if (parse_is_error(parse))
1611 return NULL;
1612
1613 lem = lex_peek_prev(parse->lex);
1614 if (lem == NULL)
1615 return NULL;
1616
1617 return lem->cspan;
1618}
1619
1620/** Skip to next lem.
1621 *
1622 * @param parse Parser object.
1623 */
1624void lskip(parse_t *parse)
1625{
1626#ifdef DEBUG_LPARSE_TRACE
1627 printf("lskip()\n");
1628#endif
1629 lex_next(parse->lex);
1630}
1631
1632/** Verify that lclass of current lem is @a lc.
1633 *
1634 * If a lem of different lclass is found, a parse error is raised and
1635 * a message is printed.
1636 *
1637 * @param parse Parser object.
1638 * @param lc Expected lclass.
1639 */
1640void lcheck(parse_t *parse, lclass_t lc)
1641{
1642#ifdef DEBUG_LPARSE_TRACE
1643 printf("lcheck(");
1644 lclass_print(lc);
1645 printf(")\n");
1646#endif
1647 if (lcur(parse)->lclass != lc) {
1648 lem_print_coords(lcur(parse));
1649 printf(" Error: expected '"); lclass_print(lc);
1650 printf("', got '"); lem_print(lcur(parse));
1651 printf("'.\n");
1652 parse_raise_error(parse);
1653 }
1654}
1655
1656/** Verify that lclass of current lem is @a lc and go to next lem.
1657 *
1658 * If a lem of different lclass is found, a parse error is raised and
1659 * a message is printed.
1660 *
1661 * @param parse Parser object.
1662 * @param lc Expected lclass.
1663 */
1664void lmatch(parse_t *parse, lclass_t lc)
1665{
1666#ifdef DEBUG_LPARSE_TRACE
1667 printf("lmatch(");
1668 lclass_print(lc);
1669 printf(")\n");
1670#endif
1671 /*
1672 * This allows us to skip error checking in many places. If there is an
1673 * active error, lmatch() does nothing (similar to parse_block(), etc.
1674 *
1675 * Without this measure we would have to check for error all the time
1676 * or risk requiring extra input from the user (in interactive mode)
1677 * before actually bailing out from the parser.
1678 */
1679 if (parse_is_error(parse))
1680 return;
1681
1682 lcheck(parse, lc);
1683 lskip(parse);
1684}
1685
1686/** Raise and display generic parsing error.
1687 *
1688 * @param parse Parser object.
1689 */
1690void lunexpected_error(parse_t *parse)
1691{
1692 lem_print_coords(lcur(parse));
1693 printf(" Error: unexpected token '");
1694 lem_print(lcur(parse));
1695 printf("'.\n");
1696 parse_raise_error(parse);
1697}
1698
1699/** Determine whether @a lclass is in follow(block).
1700 *
1701 * Tests whether @a lclass belongs to the follow(block) set, i.e. if it is
1702 * lclass of a lem that can follow a block in the program.
1703 *
1704 * @param lclass Lclass.
1705 */
1706bool_t terminates_block(lclass_t lclass)
1707{
1708 switch (lclass) {
1709 case lc_elif:
1710 case lc_else:
1711 case lc_end:
1712 case lc_except:
1713 case lc_finally:
1714 case lc_when:
1715 return b_true;
1716 default:
1717 return b_false;
1718 }
1719}
Note: See TracBrowser for help on using the repository browser.