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

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

Update SBI to rev. 144.

  • Property mode set to 100644
File size: 17.4 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
81void parse_init(parse_t *parse, stree_program_t *prog, struct lex *lex)
82{
83 parse->program = prog;
84 parse->cur_mod = parse->program->module;
85 parse->lex = lex;
86 lex_next(parse->lex);
87}
88
89/** Parse module. */
90void parse_module(parse_t *parse)
91{
92 stree_csi_t *csi;
93 stree_modm_t *modm;
94
95 while (lcur_lc(parse) != lc_eof) {
96 switch (lcur_lc(parse)) {
97 case lc_class:
98 case lc_struct:
99 case lc_interface:
100 csi = parse_csi(parse, lcur_lc(parse), NULL);
101 modm = stree_modm_new(mc_csi);
102 modm->u.csi = csi;
103
104 list_append(&parse->cur_mod->members, modm);
105 break;
106 default:
107 lunexpected_error(parse);
108 lex_next(parse->lex);
109 break;
110 }
111
112 }
113}
114
115/** Parse class, struct or interface declaration. */
116static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
117 stree_csi_t *outer_csi)
118{
119 stree_csi_t *csi;
120 csi_class_t cc;
121 stree_csimbr_t *csimbr;
122 stree_symbol_t *symbol;
123
124 switch (dclass) {
125 case lc_class: cc = csi_class; break;
126 case lc_struct: cc = csi_struct; break;
127 case lc_interface: cc = csi_interface; break;
128 default: assert(b_false);
129 }
130
131 lskip(parse);
132
133 csi = stree_csi_new(cc);
134 csi->name = parse_ident(parse);
135
136 symbol = stree_symbol_new(sc_csi);
137 symbol->u.csi = csi;
138 symbol->outer_csi = outer_csi;
139 csi->symbol = symbol;
140
141#ifdef DEBUG_PARSE_TRACE
142 printf("parse_csi: csi=%p, csi->name = %p (%s)\n", csi, csi->name,
143 strtab_get_str(csi->name->sid));
144#endif
145 if (lcur_lc(parse) == lc_colon) {
146 /* Inheritance list */
147 lskip(parse);
148 csi->base_csi_ref = parse_texpr(parse);
149 } else {
150 csi->base_csi_ref = NULL;
151 }
152
153 lmatch(parse, lc_is);
154 list_init(&csi->members);
155
156 /* Parse class, struct or interface members. */
157 while (lcur_lc(parse) != lc_end) {
158 csimbr = parse_csimbr(parse, csi);
159 list_append(&csi->members, csimbr);
160 }
161
162 lmatch(parse, lc_end);
163
164 return csi;
165}
166
167/** Parse class, struct or interface member. */
168static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi)
169{
170 stree_csimbr_t *csimbr;
171
172 stree_csi_t *csi;
173 stree_fun_t *fun;
174 stree_var_t *var;
175 stree_prop_t *prop;
176
177 switch (lcur_lc(parse)) {
178 case lc_class:
179 case lc_struct:
180 case lc_interface:
181 csi = parse_csi(parse, lcur_lc(parse), outer_csi);
182 csimbr = stree_csimbr_new(csimbr_csi);
183 csimbr->u.csi = csi;
184 break;
185 case lc_fun:
186 fun = parse_fun(parse, outer_csi);
187 csimbr = stree_csimbr_new(csimbr_fun);
188 csimbr->u.fun = fun;
189 break;
190 case lc_var:
191 var = parse_var(parse, outer_csi);
192 csimbr = stree_csimbr_new(csimbr_var);
193 csimbr->u.var = var;
194 break;
195 case lc_prop:
196 prop = parse_prop(parse, outer_csi);
197 csimbr = stree_csimbr_new(csimbr_prop);
198 csimbr->u.prop = prop;
199 break;
200 default:
201 lunexpected_error(parse);
202 lex_next(parse->lex);
203 }
204
205 return csimbr;
206}
207
208
209/** Parse member function. */
210static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi)
211{
212 stree_fun_t *fun;
213 stree_proc_arg_t *arg;
214 stree_symbol_t *symbol;
215 stree_symbol_attr_t *attr;
216
217 fun = stree_fun_new();
218 symbol = stree_symbol_new(sc_fun);
219
220 symbol->u.fun = fun;
221 symbol->outer_csi = outer_csi;
222 fun->symbol = symbol;
223
224 lmatch(parse, lc_fun);
225 fun->name = parse_ident(parse);
226 lmatch(parse, lc_lparen);
227
228#ifdef DEBUG_PARSE_TRACE
229 printf("Parsing function '%s'.\n", strtab_get_str(fun->name->sid));
230#endif
231
232 list_init(&fun->args);
233
234 if (lcur_lc(parse) != lc_rparen) {
235
236 /* Parse formal parameters. */
237 while (b_true) {
238 arg = parse_proc_arg(parse);
239
240 if (stree_arg_has_attr(arg, aac_packed)) {
241 fun->varg = arg;
242 break;
243 } else {
244 list_append(&fun->args, arg);
245 }
246
247 if (lcur_lc(parse) == lc_rparen)
248 break;
249
250 lmatch(parse, lc_scolon);
251 }
252 }
253
254 lmatch(parse, lc_rparen);
255
256 if (lcur_lc(parse) == lc_colon) {
257 lskip(parse);
258 fun->rtype = parse_texpr(parse);
259 } else {
260 fun->rtype = NULL;
261 }
262
263 list_init(&symbol->attr);
264
265 /* Parse attributes. */
266 while (lcur_lc(parse) == lc_comma) {
267 lskip(parse);
268 attr = parse_symbol_attr(parse);
269 list_append(&symbol->attr, attr);
270 }
271
272 fun->proc = stree_proc_new();
273 fun->proc->outer_symbol = symbol;
274
275 if (lcur_lc(parse) == lc_scolon) {
276 lskip(parse);
277
278 /* This function has no body. */
279 if (!stree_symbol_has_attr(symbol, sac_builtin)) {
280 printf("Error: Function '");
281 symbol_print_fqn(symbol);
282 printf("' has no body.\n");
283 exit(1);
284 }
285 fun->proc->body = NULL;
286 } else {
287 lmatch(parse, lc_is);
288 fun->proc->body = parse_block(parse);
289 lmatch(parse, lc_end);
290 }
291
292 return fun;
293}
294
295/** Parse member variable. */
296static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi)
297{
298 stree_var_t *var;
299 stree_symbol_t *symbol;
300
301 var = stree_var_new();
302 symbol = stree_symbol_new(sc_var);
303 symbol->u.var = var;
304 symbol->outer_csi = outer_csi;
305 var->symbol = symbol;
306
307 lmatch(parse, lc_var);
308 var->name = parse_ident(parse);
309 lmatch(parse, lc_colon);
310 var->type = parse_texpr(parse);
311 lmatch(parse, lc_scolon);
312
313 return var;
314}
315
316/** Parse member property. */
317static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi)
318{
319 stree_prop_t *prop;
320 stree_symbol_t *symbol;
321
322 stree_ident_t *ident;
323 stree_proc_arg_t *arg;
324
325 prop = stree_prop_new();
326 list_init(&prop->args);
327
328 symbol = stree_symbol_new(sc_prop);
329 symbol->u.prop = prop;
330 symbol->outer_csi = outer_csi;
331 prop->symbol = symbol;
332
333 lmatch(parse, lc_prop);
334
335 if (lcur_lc(parse) == lc_self) {
336 /* Indexed property set */
337
338 /* Use some name that is impossible as identifier. */
339 ident = stree_ident_new();
340 ident->sid = strtab_get_sid(INDEXER_IDENT);
341 prop->name = ident;
342
343 lskip(parse);
344 lmatch(parse, lc_lsbr);
345
346 /* Parse formal parameters. */
347 while (b_true) {
348 arg = parse_proc_arg(parse);
349 if (stree_arg_has_attr(arg, aac_packed)) {
350 prop->varg = arg;
351 break;
352 } else {
353 list_append(&prop->args, arg);
354 }
355
356 if (lcur_lc(parse) == lc_rsbr)
357 break;
358
359 lmatch(parse, lc_scolon);
360 }
361
362 lmatch(parse, lc_rsbr);
363 } else {
364 /* Named property */
365 prop->name = parse_ident(parse);
366 }
367
368 lmatch(parse, lc_colon);
369 prop->type = parse_texpr(parse);
370 lmatch(parse, lc_is);
371
372 while (lcur_lc(parse) != lc_end) {
373 switch (lcur_lc(parse)) {
374 case lc_get:
375 lskip(parse);
376 lmatch(parse, lc_is);
377 if (prop->getter != NULL) {
378 printf("Error: Duplicate getter.\n");
379 exit(1);
380 }
381
382 /* Create setter procedure */
383 prop->getter = stree_proc_new();
384 prop->getter->body = parse_block(parse);
385 prop->getter->outer_symbol = symbol;
386
387 lmatch(parse, lc_end);
388 break;
389 case lc_set:
390 lskip(parse);
391 prop->setter_arg = stree_proc_arg_new();
392 prop->setter_arg->name = parse_ident(parse);
393 prop->setter_arg->type = prop->type;
394 lmatch(parse, lc_is);
395 if (prop->setter != NULL) {
396 printf("Error: Duplicate setter.\n");
397 exit(1);
398 }
399
400 /* Create setter procedure */
401 prop->setter = stree_proc_new();
402 prop->setter->body = parse_block(parse);
403 prop->setter->outer_symbol = symbol;
404
405 lmatch(parse, lc_end);
406 break;
407 default:
408 lunexpected_error(parse);
409 }
410 }
411
412 lmatch(parse, lc_end);
413
414 return prop;
415}
416
417/** Parse symbol attribute. */
418static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse)
419{
420 stree_symbol_attr_t *attr;
421
422 if (lcur_lc(parse) != lc_builtin) {
423 printf("Error: Unexpected attribute '");
424 lem_print(lcur(parse));
425 printf("'.\n");
426 exit(1);
427 }
428
429 lskip(parse);
430
431 attr = stree_symbol_attr_new(sac_builtin);
432 return attr;
433}
434
435/** Parse formal function argument. */
436static stree_proc_arg_t *parse_proc_arg(parse_t *parse)
437{
438 stree_proc_arg_t *arg;
439 stree_arg_attr_t *attr;
440
441 arg = stree_proc_arg_new();
442 arg->name = parse_ident(parse);
443 lmatch(parse, lc_colon);
444 arg->type = parse_texpr(parse);
445
446 list_init(&arg->attr);
447
448 /* Parse attributes. */
449 while (lcur_lc(parse) == lc_comma) {
450 lskip(parse);
451 attr = parse_arg_attr(parse);
452 list_append(&arg->attr, attr);
453 }
454
455#ifdef DEBUG_PARSE_TRACE
456 printf("Parsed arg attr, type=%p.\n", arg->type);
457#endif
458 return arg;
459}
460
461/** Parse argument attribute. */
462static stree_arg_attr_t *parse_arg_attr(parse_t *parse)
463{
464 stree_arg_attr_t *attr;
465
466 if (lcur_lc(parse) != lc_packed) {
467 printf("Error: Unexpected attribute '");
468 lem_print(lcur(parse));
469 printf("'.\n");
470 exit(1);
471 }
472
473 lskip(parse);
474
475 attr = stree_arg_attr_new(aac_packed);
476 return attr;
477}
478
479/** Parse statement block. */
480static stree_block_t *parse_block(parse_t *parse)
481{
482 stree_block_t *block;
483 stree_stat_t *stat;
484
485 block = stree_block_new();
486 list_init(&block->stats);
487
488 while (terminates_block(lcur_lc(parse)) != b_true) {
489 stat = parse_stat(parse);
490 list_append(&block->stats, stat);
491 }
492
493 return block;
494}
495
496/** Parse statement. */
497stree_stat_t *parse_stat(parse_t *parse)
498{
499 stree_stat_t *stat;
500
501 stree_vdecl_t *vdecl_s;
502 stree_if_t *if_s;
503 stree_while_t *while_s;
504 stree_for_t *for_s;
505 stree_raise_t *raise_s;
506 stree_return_t *return_s;
507 stree_wef_t *wef_s;
508 stree_exps_t *exp_s;
509
510 switch (lcur_lc(parse)) {
511 case lc_var:
512 vdecl_s = parse_vdecl(parse);
513 stat = stree_stat_new(st_vdecl);
514 stat->u.vdecl_s = vdecl_s;
515 break;
516 case lc_if:
517 if_s = parse_if(parse);
518 stat = stree_stat_new(st_if);
519 stat->u.if_s = if_s;
520 break;
521 case lc_while:
522 while_s = parse_while(parse);
523 stat = stree_stat_new(st_while);
524 stat->u.while_s = while_s;
525 break;
526 case lc_for:
527 for_s = parse_for(parse);
528 stat = stree_stat_new(st_for);
529 stat->u.for_s = for_s;
530 break;
531 case lc_raise:
532 raise_s = parse_raise(parse);
533 stat = stree_stat_new(st_raise);
534 stat->u.raise_s = raise_s;
535 break;
536 case lc_return:
537 return_s = parse_return(parse);
538 stat = stree_stat_new(st_return);
539 stat->u.return_s = return_s;
540 break;
541 case lc_do:
542 case lc_with:
543 wef_s = parse_wef(parse);
544 stat = stree_stat_new(st_wef);
545 stat->u.wef_s = wef_s;
546 break;
547 default:
548 exp_s = parse_exps(parse);
549 stat = stree_stat_new(st_exps);
550 stat->u.exp_s = exp_s;
551 break;
552 }
553
554#ifdef DEBUG_PARSE_TRACE
555 printf("Parsed statement %p\n", stat);
556#endif
557 return stat;
558}
559
560/** Parse variable declaration statement. */
561static stree_vdecl_t *parse_vdecl(parse_t *parse)
562{
563 stree_vdecl_t *vdecl;
564
565 vdecl = stree_vdecl_new();
566
567 lmatch(parse, lc_var);
568 vdecl->name = parse_ident(parse);
569 lmatch(parse, lc_colon);
570 vdecl->type = parse_texpr(parse);
571
572 if (lcur_lc(parse) == lc_assign) {
573 lskip(parse);
574 (void) parse_expr(parse);
575 }
576
577 lmatch(parse, lc_scolon);
578
579#ifdef DEBUG_PARSE_TRACE
580 printf("Parsed vdecl for '%s'\n", strtab_get_str(vdecl->name->sid));
581 printf("vdecl = %p, vdecl->name = %p, sid=%d\n",
582 vdecl, vdecl->name, vdecl->name->sid);
583#endif
584 return vdecl;
585}
586
587/** Parse @c if statement, */
588static stree_if_t *parse_if(parse_t *parse)
589{
590 stree_if_t *if_s;
591
592 if_s = stree_if_new();
593
594 lmatch(parse, lc_if);
595 if_s->cond = parse_expr(parse);
596 lmatch(parse, lc_then);
597 if_s->if_block = parse_block(parse);
598
599 if (lcur_lc(parse) == lc_else) {
600 lskip(parse);
601 if_s->else_block = parse_block(parse);
602 } else {
603 if_s->else_block = NULL;
604 }
605
606 lmatch(parse, lc_end);
607 return if_s;
608}
609
610/** Parse @c while statement. */
611static stree_while_t *parse_while(parse_t *parse)
612{
613 stree_while_t *while_s;
614
615 while_s = stree_while_new();
616
617 lmatch(parse, lc_while);
618 while_s->cond = parse_expr(parse);
619 lmatch(parse, lc_do);
620 while_s->body = parse_block(parse);
621 lmatch(parse, lc_end);
622
623 return while_s;
624}
625
626/** Parse @c for statement. */
627static stree_for_t *parse_for(parse_t *parse)
628{
629 stree_for_t *for_s;
630
631 for_s = stree_for_new();
632
633 lmatch(parse, lc_for);
634 lmatch(parse, lc_ident);
635 lmatch(parse, lc_colon);
636 (void) parse_texpr(parse);
637 lmatch(parse, lc_in);
638 (void) parse_expr(parse);
639 lmatch(parse, lc_do);
640 for_s->body = parse_block(parse);
641 lmatch(parse, lc_end);
642
643 return for_s;
644}
645
646/** Parse @c raise statement. */
647static stree_raise_t *parse_raise(parse_t *parse)
648{
649 stree_raise_t *raise_s;
650
651 raise_s = stree_raise_new();
652 lmatch(parse, lc_raise);
653 raise_s->expr = parse_expr(parse);
654 lmatch(parse, lc_scolon);
655
656 return raise_s;
657}
658
659/** Parse @c return statement. */
660static stree_return_t *parse_return(parse_t *parse)
661{
662 stree_return_t *return_s;
663
664 return_s = stree_return_new();
665
666 lmatch(parse, lc_return);
667 return_s->expr = parse_expr(parse);
668 lmatch(parse, lc_scolon);
669
670 return return_s;
671}
672
673/* Parse @c with-except-finally statement. */
674static stree_wef_t *parse_wef(parse_t *parse)
675{
676 stree_wef_t *wef_s;
677 stree_except_t *except_c;
678
679 wef_s = stree_wef_new();
680 list_init(&wef_s->except_clauses);
681
682 if (lcur_lc(parse) == lc_with) {
683 lmatch(parse, lc_with);
684 lmatch(parse, lc_ident);
685 lmatch(parse, lc_colon);
686 (void) parse_texpr(parse);
687 lmatch(parse, lc_assign);
688 (void) parse_expr(parse);
689 }
690
691 lmatch(parse, lc_do);
692 wef_s->with_block = parse_block(parse);
693
694 while (lcur_lc(parse) == lc_except) {
695 except_c = parse_except(parse);
696 list_append(&wef_s->except_clauses, except_c);
697 }
698
699 if (lcur_lc(parse) == lc_finally) {
700 lmatch(parse, lc_finally);
701 lmatch(parse, lc_do);
702 wef_s->finally_block = parse_block(parse);
703 } else {
704 wef_s->finally_block = NULL;
705 }
706
707 lmatch(parse, lc_end);
708
709 return wef_s;
710}
711
712/* Parse expression statement. */
713static stree_exps_t *parse_exps(parse_t *parse)
714{
715 stree_expr_t *expr;
716 stree_exps_t *exps;
717
718 expr = parse_expr(parse);
719 lmatch(parse, lc_scolon);
720
721 exps = stree_exps_new();
722 exps->expr = expr;
723
724 return exps;
725}
726
727/* Parse @c except clause. */
728static stree_except_t *parse_except(parse_t *parse)
729{
730 stree_except_t *except_c;
731
732 except_c = stree_except_new();
733
734 lmatch(parse, lc_except);
735 except_c->evar = parse_ident(parse);
736 lmatch(parse, lc_colon);
737 except_c->etype = parse_texpr(parse);
738 lmatch(parse, lc_do);
739
740 except_c->block = parse_block(parse);
741
742 return except_c;
743}
744
745/** Parse identifier. */
746stree_ident_t *parse_ident(parse_t *parse)
747{
748 stree_ident_t *ident;
749
750 lcheck(parse, lc_ident);
751 ident = stree_ident_new();
752 ident->sid = lcur(parse)->u.ident.sid;
753 lskip(parse);
754
755 return ident;
756}
757
758/** Return current lem. */
759lem_t *lcur(parse_t *parse)
760{
761 return lex_get_current(parse->lex);
762}
763
764/** Retturn current lem lclass. */
765lclass_t lcur_lc(parse_t *parse)
766{
767 lem_t *lem;
768
769 lem = lcur(parse);
770 return lem->lclass;
771}
772
773/** Skip to next lem. */
774void lskip(parse_t *parse)
775{
776 lex_next(parse->lex);
777}
778
779/** Verify that lclass of current lem is @a lc. */
780void lcheck(parse_t *parse, lclass_t lc)
781{
782 if (lcur(parse)->lclass != lc) {
783 lem_print_coords(lcur(parse));
784 printf(" Error: expected '"); lclass_print(lc);
785 printf("', got '"); lem_print(lcur(parse));
786 printf("'.\n");
787 exit(1);
788 }
789}
790
791/** Verify that lclass of current lem is @a lc and go to next lem. */
792void lmatch(parse_t *parse, lclass_t lc)
793{
794 lcheck(parse, lc);
795 lskip(parse);
796}
797
798/** Display generic parsing error. */
799void lunexpected_error(parse_t *parse)
800{
801 lem_print_coords(lcur(parse));
802 printf(" Error: unexpected token '");
803 lem_print(lcur(parse));
804 printf("'.\n");
805 exit(1);
806}
807
808/** Basically tells us whether @a lclass is in next(block). */
809bool_t terminates_block(lclass_t lclass)
810{
811 switch (lclass) {
812 case lc_else:
813 case lc_end:
814 case lc_except:
815 case lc_finally:
816 return b_true;
817 default:
818 return b_false;
819 }
820}
Note: See TracBrowser for help on using the repository browser.