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