]> git.saurik.com Git - bison.git/blob - src/reader.c
* src/files.c, src/files.h (guard_obstack): Remove.
[bison.git] / src / reader.c
1 /* Input parser for bison
2 Copyright 1984, 1986, 1989, 1992, 1998, 2000, 2001
3 Free Software Foundation, Inc.
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
7 Bison is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 Bison is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bison; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22
23 #include "system.h"
24 #include "quotearg.h"
25 #include "quote.h"
26 #include "getargs.h"
27 #include "files.h"
28 #include "symtab.h"
29 #include "options.h"
30 #include "lex.h"
31 #include "gram.h"
32 #include "complain.h"
33 #include "output.h"
34 #include "reader.h"
35 #include "conflicts.h"
36 #include "muscle_tab.h"
37
38 typedef struct symbol_list
39 {
40 struct symbol_list *next;
41 bucket *sym;
42 int line;
43
44 /* The action is attached to the LHS of a rule. */
45 const char *action;
46 int action_line;
47
48 /* The guard is attached to the LHS of a rule. */
49 const char *guard;
50 int guard_line;
51 bucket *ruleprec;
52 } symbol_list;
53
54 int lineno;
55 char **tags;
56 short *user_toknums;
57 static symbol_list *grammar;
58 static int start_flag;
59 static bucket *startval;
60
61 /* Nonzero if components of semantic values are used, implying
62 they must be unions. */
63 static int value_components_used;
64
65 /* Nonzero if %union has been seen. */
66 static int typed;
67
68 /* Incremented for each %left, %right or %nonassoc seen */
69 static int lastprec;
70
71 static bucket *errtoken;
72 static bucket *undeftoken;
73
74
75 static symbol_list *
76 symbol_list_new (bucket *sym)
77 {
78 symbol_list *res = XMALLOC (symbol_list, 1);
79 res->next = NULL;
80 res->sym = sym;
81 res->line = lineno;
82 res->action = NULL;
83 res->action_line = 0;
84 res->guard = NULL;
85 res->guard_line = 0;
86 res->ruleprec = NULL;
87 return res;
88 }
89
90 \f
91
92 /*===================\
93 | Low level lexing. |
94 \===================*/
95
96 static void
97 skip_to_char (int target)
98 {
99 int c;
100 if (target == '\n')
101 complain (_(" Skipping to next \\n"));
102 else
103 complain (_(" Skipping to next %c"), target);
104
105 do
106 c = skip_white_space ();
107 while (c != target && c != EOF);
108 if (c != EOF)
109 ungetc (c, finput);
110 }
111
112
113 /*---------------------------------------------------------.
114 | Read a signed integer from STREAM and return its value. |
115 `---------------------------------------------------------*/
116
117 static inline int
118 read_signed_integer (FILE *stream)
119 {
120 int c = getc (stream);
121 int sign = 1;
122 int n = 0;
123
124 if (c == '-')
125 {
126 c = getc (stream);
127 sign = -1;
128 }
129
130 while (isdigit (c))
131 {
132 n = 10 * n + (c - '0');
133 c = getc (stream);
134 }
135
136 ungetc (c, stream);
137
138 return sign * n;
139 }
140 \f
141 /*--------------------------------------------------------------.
142 | Get the data type (alternative in the union) of the value for |
143 | symbol N in rule RULE. |
144 `--------------------------------------------------------------*/
145
146 static char *
147 get_type_name (int n, symbol_list *rule)
148 {
149 int i;
150 symbol_list *rp;
151
152 if (n < 0)
153 {
154 complain (_("invalid $ value"));
155 return NULL;
156 }
157
158 rp = rule;
159 i = 0;
160
161 while (i < n)
162 {
163 rp = rp->next;
164 if (rp == NULL || rp->sym == NULL)
165 {
166 complain (_("invalid $ value"));
167 return NULL;
168 }
169 i++;
170 }
171
172 return rp->sym->type_name;
173 }
174 \f
175 /*------------------------------------------------------------.
176 | Dump the string from FIN to OOUT if non null. MATCH is the |
177 | delimiter of the string (either ' or "). |
178 `------------------------------------------------------------*/
179
180 static inline void
181 copy_string2 (FILE *fin, struct obstack *oout, int match, int store)
182 {
183 int c;
184
185 if (store)
186 obstack_1grow (oout, match);
187
188 c = getc (fin);
189
190 while (c != match)
191 {
192 if (c == EOF)
193 fatal (_("unterminated string at end of file"));
194 if (c == '\n')
195 {
196 complain (_("unterminated string"));
197 ungetc (c, fin);
198 c = match; /* invent terminator */
199 continue;
200 }
201
202 obstack_1grow (oout, c);
203
204 if (c == '\\')
205 {
206 c = getc (fin);
207 if (c == EOF)
208 fatal (_("unterminated string at end of file"));
209 obstack_1grow (oout, c);
210
211 if (c == '\n')
212 lineno++;
213 }
214
215 c = getc (fin);
216 }
217
218 if (store)
219 obstack_1grow (oout, c);
220 }
221
222 /* FIXME. */
223
224 static inline void
225 copy_string (FILE *fin, struct obstack *oout, int match)
226 {
227 copy_string2 (fin, oout, match, 1);
228 }
229
230 /* FIXME. */
231
232 static inline void
233 copy_identifier (FILE *fin, struct obstack *oout)
234 {
235 int c;
236
237 while (isalnum (c = getc (fin)) || c == '_')
238 obstack_1grow (oout, c);
239
240 ungetc (c, fin);
241 }
242
243
244 /*------------------------------------------------------------------.
245 | Dump the wannabee comment from IN to OOUT. In fact we just saw a |
246 | `/', which might or might not be a comment. In any case, copy |
247 | what we saw. |
248 `------------------------------------------------------------------*/
249
250 static inline void
251 copy_comment (FILE *fin, struct obstack *oout)
252 {
253 int cplus_comment;
254 int ended;
255 int c;
256
257 /* We read a `/', output it. */
258 obstack_1grow (oout, '/');
259
260 switch ((c = getc (fin)))
261 {
262 case '/':
263 cplus_comment = 1;
264 break;
265 case '*':
266 cplus_comment = 0;
267 break;
268 default:
269 ungetc (c, fin);
270 return;
271 }
272
273 obstack_1grow (oout, c);
274 c = getc (fin);
275
276 ended = 0;
277 while (!ended)
278 {
279 if (!cplus_comment && c == '*')
280 {
281 while (c == '*')
282 {
283 obstack_1grow (oout, c);
284 c = getc (fin);
285 }
286
287 if (c == '/')
288 {
289 obstack_1grow (oout, c);
290 ended = 1;
291 }
292 }
293 else if (c == '\n')
294 {
295 lineno++;
296 obstack_1grow (oout, c);
297 if (cplus_comment)
298 ended = 1;
299 else
300 c = getc (fin);
301 }
302 else if (c == EOF)
303 fatal (_("unterminated comment"));
304 else
305 {
306 obstack_1grow (oout, c);
307 c = getc (fin);
308 }
309 }
310 }
311
312
313 /*-----------------------------------------------------------------.
314 | FIN is pointing to a location (i.e., a `@'). Output to OOUT a |
315 | reference to this location. STACK_OFFSET is the number of values |
316 | in the current rule so far, which says where to find `$0' with |
317 | respect to the top of the stack. |
318 `-----------------------------------------------------------------*/
319
320 static inline void
321 copy_at (FILE *fin, struct obstack *oout, int stack_offset)
322 {
323 int c;
324
325 c = getc (fin);
326 if (c == '$')
327 {
328 obstack_sgrow (oout, "yyloc");
329 locations_flag = 1;
330 }
331 else if (isdigit (c) || c == '-')
332 {
333 int n;
334
335 ungetc (c, fin);
336 n = read_signed_integer (fin);
337
338 obstack_fgrow1 (oout, "yylsp[%d]", n - stack_offset);
339 locations_flag = 1;
340 }
341 else
342 {
343 char buf[] = "@c";
344 buf[1] = c;
345 complain (_("%s is invalid"), quote (buf));
346 }
347 }
348
349
350 /*-------------------------------------------------------------------.
351 | FIN is pointing to a wannabee semantic value (i.e., a `$'). |
352 | |
353 | Possible inputs: $[<TYPENAME>]($|integer) |
354 | |
355 | Output to OOUT a reference to this semantic value. STACK_OFFSET is |
356 | the number of values in the current rule so far, which says where |
357 | to find `$0' with respect to the top of the stack. |
358 `-------------------------------------------------------------------*/
359
360 static inline void
361 copy_dollar (FILE *fin, struct obstack *oout,
362 symbol_list *rule, int stack_offset)
363 {
364 int c = getc (fin);
365 const char *type_name = NULL;
366
367 /* Get the type name if explicit. */
368 if (c == '<')
369 {
370 read_type_name (fin);
371 type_name = token_buffer;
372 value_components_used = 1;
373 c = getc (fin);
374 }
375
376 if (c == '$')
377 {
378 obstack_sgrow (oout, "yyval");
379
380 if (!type_name)
381 type_name = get_type_name (0, rule);
382 if (type_name)
383 obstack_fgrow1 (oout, ".%s", type_name);
384 if (!type_name && typed)
385 complain (_("$$ of `%s' has no declared type"),
386 rule->sym->tag);
387 }
388 else if (isdigit (c) || c == '-')
389 {
390 int n;
391 ungetc (c, fin);
392 n = read_signed_integer (fin);
393
394 if (!type_name && n > 0)
395 type_name = get_type_name (n, rule);
396
397 obstack_fgrow1 (oout, "yyvsp[%d]", n - stack_offset);
398
399 if (type_name)
400 obstack_fgrow1 (oout, ".%s", type_name);
401 if (!type_name && typed)
402 complain (_("$%d of `%s' has no declared type"),
403 n, rule->sym->tag);
404 }
405 else
406 {
407 char buf[] = "$c";
408 buf[1] = c;
409 complain (_("%s is invalid"), quote (buf));
410 }
411 }
412 \f
413 /*-------------------------------------------------------------------.
414 | Copy the contents of a `%{ ... %}' into the definitions file. The |
415 | `%{' has already been read. Return after reading the `%}'. |
416 `-------------------------------------------------------------------*/
417
418 static void
419 copy_definition (void)
420 {
421 int c;
422 /* -1 while reading a character if prev char was %. */
423 int after_percent;
424
425 if (!no_lines_flag)
426 {
427 obstack_fgrow2 (&attrs_obstack, muscle_find ("linef"),
428 lineno, quotearg_style (c_quoting_style,
429 muscle_find("filename")));
430 }
431
432 after_percent = 0;
433
434 c = getc (finput);
435
436 for (;;)
437 {
438 switch (c)
439 {
440 case '\n':
441 obstack_1grow (&attrs_obstack, c);
442 lineno++;
443 break;
444
445 case '%':
446 after_percent = -1;
447 break;
448
449 case '\'':
450 case '"':
451 copy_string (finput, &attrs_obstack, c);
452 break;
453
454 case '/':
455 copy_comment (finput, &attrs_obstack);
456 break;
457
458 case EOF:
459 fatal ("%s", _("unterminated `%{' definition"));
460
461 default:
462 obstack_1grow (&attrs_obstack, c);
463 }
464
465 c = getc (finput);
466
467 if (after_percent)
468 {
469 if (c == '}')
470 return;
471 obstack_1grow (&attrs_obstack, '%');
472 }
473 after_percent = 0;
474 }
475 }
476
477
478 /*-------------------------------------------------------------------.
479 | Parse what comes after %token or %nterm. For %token, WHAT_IS is |
480 | token_sym and WHAT_IS_NOT is nterm_sym. For %nterm, the arguments |
481 | are reversed. |
482 `-------------------------------------------------------------------*/
483
484 static void
485 parse_token_decl (symbol_class what_is, symbol_class what_is_not)
486 {
487 token_t token = tok_undef;
488 char *typename = NULL;
489
490 /* The symbol being defined. */
491 struct bucket *symbol = NULL;
492
493 /* After `%token' and `%nterm', any number of symbols maybe be
494 defined. */
495 for (;;)
496 {
497 int tmp_char = ungetc (skip_white_space (), finput);
498
499 /* `%' (for instance from `%token', or from `%%' etc.) is the
500 only valid means to end this declaration. */
501 if (tmp_char == '%')
502 return;
503 if (tmp_char == EOF)
504 fatal (_("Premature EOF after %s"), token_buffer);
505
506 token = lex ();
507 if (token == tok_comma)
508 {
509 symbol = NULL;
510 continue;
511 }
512 if (token == tok_typename)
513 {
514 typename = xstrdup (token_buffer);
515 value_components_used = 1;
516 symbol = NULL;
517 }
518 else if (token == tok_identifier && *symval->tag == '\"' && symbol)
519 {
520 if (symval->alias)
521 warn (_("symbol `%s' used more than once as a literal string"),
522 symval->tag);
523 else if (symbol->alias)
524 warn (_("symbol `%s' given more than one literal string"),
525 symbol->tag);
526 else
527 {
528 symval->class = token_sym;
529 symval->type_name = typename;
530 symval->user_token_number = symbol->user_token_number;
531 symbol->user_token_number = SALIAS;
532 symval->alias = symbol;
533 symbol->alias = symval;
534 /* symbol and symval combined are only one symbol */
535 nsyms--;
536 }
537 symbol = NULL;
538 }
539 else if (token == tok_identifier)
540 {
541 int oldclass = symval->class;
542 symbol = symval;
543
544 if (symbol->class == what_is_not)
545 complain (_("symbol %s redefined"), symbol->tag);
546 symbol->class = what_is;
547 if (what_is == nterm_sym && oldclass != nterm_sym)
548 symbol->value = nvars++;
549
550 if (typename)
551 {
552 if (symbol->type_name == NULL)
553 symbol->type_name = typename;
554 else if (strcmp (typename, symbol->type_name) != 0)
555 complain (_("type redeclaration for %s"), symbol->tag);
556 }
557 }
558 else if (symbol && token == tok_number)
559 {
560 symbol->user_token_number = numval;
561 }
562 else
563 {
564 complain (_("`%s' is invalid in %s"),
565 token_buffer,
566 (what_is == token_sym) ? "%token" : "%nterm");
567 skip_to_char ('%');
568 }
569 }
570
571 }
572
573
574 /*------------------------------.
575 | Parse what comes after %start |
576 `------------------------------*/
577
578 static void
579 parse_start_decl (void)
580 {
581 if (start_flag)
582 complain (_("multiple %s declarations"), "%start");
583 if (lex () != tok_identifier)
584 complain (_("invalid %s declaration"), "%start");
585 else
586 {
587 start_flag = 1;
588 startval = symval;
589 }
590 }
591
592 /*-----------------------------------------------------------.
593 | read in a %type declaration and record its information for |
594 | get_type_name to access |
595 `-----------------------------------------------------------*/
596
597 static void
598 parse_type_decl (void)
599 {
600 char *name;
601
602 if (lex () != tok_typename)
603 {
604 complain ("%s", _("%type declaration has no <typename>"));
605 skip_to_char ('%');
606 return;
607 }
608
609 name = xstrdup (token_buffer);
610
611 for (;;)
612 {
613 token_t t;
614 int tmp_char = ungetc (skip_white_space (), finput);
615
616 if (tmp_char == '%')
617 return;
618 if (tmp_char == EOF)
619 fatal (_("Premature EOF after %s"), token_buffer);
620
621 t = lex ();
622
623 switch (t)
624 {
625
626 case tok_comma:
627 case tok_semicolon:
628 break;
629
630 case tok_identifier:
631 if (symval->type_name == NULL)
632 symval->type_name = name;
633 else if (strcmp (name, symval->type_name) != 0)
634 complain (_("type redeclaration for %s"), symval->tag);
635
636 break;
637
638 default:
639 complain (_("invalid %%type declaration due to item: %s"),
640 token_buffer);
641 skip_to_char ('%');
642 }
643 }
644 }
645
646
647
648 /*----------------------------------------------------------------.
649 | Read in a %left, %right or %nonassoc declaration and record its |
650 | information. |
651 `----------------------------------------------------------------*/
652
653 static void
654 parse_assoc_decl (associativity assoc)
655 {
656 char *name = NULL;
657 int prev = 0;
658
659 lastprec++; /* Assign a new precedence level, never 0. */
660
661 for (;;)
662 {
663 token_t t;
664 int tmp_char = ungetc (skip_white_space (), finput);
665
666 if (tmp_char == '%')
667 return;
668 if (tmp_char == EOF)
669 fatal (_("Premature EOF after %s"), token_buffer);
670
671 t = lex ();
672
673 switch (t)
674 {
675 case tok_typename:
676 name = xstrdup (token_buffer);
677 break;
678
679 case tok_comma:
680 break;
681
682 case tok_identifier:
683 if (symval->prec != 0)
684 complain (_("redefining precedence of %s"), symval->tag);
685 symval->prec = lastprec;
686 symval->assoc = assoc;
687 if (symval->class == nterm_sym)
688 complain (_("symbol %s redefined"), symval->tag);
689 symval->class = token_sym;
690 if (name)
691 { /* record the type, if one is specified */
692 if (symval->type_name == NULL)
693 symval->type_name = name;
694 else if (strcmp (name, symval->type_name) != 0)
695 complain (_("type redeclaration for %s"), symval->tag);
696 }
697 break;
698
699 case tok_number:
700 if (prev == tok_identifier)
701 {
702 symval->user_token_number = numval;
703 }
704 else
705 {
706 complain (_
707 ("invalid text (%s) - number should be after identifier"),
708 token_buffer);
709 skip_to_char ('%');
710 }
711 break;
712
713 case tok_semicolon:
714 return;
715
716 default:
717 complain (_("unexpected item: %s"), token_buffer);
718 skip_to_char ('%');
719 }
720
721 prev = t;
722 }
723 }
724
725
726
727 /*--------------------------------------------------------------.
728 | Copy the union declaration into the stype muscle |
729 | (and fdefines), where it is made into the definition of |
730 | YYSTYPE, the type of elements of the parser value stack. |
731 `--------------------------------------------------------------*/
732
733 static void
734 parse_union_decl (void)
735 {
736 int c;
737 int count = 0;
738 bool done = FALSE;
739 struct obstack union_obstack;
740 if (typed)
741 complain (_("multiple %s declarations"), "%union");
742
743 typed = 1;
744
745 obstack_init (&union_obstack);
746 obstack_sgrow (&union_obstack, "union");
747
748 while (!done)
749 {
750 c = xgetc (finput);
751
752 /* If C contains '/', it is output by copy_comment (). */
753 if (c != '/')
754 obstack_1grow (&union_obstack, c);
755
756 switch (c)
757 {
758 case '\n':
759 lineno++;
760 break;
761
762 case '/':
763 copy_comment (finput, &union_obstack);
764 break;
765
766 case '{':
767 count++;
768 break;
769
770 case '}':
771 /* FIXME: Errr. How could this happen???. --akim */
772 if (count == 0)
773 complain (_("unmatched %s"), "`}'");
774 count--;
775 if (!count)
776 done = TRUE;
777 break;
778 }
779 }
780
781 /* JF don't choke on trailing semi */
782 c = skip_white_space ();
783 if (c != ';')
784 ungetc (c, finput);
785 obstack_1grow (&union_obstack, 0);
786 muscle_insert ("stype", obstack_finish (&union_obstack));
787 }
788
789
790 /*-------------------------------------------------------.
791 | Parse the declaration %expect N which says to expect N |
792 | shift-reduce conflicts. |
793 `-------------------------------------------------------*/
794
795 static void
796 parse_expect_decl (void)
797 {
798 int c = skip_white_space ();
799 ungetc (c, finput);
800
801 if (!isdigit (c))
802 complain (_("argument of %%expect is not an integer"));
803 else
804 expected_conflicts = read_signed_integer (finput);
805 }
806
807
808 /*-------------------------------------------------------------------.
809 | Parse what comes after %thong. the full syntax is |
810 | |
811 | %thong <type> token number literal |
812 | |
813 | the <type> or number may be omitted. The number specifies the |
814 | user_token_number. |
815 | |
816 | Two symbols are entered in the table, one for the token symbol and |
817 | one for the literal. Both are given the <type>, if any, from the |
818 | declaration. The ->user_token_number of the first is SALIAS and |
819 | the ->user_token_number of the second is set to the number, if |
820 | any, from the declaration. The two symbols are linked via |
821 | pointers in their ->alias fields. |
822 | |
823 | During OUTPUT_DEFINES_TABLE, the symbol is reported thereafter, |
824 | only the literal string is retained it is the literal string that |
825 | is output to yytname |
826 `-------------------------------------------------------------------*/
827
828 static void
829 parse_thong_decl (void)
830 {
831 token_t token;
832 struct bucket *symbol;
833 char *typename = 0;
834 int usrtoknum = SUNDEF;
835
836 token = lex (); /* fetch typename or first token */
837 if (token == tok_typename)
838 {
839 typename = xstrdup (token_buffer);
840 value_components_used = 1;
841 token = lex (); /* fetch first token */
842 }
843
844 /* process first token */
845
846 if (token != tok_identifier)
847 {
848 complain (_("unrecognized item %s, expected an identifier"),
849 token_buffer);
850 skip_to_char ('%');
851 return;
852 }
853 symval->class = token_sym;
854 symval->type_name = typename;
855 symval->user_token_number = SALIAS;
856 symbol = symval;
857
858 token = lex (); /* get number or literal string */
859
860 if (token == tok_number)
861 {
862 usrtoknum = numval;
863 token = lex (); /* okay, did number, now get literal */
864 }
865
866 /* process literal string token */
867
868 if (token != tok_identifier || *symval->tag != '\"')
869 {
870 complain (_("expected string constant instead of %s"), token_buffer);
871 skip_to_char ('%');
872 return;
873 }
874 symval->class = token_sym;
875 symval->type_name = typename;
876 symval->user_token_number = usrtoknum;
877
878 symval->alias = symbol;
879 symbol->alias = symval;
880
881 /* symbol and symval combined are only one symbol. */
882 nsyms--;
883 }
884
885 static void
886 parse_muscle_decl (void)
887 {
888 int ch = ungetc (skip_white_space (), finput);
889 char* muscle_key;
890 char* muscle_value;
891
892 /* Read key. */
893 if (!isalpha (ch) && ch != '_')
894 {
895 complain (_("invalid %s declaration"), "%define");
896 skip_to_char ('%');
897 return;
898 }
899 copy_identifier (finput, &muscle_obstack);
900 obstack_1grow (&muscle_obstack, 0);
901 muscle_key = obstack_finish (&muscle_obstack);
902
903 /* Read value. */
904 ch = skip_white_space ();
905 if (ch != '"')
906 {
907 ungetc (ch, finput);
908 if (ch != EOF)
909 {
910 complain (_("invalid %s declaration"), "%define");
911 skip_to_char ('%');
912 return;
913 }
914 else
915 fatal (_("Premature EOF after %s"), "\"");
916 }
917 copy_string2 (finput, &muscle_obstack, '"', 0);
918 obstack_1grow (&muscle_obstack, 0);
919 muscle_value = obstack_finish (&muscle_obstack);
920
921 /* Store the (key, value) pair in the environment. */
922 muscle_insert (muscle_key, muscle_value);
923 }
924
925
926
927 /*---------------------------------.
928 | Parse a double quoted parameter. |
929 `---------------------------------*/
930
931 static const char *
932 parse_dquoted_param (const char *from)
933 {
934 struct obstack param_obstack;
935 const char *param = NULL;
936 int c;
937
938 obstack_init (&param_obstack);
939 c = skip_white_space ();
940
941 if (c != '"')
942 {
943 complain (_("invalid %s declaration"), from);
944 ungetc (c, finput);
945 skip_to_char ('%');
946 return NULL;
947 }
948
949 while ((c = literalchar ()) != '"')
950 obstack_1grow (&param_obstack, c);
951
952 obstack_1grow (&param_obstack, '\0');
953 param = obstack_finish (&param_obstack);
954
955 if (c != '"' || strlen (param) == 0)
956 {
957 complain (_("invalid %s declaration"), from);
958 if (c != '"')
959 ungetc (c, finput);
960 skip_to_char ('%');
961 return NULL;
962 }
963
964 return param;
965 }
966
967 /*----------------------------------.
968 | Parse what comes after %skeleton. |
969 `----------------------------------*/
970
971 static void
972 parse_skel_decl (void)
973 {
974 skeleton = parse_dquoted_param ("%skeleton");
975 }
976
977 /*----------------------------------------------------------------.
978 | Read from finput until `%%' is seen. Discard the `%%'. Handle |
979 | any `%' declarations, and copy the contents of any `%{ ... %}' |
980 | groups to ATTRS_OBSTACK. |
981 `----------------------------------------------------------------*/
982
983 static void
984 read_declarations (void)
985 {
986 for (;;)
987 {
988 int c = skip_white_space ();
989
990 if (c == '%')
991 {
992 token_t tok = parse_percent_token ();
993
994 switch (tok)
995 {
996 case tok_two_percents:
997 return;
998
999 case tok_percent_left_curly:
1000 copy_definition ();
1001 break;
1002
1003 case tok_token:
1004 parse_token_decl (token_sym, nterm_sym);
1005 break;
1006
1007 case tok_nterm:
1008 parse_token_decl (nterm_sym, token_sym);
1009 break;
1010
1011 case tok_type:
1012 parse_type_decl ();
1013 break;
1014
1015 case tok_start:
1016 parse_start_decl ();
1017 break;
1018
1019 case tok_union:
1020 parse_union_decl ();
1021 break;
1022
1023 case tok_expect:
1024 parse_expect_decl ();
1025 break;
1026
1027 case tok_thong:
1028 parse_thong_decl ();
1029 break;
1030
1031 case tok_left:
1032 parse_assoc_decl (left_assoc);
1033 break;
1034
1035 case tok_right:
1036 parse_assoc_decl (right_assoc);
1037 break;
1038
1039 case tok_nonassoc:
1040 parse_assoc_decl (non_assoc);
1041 break;
1042
1043 case tok_define:
1044 parse_muscle_decl ();
1045 break;
1046
1047 case tok_skel:
1048 parse_skel_decl ();
1049 break;
1050
1051 case tok_noop:
1052 break;
1053
1054 case tok_stropt:
1055 case tok_intopt:
1056 case tok_obsolete:
1057 abort ();
1058 break;
1059
1060 case tok_illegal:
1061 default:
1062 complain (_("unrecognized: %s"), token_buffer);
1063 skip_to_char ('%');
1064 }
1065 }
1066 else if (c == EOF)
1067 fatal (_("no input grammar"));
1068 else
1069 {
1070 char buf[] = "c";
1071 buf[0] = c;
1072 complain (_("unknown character: %s"), quote (buf));
1073 skip_to_char ('%');
1074 }
1075 }
1076 }
1077 \f
1078 /*-------------------------------------------------------------------.
1079 | Assuming that a `{' has just been seen, copy everything up to the |
1080 | matching `}' into the actions file. STACK_OFFSET is the number of |
1081 | values in the current rule so far, which says where to find `$0' |
1082 | with respect to the top of the stack. |
1083 | |
1084 | This routine is used both for actions and guards. Only the |
1085 | actions_obstack is used, but this is fine, since we use only |
1086 | pointers to relevant portions inside this obstack. |
1087 `-------------------------------------------------------------------*/
1088
1089 static void
1090 parse_braces (symbol_list *rule, int stack_offset)
1091 {
1092 int c;
1093 int count;
1094
1095 /* offset is always 0 if parser has already popped the stack pointer */
1096 if (semantic_parser)
1097 stack_offset = 0;
1098
1099 count = 1;
1100 while (count > 0)
1101 {
1102 while ((c = getc (finput)) != '}')
1103 switch (c)
1104 {
1105 case '\n':
1106 obstack_1grow (&action_obstack, c);
1107 lineno++;
1108 break;
1109
1110 case '{':
1111 obstack_1grow (&action_obstack, c);
1112 count++;
1113 break;
1114
1115 case '\'':
1116 case '"':
1117 copy_string (finput, &action_obstack, c);
1118 break;
1119
1120 case '/':
1121 copy_comment (finput, &action_obstack);
1122 break;
1123
1124 case '$':
1125 copy_dollar (finput, &action_obstack,
1126 rule, stack_offset);
1127 break;
1128
1129 case '@':
1130 copy_at (finput, &action_obstack,
1131 stack_offset);
1132 break;
1133
1134 case EOF:
1135 fatal (_("unmatched %s"), "`{'");
1136
1137 default:
1138 obstack_1grow (&action_obstack, c);
1139 }
1140
1141 /* Above loop exits when C is '}'. */
1142 if (--count)
1143 {
1144 obstack_1grow (&action_obstack, c);
1145 c = getc (finput);
1146 }
1147 }
1148
1149 obstack_1grow (&action_obstack, '\0');
1150 }
1151
1152
1153 static void
1154 parse_action (symbol_list *rule, int stack_offset)
1155 {
1156 rule->action_line = lineno;
1157 parse_braces (rule, stack_offset);
1158 rule->action = obstack_finish (&action_obstack);
1159 }
1160
1161
1162 static void
1163 parse_guard (symbol_list *rule, int stack_offset)
1164 {
1165 token_t t = lex ();
1166 if (t != tok_left_curly)
1167 complain (_("invalid %s declaration"), "%guard");
1168 rule->guard_line = lineno;
1169 parse_braces (rule, stack_offset);
1170 rule->guard = obstack_finish (&action_obstack);
1171 }
1172
1173 \f
1174
1175 /*-------------------------------------------------------------------.
1176 | Generate a dummy symbol, a nonterminal, whose name cannot conflict |
1177 | with the user's names. |
1178 `-------------------------------------------------------------------*/
1179
1180 static bucket *
1181 gensym (void)
1182 {
1183 /* Incremented for each generated symbol */
1184 static int gensym_count = 0;
1185 static char buf[256];
1186
1187 bucket *sym;
1188
1189 sprintf (buf, "@%d", ++gensym_count);
1190 token_buffer = buf;
1191 sym = getsym (token_buffer);
1192 sym->class = nterm_sym;
1193 sym->value = nvars++;
1194 return sym;
1195 }
1196 \f
1197 /*-------------------------------------------------------------------.
1198 | Parse the input grammar into a one symbol_list structure. Each |
1199 | rule is represented by a sequence of symbols: the left hand side |
1200 | followed by the contents of the right hand side, followed by a |
1201 | null pointer instead of a symbol to terminate the rule. The next |
1202 | symbol is the lhs of the following rule. |
1203 | |
1204 | All guards and actions are copied out to the appropriate files, |
1205 | labelled by the rule number they apply to. |
1206 | |
1207 | Bison used to allow some %directives in the rules sections, but |
1208 | this is no longer consider appropriate: (i) the documented grammar |
1209 | doesn't claim it, (ii), it would promote bad style, (iii), error |
1210 | recovery for %directives consists in skipping the junk until a `%' |
1211 | is seen and helrp synchronizing. This scheme is definitely wrong |
1212 | in the rules section. |
1213 `-------------------------------------------------------------------*/
1214
1215 static void
1216 readgram (void)
1217 {
1218 token_t t;
1219 bucket *lhs = NULL;
1220 symbol_list *p = NULL;
1221 symbol_list *p1 = NULL;
1222 bucket *bp;
1223
1224 /* Points to first symbol_list of current rule. its symbol is the
1225 lhs of the rule. */
1226 symbol_list *crule = NULL;
1227 /* Points to the symbol_list preceding crule. */
1228 symbol_list *crule1 = NULL;
1229
1230 t = lex ();
1231
1232 while (t != tok_two_percents && t != tok_eof)
1233 if (t == tok_identifier || t == tok_bar)
1234 {
1235 int action_flag = 0;
1236 /* Number of symbols in rhs of this rule so far */
1237 int rulelength = 0;
1238 int xactions = 0; /* JF for error checking */
1239 bucket *first_rhs = 0;
1240
1241 if (t == tok_identifier)
1242 {
1243 lhs = symval;
1244
1245 if (!start_flag)
1246 {
1247 startval = lhs;
1248 start_flag = 1;
1249 }
1250
1251 t = lex ();
1252 if (t != tok_colon)
1253 {
1254 complain (_("ill-formed rule: initial symbol not followed by colon"));
1255 unlex (t);
1256 }
1257 }
1258
1259 if (nrules == 0 && t == tok_bar)
1260 {
1261 complain (_("grammar starts with vertical bar"));
1262 lhs = symval; /* BOGUS: use a random symval */
1263 }
1264 /* start a new rule and record its lhs. */
1265
1266 nrules++;
1267 nitems++;
1268
1269 p = symbol_list_new (lhs);
1270
1271 crule1 = p1;
1272 if (p1)
1273 p1->next = p;
1274 else
1275 grammar = p;
1276
1277 p1 = p;
1278 crule = p;
1279
1280 /* mark the rule's lhs as a nonterminal if not already so. */
1281
1282 if (lhs->class == unknown_sym)
1283 {
1284 lhs->class = nterm_sym;
1285 lhs->value = nvars;
1286 nvars++;
1287 }
1288 else if (lhs->class == token_sym)
1289 complain (_("rule given for %s, which is a token"), lhs->tag);
1290
1291 /* read the rhs of the rule. */
1292
1293 for (;;)
1294 {
1295 t = lex ();
1296 if (t == tok_prec)
1297 {
1298 t = lex ();
1299 crule->ruleprec = symval;
1300 t = lex ();
1301 }
1302
1303 if (!(t == tok_identifier || t == tok_left_curly))
1304 break;
1305
1306 /* If next token is an identifier, see if a colon follows it.
1307 If one does, exit this rule now. */
1308 if (t == tok_identifier)
1309 {
1310 bucket *ssave;
1311 token_t t1;
1312
1313 ssave = symval;
1314 t1 = lex ();
1315 unlex (t1);
1316 symval = ssave;
1317 if (t1 == tok_colon)
1318 break;
1319
1320 if (!first_rhs) /* JF */
1321 first_rhs = symval;
1322 /* Not followed by colon =>
1323 process as part of this rule's rhs. */
1324 }
1325
1326 /* If we just passed an action, that action was in the middle
1327 of a rule, so make a dummy rule to reduce it to a
1328 non-terminal. */
1329 if (action_flag)
1330 {
1331 /* Since the action was written out with this rule's
1332 number, we must give the new rule this number by
1333 inserting the new rule before it. */
1334
1335 /* Make a dummy nonterminal, a gensym. */
1336 bucket *sdummy = gensym ();
1337
1338 /* Make a new rule, whose body is empty, before the
1339 current one, so that the action just read can
1340 belong to it. */
1341 nrules++;
1342 nitems++;
1343 p = symbol_list_new (sdummy);
1344 /* Attach its lineno to that of the host rule. */
1345 p->line = crule->line;
1346 if (crule1)
1347 crule1->next = p;
1348 else
1349 grammar = p;
1350 /* End of the rule. */
1351 crule1 = symbol_list_new (NULL);
1352 crule1->next = crule;
1353
1354 p->next = crule1;
1355
1356 /* Insert the dummy generated by that rule into this
1357 rule. */
1358 nitems++;
1359 p = symbol_list_new (sdummy);
1360 p1->next = p;
1361 p1 = p;
1362
1363 action_flag = 0;
1364 }
1365
1366 if (t == tok_identifier)
1367 {
1368 nitems++;
1369 p = symbol_list_new (symval);
1370 p1->next = p;
1371 p1 = p;
1372 }
1373 else /* handle an action. */
1374 {
1375 parse_action (crule, rulelength);
1376 action_flag = 1;
1377 xactions++; /* JF */
1378 }
1379 rulelength++;
1380 } /* end of read rhs of rule */
1381
1382 /* Put an empty link in the list to mark the end of this rule */
1383 p = symbol_list_new (NULL);
1384 p1->next = p;
1385 p1 = p;
1386
1387 if (t == tok_prec)
1388 {
1389 complain (_("two @prec's in a row"));
1390 t = lex ();
1391 crule->ruleprec = symval;
1392 t = lex ();
1393 }
1394
1395 if (t == tok_guard)
1396 {
1397 if (!semantic_parser)
1398 complain (_("%%guard present but %%semantic_parser not specified"));
1399
1400 parse_guard (crule, rulelength);
1401 t = lex ();
1402 }
1403
1404 if (t == tok_left_curly)
1405 {
1406 /* This case never occurs -wjh */
1407 if (action_flag)
1408 complain (_("two actions at end of one rule"));
1409 parse_action (crule, rulelength);
1410 action_flag = 1;
1411 xactions++; /* -wjh */
1412 t = lex ();
1413 }
1414 /* If $$ is being set in default way, report if any type
1415 mismatch. */
1416 else if (!xactions
1417 && first_rhs && lhs->type_name != first_rhs->type_name)
1418 {
1419 if (lhs->type_name == 0
1420 || first_rhs->type_name == 0
1421 || strcmp (lhs->type_name, first_rhs->type_name))
1422 complain (_("type clash (`%s' `%s') on default action"),
1423 lhs->type_name ? lhs->type_name : "",
1424 first_rhs->type_name ? first_rhs->type_name : "");
1425 }
1426 /* Warn if there is no default for $$ but we need one. */
1427 else if (!xactions && !first_rhs && lhs->type_name != 0)
1428 complain (_("empty rule for typed nonterminal, and no action"));
1429 if (t == tok_semicolon)
1430 t = lex ();
1431 }
1432 else
1433 {
1434 complain (_("invalid input: %s"), quote (token_buffer));
1435 t = lex ();
1436 }
1437
1438
1439 /* grammar has been read. Do some checking */
1440
1441 if (nsyms > MAXSHORT)
1442 fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
1443 MAXSHORT);
1444 if (nrules == 0)
1445 fatal (_("no rules in the input grammar"));
1446
1447 /* Report any undefined symbols and consider them nonterminals. */
1448
1449 for (bp = firstsymbol; bp; bp = bp->next)
1450 if (bp->class == unknown_sym)
1451 {
1452 complain (_
1453 ("symbol %s is used, but is not defined as a token and has no rules"),
1454 bp->tag);
1455 bp->class = nterm_sym;
1456 bp->value = nvars++;
1457 }
1458
1459 ntokens = nsyms - nvars;
1460 }
1461
1462 /* At the end of the grammar file, some C source code must
1463 be stored. It is going to be associated to the epilogue
1464 directive. */
1465 static void
1466 read_additionnal_code (void)
1467 {
1468 char c;
1469 struct obstack el_obstack;
1470
1471 obstack_init (&el_obstack);
1472
1473 if (!no_lines_flag)
1474 {
1475 obstack_fgrow2 (&el_obstack, muscle_find ("linef"),
1476 lineno, quotearg_style (c_quoting_style,
1477 muscle_find("filename")));
1478 }
1479
1480 while ((c = getc (finput)) != EOF)
1481 obstack_1grow (&el_obstack, c);
1482
1483 obstack_1grow (&el_obstack, 0);
1484 muscle_insert ("epilogue", obstack_finish (&el_obstack));
1485 }
1486
1487 \f
1488 /*------------------------------------------------------------------.
1489 | Set TOKEN_TRANSLATIONS. Check that no two symbols share the same |
1490 | number. |
1491 `------------------------------------------------------------------*/
1492
1493 static void
1494 token_translations_init (void)
1495 {
1496 bucket *bp = NULL;
1497 int i;
1498
1499 token_translations = XCALLOC (short, max_user_token_number + 1);
1500
1501 /* Initialize all entries for literal tokens to 2, the internal
1502 token number for $undefined., which represents all invalid
1503 inputs. */
1504 for (i = 0; i <= max_user_token_number; i++)
1505 token_translations[i] = 2;
1506
1507 for (bp = firstsymbol; bp; bp = bp->next)
1508 {
1509 /* Non-terminal? */
1510 if (bp->value >= ntokens)
1511 continue;
1512 /* A token string alias? */
1513 if (bp->user_token_number == SALIAS)
1514 continue;
1515
1516 assert (bp->user_token_number != SUNDEF);
1517
1518 /* A token which translation has already been set? */
1519 if (token_translations[bp->user_token_number] != 2)
1520 complain (_("tokens %s and %s both assigned number %d"),
1521 tags[token_translations[bp->user_token_number]],
1522 bp->tag, bp->user_token_number);
1523 token_translations[bp->user_token_number] = bp->value;
1524 }
1525 }
1526
1527
1528 /*------------------------------------------------------------------.
1529 | Assign symbol numbers, and write definition of token names into |
1530 | FDEFINES. Set up vectors TAGS and SPREC of names and precedences |
1531 | of symbols. |
1532 `------------------------------------------------------------------*/
1533
1534 static void
1535 packsymbols (void)
1536 {
1537 bucket *bp = NULL;
1538 int tokno = 1;
1539 int last_user_token_number;
1540 static char DOLLAR[] = "$";
1541
1542 tags = XCALLOC (char *, nsyms + 1);
1543 user_toknums = XCALLOC (short, nsyms + 1);
1544
1545 sprec = XCALLOC (short, nsyms);
1546 sassoc = XCALLOC (short, nsyms);
1547
1548 /* The EOF token. */
1549 tags[0] = DOLLAR;
1550 user_toknums[0] = 0;
1551
1552 max_user_token_number = 256;
1553 last_user_token_number = 256;
1554
1555 for (bp = firstsymbol; bp; bp = bp->next)
1556 {
1557 if (bp->class == nterm_sym)
1558 {
1559 bp->value += ntokens;
1560 }
1561 else if (bp->alias)
1562 {
1563 /* this symbol and its alias are a single token defn.
1564 allocate a tokno, and assign to both check agreement of
1565 ->prec and ->assoc fields and make both the same */
1566 if (bp->value == 0)
1567 bp->value = bp->alias->value = tokno++;
1568
1569 if (bp->prec != bp->alias->prec)
1570 {
1571 if (bp->prec != 0 && bp->alias->prec != 0
1572 && bp->user_token_number == SALIAS)
1573 complain (_("conflicting precedences for %s and %s"),
1574 bp->tag, bp->alias->tag);
1575 if (bp->prec != 0)
1576 bp->alias->prec = bp->prec;
1577 else
1578 bp->prec = bp->alias->prec;
1579 }
1580
1581 if (bp->assoc != bp->alias->assoc)
1582 {
1583 if (bp->assoc != 0 && bp->alias->assoc != 0
1584 && bp->user_token_number == SALIAS)
1585 complain (_("conflicting assoc values for %s and %s"),
1586 bp->tag, bp->alias->tag);
1587 if (bp->assoc != 0)
1588 bp->alias->assoc = bp->assoc;
1589 else
1590 bp->assoc = bp->alias->assoc;
1591 }
1592
1593 if (bp->user_token_number == SALIAS)
1594 continue; /* do not do processing below for SALIASs */
1595
1596 }
1597 else /* bp->class == token_sym */
1598 {
1599 bp->value = tokno++;
1600 }
1601
1602 if (bp->class == token_sym)
1603 {
1604 if (bp->user_token_number == SUNDEF)
1605 bp->user_token_number = ++last_user_token_number;
1606 if (bp->user_token_number > max_user_token_number)
1607 max_user_token_number = bp->user_token_number;
1608 }
1609
1610 tags[bp->value] = bp->tag;
1611 user_toknums[bp->value] = bp->user_token_number;
1612 sprec[bp->value] = bp->prec;
1613 sassoc[bp->value] = bp->assoc;
1614 }
1615
1616 token_translations_init ();
1617
1618 error_token_number = errtoken->value;
1619
1620 if (startval->class == unknown_sym)
1621 fatal (_("the start symbol %s is undefined"), startval->tag);
1622 else if (startval->class == token_sym)
1623 fatal (_("the start symbol %s is a token"), startval->tag);
1624
1625 start_symbol = startval->value;
1626 }
1627
1628
1629 /*---------------------------------------------------------------.
1630 | Save the definition of token names in the `TOKENDEFS' muscle. |
1631 `---------------------------------------------------------------*/
1632
1633 static void
1634 symbols_save (void)
1635 {
1636 struct obstack tokendefs;
1637 bucket *bp;
1638 char *cp, *symbol;
1639 char c;
1640 obstack_init (&tokendefs);
1641
1642 for (bp = firstsymbol; bp; bp = bp->next)
1643 {
1644 symbol = bp->tag; /* get symbol */
1645
1646 if (bp->value >= ntokens)
1647 continue;
1648 if (bp->user_token_number == SALIAS)
1649 continue;
1650 if ('\'' == *symbol)
1651 continue; /* skip literal character */
1652 if (bp == errtoken)
1653 continue; /* skip error token */
1654 if ('\"' == *symbol)
1655 {
1656 /* use literal string only if given a symbol with an alias */
1657 if (bp->alias)
1658 symbol = bp->alias->tag;
1659 else
1660 continue;
1661 }
1662
1663 /* Don't #define nonliteral tokens whose names contain periods. */
1664 cp = symbol;
1665 while ((c = *cp++) && c != '.');
1666 if (c != '\0')
1667 continue;
1668
1669 obstack_fgrow2 (&tokendefs, "# define %s\t%d\n",
1670 symbol, bp->user_token_number);
1671 if (semantic_parser)
1672 /* FIXME: This is probably wrong, and should be just as
1673 above. --akim. */
1674 obstack_fgrow2 (&tokendefs, "# define T%s\t%d\n", symbol, bp->value);
1675 }
1676
1677 obstack_1grow (&tokendefs, 0);
1678 muscle_insert ("tokendef", xstrdup (obstack_finish (&tokendefs)));
1679 obstack_free (&tokendefs, NULL);
1680 }
1681
1682
1683 /*---------------------------------------------------------------.
1684 | Convert the rules into the representation using RRHS, RLHS and |
1685 | RITEMS. |
1686 `---------------------------------------------------------------*/
1687
1688 static void
1689 packgram (void)
1690 {
1691 int itemno;
1692 int ruleno;
1693 symbol_list *p;
1694
1695 ritem = XCALLOC (short, nitems + 1);
1696 rule_table = XCALLOC (rule_t, nrules) - 1;
1697
1698 itemno = 0;
1699 ruleno = 1;
1700
1701 p = grammar;
1702 while (p)
1703 {
1704 bucket *ruleprec = p->ruleprec;
1705 rule_table[ruleno].lhs = p->sym->value;
1706 rule_table[ruleno].rhs = itemno;
1707 rule_table[ruleno].line = p->line;
1708 rule_table[ruleno].useful = TRUE;
1709 rule_table[ruleno].action = p->action;
1710 rule_table[ruleno].action_line = p->action_line;
1711 rule_table[ruleno].guard = p->guard;
1712 rule_table[ruleno].guard_line = p->guard_line;
1713
1714 p = p->next;
1715 while (p && p->sym)
1716 {
1717 ritem[itemno++] = p->sym->value;
1718 /* A rule gets by default the precedence and associativity
1719 of the last token in it. */
1720 if (p->sym->class == token_sym)
1721 {
1722 rule_table[ruleno].prec = p->sym->prec;
1723 rule_table[ruleno].assoc = p->sym->assoc;
1724 }
1725 if (p)
1726 p = p->next;
1727 }
1728
1729 /* If this rule has a %prec,
1730 the specified symbol's precedence replaces the default. */
1731 if (ruleprec)
1732 {
1733 rule_table[ruleno].prec = ruleprec->prec;
1734 rule_table[ruleno].assoc = ruleprec->assoc;
1735 rule_table[ruleno].precsym = ruleprec->value;
1736 }
1737
1738 ritem[itemno++] = -ruleno;
1739 ruleno++;
1740
1741 if (p)
1742 p = p->next;
1743 }
1744
1745 ritem[itemno] = 0;
1746
1747 if (trace_flag)
1748 ritem_print (stderr);
1749 }
1750 \f
1751 /*-------------------------------------------------------------------.
1752 | Read in the grammar specification and record it in the format |
1753 | described in gram.h. All guards are copied into the GUARD_OBSTACK |
1754 | and all actions into ACTION_OBSTACK, in each case forming the body |
1755 | of a C function (YYGUARD or YYACTION) which contains a switch |
1756 | statement to decide which guard or action to execute. |
1757 `-------------------------------------------------------------------*/
1758
1759 void
1760 reader (void)
1761 {
1762 start_flag = 0;
1763 startval = NULL; /* start symbol not specified yet. */
1764
1765 nsyms = 1;
1766 nvars = 0;
1767 nrules = 0;
1768 nitems = 0;
1769
1770 typed = 0;
1771 lastprec = 0;
1772
1773 semantic_parser = 0;
1774 pure_parser = 0;
1775
1776 grammar = NULL;
1777
1778 lex_init ();
1779 lineno = 1;
1780
1781 /* Initialize the muscle obstack. */
1782 obstack_init (&muscle_obstack);
1783
1784 /* Initialize the symbol table. */
1785 tabinit ();
1786
1787 /* Construct the error token */
1788 errtoken = getsym ("error");
1789 errtoken->class = token_sym;
1790 errtoken->user_token_number = 256; /* Value specified by POSIX. */
1791
1792 /* Construct a token that represents all undefined literal tokens.
1793 It is always token number 2. */
1794 undeftoken = getsym ("$undefined.");
1795 undeftoken->class = token_sym;
1796 undeftoken->user_token_number = 2;
1797
1798 /* Initialize the obstacks. */
1799 obstack_init (&action_obstack);
1800 obstack_init (&attrs_obstack);
1801 obstack_init (&output_obstack);
1802
1803 finput = xfopen (infile, "r");
1804
1805 /* Read the declaration section. Copy %{ ... %} groups to
1806 TABLE_OBSTACK and FDEFINES file. Also notice any %token, %left,
1807 etc. found there. */
1808 read_declarations ();
1809 /* Read in the grammar, build grammar in list form. Write out
1810 guards and actions. */
1811 readgram ();
1812 /* Some C code is given at the end of the grammar file. */
1813 read_additionnal_code ();
1814
1815 lex_free ();
1816 xfclose (finput);
1817
1818 /* Assign the symbols their symbol numbers. Write #defines for the
1819 token symbols into FDEFINES if requested. */
1820 packsymbols ();
1821 /* Save them. */
1822 symbols_save ();
1823
1824 /* Convert the grammar into the format described in gram.h. */
1825 packgram ();
1826 }