Imported Upstream version 20100216
[platform/upstream/byacc.git] / reader.c
1 /* $Id: reader.c,v 1.19 2010/02/17 01:41:35 tom Exp $ */
2
3 #include "defs.h"
4
5 /*  The line size must be a positive integer.  One hundred was chosen   */
6 /*  because few lines in Yacc input grammars exceed 100 characters.     */
7 /*  Note that if a line exceeds LINESIZE characters, the line buffer    */
8 /*  will be expanded to accomodate it.                                  */
9
10 #define LINESIZE 100
11
12 #define L_CURL '{'
13 #define R_CURL '}'
14
15 static void start_rule(bucket *bp, int s_lineno);
16
17 static char *cache;
18 static int cinc, cache_size;
19
20 int ntags;
21 static int tagmax;
22 static char **tag_table;
23
24 static char saw_eof;
25 char unionized;
26 char *cptr, *line;
27 static int linesize;
28
29 static bucket *goal;
30 static Value_t prec;
31 static int gensym;
32 static char last_was_action;
33
34 static int maxitems;
35 static bucket **pitem;
36
37 static int maxrules;
38 static bucket **plhs;
39
40 static size_t name_pool_size;
41 static char *name_pool;
42
43 char line_format[] = "#line %d \"%s\"\n";
44
45 static void
46 cachec(int c)
47 {
48     assert(cinc >= 0);
49     if (cinc >= cache_size)
50     {
51         cache_size += 256;
52         cache = REALLOC(cache, cache_size);
53         if (cache == 0)
54             no_space();
55     }
56     cache[cinc] = (char)c;
57     ++cinc;
58 }
59
60 static void
61 get_line(void)
62 {
63     FILE *f = input_file;
64     int c;
65     int i;
66
67     if (saw_eof || (c = getc(f)) == EOF)
68     {
69         if (line)
70         {
71             FREE(line);
72             line = 0;
73         }
74         cptr = 0;
75         saw_eof = 1;
76         return;
77     }
78
79     if (line == 0 || linesize != (LINESIZE + 1))
80     {
81         if (line)
82             FREE(line);
83         linesize = LINESIZE + 1;
84         line = MALLOC(linesize);
85         if (line == 0)
86             no_space();
87     }
88
89     i = 0;
90     ++lineno;
91     for (;;)
92     {
93         line[i] = (char)c;
94         if (c == '\n')
95         {
96             cptr = line;
97             return;
98         }
99         if (++i >= linesize)
100         {
101             linesize += LINESIZE;
102             line = REALLOC(line, linesize);
103             if (line == 0)
104                 no_space();
105         }
106         c = getc(f);
107         if (c == EOF)
108         {
109             line[i] = '\n';
110             saw_eof = 1;
111             cptr = line;
112             return;
113         }
114     }
115 }
116
117 static char *
118 dup_line(void)
119 {
120     char *p, *s, *t;
121
122     if (line == 0)
123         return (0);
124     s = line;
125     while (*s != '\n')
126         ++s;
127     p = MALLOC(s - line + 1);
128     if (p == 0)
129         no_space();
130
131     s = line;
132     t = p;
133     while ((*t++ = *s++) != '\n')
134         continue;
135     return (p);
136 }
137
138 static void
139 skip_comment(void)
140 {
141     char *s;
142
143     int st_lineno = lineno;
144     char *st_line = dup_line();
145     char *st_cptr = st_line + (cptr - line);
146
147     s = cptr + 2;
148     for (;;)
149     {
150         if (*s == '*' && s[1] == '/')
151         {
152             cptr = s + 2;
153             FREE(st_line);
154             return;
155         }
156         if (*s == '\n')
157         {
158             get_line();
159             if (line == 0)
160                 unterminated_comment(st_lineno, st_line, st_cptr);
161             s = cptr;
162         }
163         else
164             ++s;
165     }
166 }
167
168 static int
169 nextc(void)
170 {
171     char *s;
172
173     if (line == 0)
174     {
175         get_line();
176         if (line == 0)
177             return (EOF);
178     }
179
180     s = cptr;
181     for (;;)
182     {
183         switch (*s)
184         {
185         case '\n':
186             get_line();
187             if (line == 0)
188                 return (EOF);
189             s = cptr;
190             break;
191
192         case ' ':
193         case '\t':
194         case '\f':
195         case '\r':
196         case '\v':
197         case ',':
198         case ';':
199             ++s;
200             break;
201
202         case '\\':
203             cptr = s;
204             return ('%');
205
206         case '/':
207             if (s[1] == '*')
208             {
209                 cptr = s;
210                 skip_comment();
211                 s = cptr;
212                 break;
213             }
214             else if (s[1] == '/')
215             {
216                 get_line();
217                 if (line == 0)
218                     return (EOF);
219                 s = cptr;
220                 break;
221             }
222             /* FALLTHRU */
223
224         default:
225             cptr = s;
226             return (*s);
227         }
228     }
229 }
230
231 static int
232 keyword(void)
233 {
234     int c;
235     char *t_cptr = cptr;
236
237     c = *++cptr;
238     if (isalpha(c))
239     {
240         cinc = 0;
241         for (;;)
242         {
243             if (isalpha(c))
244             {
245                 if (isupper(c))
246                     c = tolower(c);
247                 cachec(c);
248             }
249             else if (isdigit(c) || c == '-' || c == '_' || c == '.' || c == '$')
250                 cachec(c);
251             else
252                 break;
253             c = *++cptr;
254         }
255         cachec(NUL);
256
257         if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0)
258             return (TOKEN);
259         if (strcmp(cache, "type") == 0)
260             return (TYPE);
261         if (strcmp(cache, "left") == 0)
262             return (LEFT);
263         if (strcmp(cache, "right") == 0)
264             return (RIGHT);
265         if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0)
266             return (NONASSOC);
267         if (strcmp(cache, "start") == 0)
268             return (START);
269         if (strcmp(cache, "union") == 0)
270             return (UNION);
271         if (strcmp(cache, "ident") == 0)
272             return (IDENT);
273         if (strcmp(cache, "expect") == 0)
274             return (EXPECT);
275         if (strcmp(cache, "expect-rr") == 0)
276             return (EXPECT_RR);
277         if (strcmp(cache, "pure-parser") == 0)
278             return (PURE_PARSER);
279     }
280     else
281     {
282         ++cptr;
283         if (c == L_CURL)
284             return (TEXT);
285         if (c == '%' || c == '\\')
286             return (MARK);
287         if (c == '<')
288             return (LEFT);
289         if (c == '>')
290             return (RIGHT);
291         if (c == '0')
292             return (TOKEN);
293         if (c == '2')
294             return (NONASSOC);
295     }
296     syntax_error(lineno, line, t_cptr);
297     /*NOTREACHED */
298 }
299
300 static void
301 copy_ident(void)
302 {
303     int c;
304     FILE *f = output_file;
305
306     c = nextc();
307     if (c == EOF)
308         unexpected_EOF();
309     if (c != '"')
310         syntax_error(lineno, line, cptr);
311     ++outline;
312     fprintf(f, "#ident \"");
313     for (;;)
314     {
315         c = *++cptr;
316         if (c == '\n')
317         {
318             fprintf(f, "\"\n");
319             return;
320         }
321         putc(c, f);
322         if (c == '"')
323         {
324             putc('\n', f);
325             ++cptr;
326             return;
327         }
328     }
329 }
330
331 static void
332 copy_text(void)
333 {
334     int c;
335     int quote;
336     FILE *f = text_file;
337     int need_newline = 0;
338     int t_lineno = lineno;
339     char *t_line = dup_line();
340     char *t_cptr = t_line + (cptr - line - 2);
341
342     if (*cptr == '\n')
343     {
344         get_line();
345         if (line == 0)
346             unterminated_text(t_lineno, t_line, t_cptr);
347     }
348     if (!lflag)
349         fprintf(f, line_format, lineno, input_file_name);
350
351   loop:
352     c = *cptr++;
353     switch (c)
354     {
355     case '\n':
356       next_line:
357         putc('\n', f);
358         need_newline = 0;
359         get_line();
360         if (line)
361             goto loop;
362         unterminated_text(t_lineno, t_line, t_cptr);
363
364     case '\'':
365     case '"':
366         {
367             int s_lineno = lineno;
368             char *s_line = dup_line();
369             char *s_cptr = s_line + (cptr - line - 1);
370
371             quote = c;
372             putc(c, f);
373             for (;;)
374             {
375                 c = *cptr++;
376                 putc(c, f);
377                 if (c == quote)
378                 {
379                     need_newline = 1;
380                     FREE(s_line);
381                     goto loop;
382                 }
383                 if (c == '\n')
384                     unterminated_string(s_lineno, s_line, s_cptr);
385                 if (c == '\\')
386                 {
387                     c = *cptr++;
388                     putc(c, f);
389                     if (c == '\n')
390                     {
391                         get_line();
392                         if (line == 0)
393                             unterminated_string(s_lineno, s_line, s_cptr);
394                     }
395                 }
396             }
397         }
398
399     case '/':
400         putc(c, f);
401         need_newline = 1;
402         c = *cptr;
403         if (c == '/')
404         {
405             putc('*', f);
406             while ((c = *++cptr) != '\n')
407             {
408                 if (c == '*' && cptr[1] == '/')
409                     fprintf(f, "* ");
410                 else
411                     putc(c, f);
412             }
413             fprintf(f, "*/");
414             goto next_line;
415         }
416         if (c == '*')
417         {
418             int c_lineno = lineno;
419             char *c_line = dup_line();
420             char *c_cptr = c_line + (cptr - line - 1);
421
422             putc('*', f);
423             ++cptr;
424             for (;;)
425             {
426                 c = *cptr++;
427                 putc(c, f);
428                 if (c == '*' && *cptr == '/')
429                 {
430                     putc('/', f);
431                     ++cptr;
432                     FREE(c_line);
433                     goto loop;
434                 }
435                 if (c == '\n')
436                 {
437                     get_line();
438                     if (line == 0)
439                         unterminated_comment(c_lineno, c_line, c_cptr);
440                 }
441             }
442         }
443         need_newline = 1;
444         goto loop;
445
446     case '%':
447     case '\\':
448         if (*cptr == R_CURL)
449         {
450             if (need_newline)
451                 putc('\n', f);
452             ++cptr;
453             FREE(t_line);
454             return;
455         }
456         /* FALLTHRU */
457
458     default:
459         putc(c, f);
460         need_newline = 1;
461         goto loop;
462     }
463 }
464
465 static void
466 copy_union(void)
467 {
468     int c;
469     int quote;
470     int depth;
471     int u_lineno = lineno;
472     char *u_line = dup_line();
473     char *u_cptr = u_line + (cptr - line - 6);
474
475     if (unionized)
476         over_unionized(cptr - 6);
477     unionized = 1;
478
479     if (!lflag)
480         fprintf(text_file, line_format, lineno, input_file_name);
481
482     fprintf(text_file, "typedef union");
483     if (dflag)
484         fprintf(union_file, "typedef union");
485
486     depth = 0;
487   loop:
488     c = *cptr++;
489     putc(c, text_file);
490     if (dflag)
491         putc(c, union_file);
492     switch (c)
493     {
494     case '\n':
495       next_line:
496         get_line();
497         if (line == 0)
498             unterminated_union(u_lineno, u_line, u_cptr);
499         goto loop;
500
501     case L_CURL:
502         ++depth;
503         goto loop;
504
505     case R_CURL:
506         if (--depth == 0)
507         {
508             fprintf(text_file, " YYSTYPE;\n");
509             FREE(u_line);
510             return;
511         }
512         goto loop;
513
514     case '\'':
515     case '"':
516         {
517             int s_lineno = lineno;
518             char *s_line = dup_line();
519             char *s_cptr = s_line + (cptr - line - 1);
520
521             quote = c;
522             for (;;)
523             {
524                 c = *cptr++;
525                 putc(c, text_file);
526                 if (dflag)
527                     putc(c, union_file);
528                 if (c == quote)
529                 {
530                     FREE(s_line);
531                     goto loop;
532                 }
533                 if (c == '\n')
534                     unterminated_string(s_lineno, s_line, s_cptr);
535                 if (c == '\\')
536                 {
537                     c = *cptr++;
538                     putc(c, text_file);
539                     if (dflag)
540                         putc(c, union_file);
541                     if (c == '\n')
542                     {
543                         get_line();
544                         if (line == 0)
545                             unterminated_string(s_lineno, s_line, s_cptr);
546                     }
547                 }
548             }
549         }
550
551     case '/':
552         c = *cptr;
553         if (c == '/')
554         {
555             putc('*', text_file);
556             if (dflag)
557                 putc('*', union_file);
558             while ((c = *++cptr) != '\n')
559             {
560                 if (c == '*' && cptr[1] == '/')
561                 {
562                     fprintf(text_file, "* ");
563                     if (dflag)
564                         fprintf(union_file, "* ");
565                 }
566                 else
567                 {
568                     putc(c, text_file);
569                     if (dflag)
570                         putc(c, union_file);
571                 }
572             }
573             fprintf(text_file, "*/\n");
574             if (dflag)
575                 fprintf(union_file, "*/\n");
576             goto next_line;
577         }
578         if (c == '*')
579         {
580             int c_lineno = lineno;
581             char *c_line = dup_line();
582             char *c_cptr = c_line + (cptr - line - 1);
583
584             putc('*', text_file);
585             if (dflag)
586                 putc('*', union_file);
587             ++cptr;
588             for (;;)
589             {
590                 c = *cptr++;
591                 putc(c, text_file);
592                 if (dflag)
593                     putc(c, union_file);
594                 if (c == '*' && *cptr == '/')
595                 {
596                     putc('/', text_file);
597                     if (dflag)
598                         putc('/', union_file);
599                     ++cptr;
600                     FREE(c_line);
601                     goto loop;
602                 }
603                 if (c == '\n')
604                 {
605                     get_line();
606                     if (line == 0)
607                         unterminated_comment(c_lineno, c_line, c_cptr);
608                 }
609             }
610         }
611         goto loop;
612
613     default:
614         goto loop;
615     }
616 }
617
618 static int
619 hexval(int c)
620 {
621     if (c >= '0' && c <= '9')
622         return (c - '0');
623     if (c >= 'A' && c <= 'F')
624         return (c - 'A' + 10);
625     if (c >= 'a' && c <= 'f')
626         return (c - 'a' + 10);
627     return (-1);
628 }
629
630 static bucket *
631 get_literal(void)
632 {
633     int c, quote;
634     int i;
635     int n;
636     char *s;
637     bucket *bp;
638     int s_lineno = lineno;
639     char *s_line = dup_line();
640     char *s_cptr = s_line + (cptr - line);
641
642     quote = *cptr++;
643     cinc = 0;
644     for (;;)
645     {
646         c = *cptr++;
647         if (c == quote)
648             break;
649         if (c == '\n')
650             unterminated_string(s_lineno, s_line, s_cptr);
651         if (c == '\\')
652         {
653             char *c_cptr = cptr - 1;
654
655             c = *cptr++;
656             switch (c)
657             {
658             case '\n':
659                 get_line();
660                 if (line == 0)
661                     unterminated_string(s_lineno, s_line, s_cptr);
662                 continue;
663
664             case '0':
665             case '1':
666             case '2':
667             case '3':
668             case '4':
669             case '5':
670             case '6':
671             case '7':
672                 n = c - '0';
673                 c = *cptr;
674                 if (IS_OCTAL(c))
675                 {
676                     n = (n << 3) + (c - '0');
677                     c = *++cptr;
678                     if (IS_OCTAL(c))
679                     {
680                         n = (n << 3) + (c - '0');
681                         ++cptr;
682                     }
683                 }
684                 if (n > MAXCHAR)
685                     illegal_character(c_cptr);
686                 c = n;
687                 break;
688
689             case 'x':
690                 c = *cptr++;
691                 n = hexval(c);
692                 if (n < 0 || n >= 16)
693                     illegal_character(c_cptr);
694                 for (;;)
695                 {
696                     c = *cptr;
697                     i = hexval(c);
698                     if (i < 0 || i >= 16)
699                         break;
700                     ++cptr;
701                     n = (n << 4) + i;
702                     if (n > MAXCHAR)
703                         illegal_character(c_cptr);
704                 }
705                 c = n;
706                 break;
707
708             case 'a':
709                 c = 7;
710                 break;
711             case 'b':
712                 c = '\b';
713                 break;
714             case 'f':
715                 c = '\f';
716                 break;
717             case 'n':
718                 c = '\n';
719                 break;
720             case 'r':
721                 c = '\r';
722                 break;
723             case 't':
724                 c = '\t';
725                 break;
726             case 'v':
727                 c = '\v';
728                 break;
729             }
730         }
731         cachec(c);
732     }
733     FREE(s_line);
734
735     n = cinc;
736     s = MALLOC(n);
737     if (s == 0)
738         no_space();
739
740     for (i = 0; i < n; ++i)
741         s[i] = cache[i];
742
743     cinc = 0;
744     if (n == 1)
745         cachec('\'');
746     else
747         cachec('"');
748
749     for (i = 0; i < n; ++i)
750     {
751         c = ((unsigned char *)s)[i];
752         if (c == '\\' || c == cache[0])
753         {
754             cachec('\\');
755             cachec(c);
756         }
757         else if (isprint(c))
758             cachec(c);
759         else
760         {
761             cachec('\\');
762             switch (c)
763             {
764             case 7:
765                 cachec('a');
766                 break;
767             case '\b':
768                 cachec('b');
769                 break;
770             case '\f':
771                 cachec('f');
772                 break;
773             case '\n':
774                 cachec('n');
775                 break;
776             case '\r':
777                 cachec('r');
778                 break;
779             case '\t':
780                 cachec('t');
781                 break;
782             case '\v':
783                 cachec('v');
784                 break;
785             default:
786                 cachec(((c >> 6) & 7) + '0');
787                 cachec(((c >> 3) & 7) + '0');
788                 cachec((c & 7) + '0');
789                 break;
790             }
791         }
792     }
793
794     if (n == 1)
795         cachec('\'');
796     else
797         cachec('"');
798
799     cachec(NUL);
800     bp = lookup(cache);
801     bp->class = TERM;
802     if (n == 1 && bp->value == UNDEFINED)
803         bp->value = *(unsigned char *)s;
804     FREE(s);
805
806     return (bp);
807 }
808
809 static int
810 is_reserved(char *name)
811 {
812     char *s;
813
814     if (strcmp(name, ".") == 0 ||
815         strcmp(name, "$accept") == 0 ||
816         strcmp(name, "$end") == 0)
817         return (1);
818
819     if (name[0] == '$' && name[1] == '$' && isdigit(name[2]))
820     {
821         s = name + 3;
822         while (isdigit(*s))
823             ++s;
824         if (*s == NUL)
825             return (1);
826     }
827
828     return (0);
829 }
830
831 static bucket *
832 get_name(void)
833 {
834     int c;
835
836     cinc = 0;
837     for (c = *cptr; IS_IDENT(c); c = *++cptr)
838         cachec(c);
839     cachec(NUL);
840
841     if (is_reserved(cache))
842         used_reserved(cache);
843
844     return (lookup(cache));
845 }
846
847 static Value_t
848 get_number(void)
849 {
850     int c;
851     Value_t n;
852
853     n = 0;
854     for (c = *cptr; isdigit(c); c = *++cptr)
855         n = (Value_t) (10 * n + (c - '0'));
856
857     return (n);
858 }
859
860 static char *
861 get_tag(void)
862 {
863     int c;
864     int i;
865     char *s;
866     int t_lineno = lineno;
867     char *t_line = dup_line();
868     char *t_cptr = t_line + (cptr - line);
869
870     ++cptr;
871     c = nextc();
872     if (c == EOF)
873         unexpected_EOF();
874     if (!isalpha(c) && c != '_' && c != '$')
875         illegal_tag(t_lineno, t_line, t_cptr);
876
877     cinc = 0;
878     do
879     {
880         cachec(c);
881         c = *++cptr;
882     }
883     while (IS_IDENT(c));
884     cachec(NUL);
885
886     c = nextc();
887     if (c == EOF)
888         unexpected_EOF();
889     if (c != '>')
890         illegal_tag(t_lineno, t_line, t_cptr);
891     ++cptr;
892
893     for (i = 0; i < ntags; ++i)
894     {
895         if (strcmp(cache, tag_table[i]) == 0)
896         {
897             FREE(t_line);
898             return (tag_table[i]);
899         }
900     }
901
902     if (ntags >= tagmax)
903     {
904         tagmax += 16;
905         tag_table = (char **)
906             (tag_table
907              ? REALLOC(tag_table, (unsigned)tagmax * sizeof(char *))
908              : MALLOC((unsigned)tagmax * sizeof(char *)));
909         if (tag_table == 0)
910             no_space();
911     }
912
913     s = MALLOC(cinc);
914     if (s == 0)
915         no_space();
916     strcpy(s, cache);
917     tag_table[ntags] = s;
918     ++ntags;
919     FREE(t_line);
920     return (s);
921 }
922
923 static void
924 declare_tokens(int assoc)
925 {
926     int c;
927     bucket *bp;
928     Value_t value;
929     char *tag = 0;
930
931     if (assoc != TOKEN)
932         ++prec;
933
934     c = nextc();
935     if (c == EOF)
936         unexpected_EOF();
937     if (c == '<')
938     {
939         tag = get_tag();
940         c = nextc();
941         if (c == EOF)
942             unexpected_EOF();
943     }
944
945     for (;;)
946     {
947         if (isalpha(c) || c == '_' || c == '.' || c == '$')
948             bp = get_name();
949         else if (c == '\'' || c == '"')
950             bp = get_literal();
951         else
952             return;
953
954         if (bp == goal)
955             tokenized_start(bp->name);
956         bp->class = TERM;
957
958         if (tag)
959         {
960             if (bp->tag && tag != bp->tag)
961                 retyped_warning(bp->name);
962             bp->tag = tag;
963         }
964
965         if (assoc != TOKEN)
966         {
967             if (bp->prec && prec != bp->prec)
968                 reprec_warning(bp->name);
969             bp->assoc = (Assoc_t) assoc;
970             bp->prec = prec;
971         }
972
973         c = nextc();
974         if (c == EOF)
975             unexpected_EOF();
976         value = UNDEFINED;
977         if (isdigit(c))
978         {
979             value = get_number();
980             if (bp->value != UNDEFINED && value != bp->value)
981                 revalued_warning(bp->name);
982             bp->value = value;
983             c = nextc();
984             if (c == EOF)
985                 unexpected_EOF();
986         }
987     }
988 }
989
990 /*
991  * %expect requires special handling
992  * as it really isn't part of the yacc
993  * grammar only a flag for yacc proper.
994  */
995 static void
996 declare_expect(int assoc)
997 {
998     int c;
999
1000     if (assoc != EXPECT && assoc != EXPECT_RR)
1001         ++prec;
1002
1003     /*
1004      * Stay away from nextc - doesn't
1005      * detect EOL and will read to EOF.
1006      */
1007     c = *++cptr;
1008     if (c == EOF)
1009         unexpected_EOF();
1010
1011     for (;;)
1012     {
1013         if (isdigit(c))
1014         {
1015             if (assoc == EXPECT)
1016                 SRexpect = get_number();
1017             else
1018                 RRexpect = get_number();
1019             break;
1020         }
1021         /*
1022          * Looking for number before EOL.
1023          * Spaces, tabs, and numbers are ok,
1024          * words, punc., etc. are syntax errors.
1025          */
1026         else if (c == '\n' || isalpha(c) || !isspace(c))
1027         {
1028             syntax_error(lineno, line, cptr);
1029         }
1030         else
1031         {
1032             c = *++cptr;
1033             if (c == EOF)
1034                 unexpected_EOF();
1035         }
1036     }
1037 }
1038
1039 static void
1040 declare_types(void)
1041 {
1042     int c;
1043     bucket *bp;
1044     char *tag;
1045
1046     c = nextc();
1047     if (c == EOF)
1048         unexpected_EOF();
1049     if (c != '<')
1050         syntax_error(lineno, line, cptr);
1051     tag = get_tag();
1052
1053     for (;;)
1054     {
1055         c = nextc();
1056         if (isalpha(c) || c == '_' || c == '.' || c == '$')
1057             bp = get_name();
1058         else if (c == '\'' || c == '"')
1059             bp = get_literal();
1060         else
1061             return;
1062
1063         if (bp->tag && tag != bp->tag)
1064             retyped_warning(bp->name);
1065         bp->tag = tag;
1066     }
1067 }
1068
1069 static void
1070 declare_start(void)
1071 {
1072     int c;
1073     bucket *bp;
1074
1075     c = nextc();
1076     if (c == EOF)
1077         unexpected_EOF();
1078     if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1079         syntax_error(lineno, line, cptr);
1080     bp = get_name();
1081     if (bp->class == TERM)
1082         terminal_start(bp->name);
1083     if (goal && goal != bp)
1084         restarted_warning();
1085     goal = bp;
1086 }
1087
1088 static void
1089 read_declarations(void)
1090 {
1091     int c, k;
1092
1093     cache_size = 256;
1094     cache = MALLOC(cache_size);
1095     if (cache == 0)
1096         no_space();
1097
1098     for (;;)
1099     {
1100         c = nextc();
1101         if (c == EOF)
1102             unexpected_EOF();
1103         if (c != '%')
1104             syntax_error(lineno, line, cptr);
1105         switch (k = keyword())
1106         {
1107         case MARK:
1108             return;
1109
1110         case IDENT:
1111             copy_ident();
1112             break;
1113
1114         case TEXT:
1115             copy_text();
1116             break;
1117
1118         case UNION:
1119             copy_union();
1120             break;
1121
1122         case TOKEN:
1123         case LEFT:
1124         case RIGHT:
1125         case NONASSOC:
1126             declare_tokens(k);
1127             break;
1128
1129         case EXPECT:
1130         case EXPECT_RR:
1131             declare_expect(k);
1132             break;
1133
1134         case TYPE:
1135             declare_types();
1136             break;
1137
1138         case START:
1139             declare_start();
1140             break;
1141
1142         case PURE_PARSER:
1143             pure_parser = 1;
1144             break;
1145         }
1146     }
1147 }
1148
1149 static void
1150 initialize_grammar(void)
1151 {
1152     nitems = 4;
1153     maxitems = 300;
1154     pitem = (bucket **)MALLOC((unsigned)maxitems * sizeof(bucket *));
1155     if (pitem == 0)
1156         no_space();
1157     pitem[0] = 0;
1158     pitem[1] = 0;
1159     pitem[2] = 0;
1160     pitem[3] = 0;
1161
1162     nrules = 3;
1163     maxrules = 100;
1164     plhs = (bucket **)MALLOC((unsigned)maxrules * sizeof(bucket *));
1165     if (plhs == 0)
1166         no_space();
1167     plhs[0] = 0;
1168     plhs[1] = 0;
1169     plhs[2] = 0;
1170     rprec = (short *)MALLOC((unsigned)maxrules * sizeof(short));
1171     if (rprec == 0)
1172         no_space();
1173     rprec[0] = 0;
1174     rprec[1] = 0;
1175     rprec[2] = 0;
1176     rassoc = (char *)MALLOC((unsigned)maxrules * sizeof(char));
1177     if (rassoc == 0)
1178         no_space();
1179     rassoc[0] = TOKEN;
1180     rassoc[1] = TOKEN;
1181     rassoc[2] = TOKEN;
1182 }
1183
1184 static void
1185 expand_items(void)
1186 {
1187     maxitems += 300;
1188     pitem = (bucket **)REALLOC(pitem, (unsigned)maxitems * sizeof(bucket *));
1189     if (pitem == 0)
1190         no_space();
1191 }
1192
1193 static void
1194 expand_rules(void)
1195 {
1196     maxrules += 100;
1197     plhs = (bucket **)REALLOC(plhs, (unsigned)maxrules * sizeof(bucket *));
1198     if (plhs == 0)
1199         no_space();
1200     rprec = (short *)REALLOC(rprec, (unsigned)maxrules * sizeof(short));
1201     if (rprec == 0)
1202         no_space();
1203     rassoc = (char *)REALLOC(rassoc, (unsigned)maxrules * sizeof(char));
1204     if (rassoc == 0)
1205         no_space();
1206 }
1207
1208 static void
1209 advance_to_start(void)
1210 {
1211     int c;
1212     bucket *bp;
1213     char *s_cptr;
1214     int s_lineno;
1215
1216     for (;;)
1217     {
1218         c = nextc();
1219         if (c != '%')
1220             break;
1221         s_cptr = cptr;
1222         switch (keyword())
1223         {
1224         case MARK:
1225             no_grammar();
1226
1227         case TEXT:
1228             copy_text();
1229             break;
1230
1231         case START:
1232             declare_start();
1233             break;
1234
1235         default:
1236             syntax_error(lineno, line, s_cptr);
1237         }
1238     }
1239
1240     c = nextc();
1241     if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1242         syntax_error(lineno, line, cptr);
1243     bp = get_name();
1244     if (goal == 0)
1245     {
1246         if (bp->class == TERM)
1247             terminal_start(bp->name);
1248         goal = bp;
1249     }
1250
1251     s_lineno = lineno;
1252     c = nextc();
1253     if (c == EOF)
1254         unexpected_EOF();
1255     if (c != ':')
1256         syntax_error(lineno, line, cptr);
1257     start_rule(bp, s_lineno);
1258     ++cptr;
1259 }
1260
1261 static void
1262 start_rule(bucket *bp, int s_lineno)
1263 {
1264     if (bp->class == TERM)
1265         terminal_lhs(s_lineno);
1266     bp->class = NONTERM;
1267     if (nrules >= maxrules)
1268         expand_rules();
1269     plhs[nrules] = bp;
1270     rprec[nrules] = UNDEFINED;
1271     rassoc[nrules] = TOKEN;
1272 }
1273
1274 static void
1275 end_rule(void)
1276 {
1277     int i;
1278
1279     if (!last_was_action && plhs[nrules]->tag)
1280     {
1281         if (pitem[nitems - 1])
1282         {
1283             for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1284                 continue;
1285             if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1286                 default_action_warning();
1287         }
1288     }
1289
1290     last_was_action = 0;
1291     if (nitems >= maxitems)
1292         expand_items();
1293     pitem[nitems] = 0;
1294     ++nitems;
1295     ++nrules;
1296 }
1297
1298 static void
1299 insert_empty_rule(void)
1300 {
1301     bucket *bp, **bpp;
1302
1303     assert(cache);
1304     sprintf(cache, "$$%d", ++gensym);
1305     bp = make_bucket(cache);
1306     last_symbol->next = bp;
1307     last_symbol = bp;
1308     bp->tag = plhs[nrules]->tag;
1309     bp->class = NONTERM;
1310
1311     if ((nitems += 2) > maxitems)
1312         expand_items();
1313     bpp = pitem + nitems - 1;
1314     *bpp-- = bp;
1315     while ((bpp[0] = bpp[-1]) != 0)
1316         --bpp;
1317
1318     if (++nrules >= maxrules)
1319         expand_rules();
1320     plhs[nrules] = plhs[nrules - 1];
1321     plhs[nrules - 1] = bp;
1322     rprec[nrules] = rprec[nrules - 1];
1323     rprec[nrules - 1] = 0;
1324     rassoc[nrules] = rassoc[nrules - 1];
1325     rassoc[nrules - 1] = TOKEN;
1326 }
1327
1328 static void
1329 add_symbol(void)
1330 {
1331     int c;
1332     bucket *bp;
1333     int s_lineno = lineno;
1334
1335     c = *cptr;
1336     if (c == '\'' || c == '"')
1337         bp = get_literal();
1338     else
1339         bp = get_name();
1340
1341     c = nextc();
1342     if (c == ':')
1343     {
1344         end_rule();
1345         start_rule(bp, s_lineno);
1346         ++cptr;
1347         return;
1348     }
1349
1350     if (last_was_action)
1351         insert_empty_rule();
1352     last_was_action = 0;
1353
1354     if (++nitems > maxitems)
1355         expand_items();
1356     pitem[nitems - 1] = bp;
1357 }
1358
1359 static char *
1360 after_blanks(char *s)
1361 {
1362     while (*s != '\0' && isspace(*s))
1363         ++s;
1364     return s;
1365 }
1366
1367 static void
1368 copy_action(void)
1369 {
1370     int c;
1371     int i, n;
1372     int depth;
1373     int quote;
1374     char *tag;
1375     FILE *f = action_file;
1376     int a_lineno = lineno;
1377     char *a_line = dup_line();
1378     char *a_cptr = a_line + (cptr - line);
1379
1380     if (last_was_action)
1381         insert_empty_rule();
1382     last_was_action = 1;
1383
1384     fprintf(f, "case %d:\n", nrules - 2);
1385     if (!lflag)
1386         fprintf(f, line_format, lineno, input_file_name);
1387     if (*cptr == '=')
1388         ++cptr;
1389
1390     /* avoid putting curly-braces in first column, to ease editing */
1391     if (*after_blanks(cptr) == L_CURL)
1392     {
1393         putc('\t', f);
1394         cptr = after_blanks(cptr);
1395     }
1396
1397     n = 0;
1398     for (i = nitems - 1; pitem[i]; --i)
1399         ++n;
1400
1401     depth = 0;
1402   loop:
1403     c = *cptr;
1404     if (c == '$')
1405     {
1406         if (cptr[1] == '<')
1407         {
1408             int d_lineno = lineno;
1409             char *d_line = dup_line();
1410             char *d_cptr = d_line + (cptr - line);
1411
1412             ++cptr;
1413             tag = get_tag();
1414             c = *cptr;
1415             if (c == '$')
1416             {
1417                 fprintf(f, "yyval.%s", tag);
1418                 ++cptr;
1419                 FREE(d_line);
1420                 goto loop;
1421             }
1422             else if (isdigit(c))
1423             {
1424                 i = get_number();
1425                 if (i > n)
1426                     dollar_warning(d_lineno, i);
1427                 fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1428                 FREE(d_line);
1429                 goto loop;
1430             }
1431             else if (c == '-' && isdigit(cptr[1]))
1432             {
1433                 ++cptr;
1434                 i = -get_number() - n;
1435                 fprintf(f, "yystack.l_mark[%d].%s", i, tag);
1436                 FREE(d_line);
1437                 goto loop;
1438             }
1439             else
1440                 dollar_error(d_lineno, d_line, d_cptr);
1441         }
1442         else if (cptr[1] == '$')
1443         {
1444             if (ntags)
1445             {
1446                 tag = plhs[nrules]->tag;
1447                 if (tag == 0)
1448                     untyped_lhs();
1449                 fprintf(f, "yyval.%s", tag);
1450             }
1451             else
1452                 fprintf(f, "yyval");
1453             cptr += 2;
1454             goto loop;
1455         }
1456         else if (isdigit(cptr[1]))
1457         {
1458             ++cptr;
1459             i = get_number();
1460             if (ntags)
1461             {
1462                 if (i <= 0 || i > n)
1463                     unknown_rhs(i);
1464                 tag = pitem[nitems + i - n - 1]->tag;
1465                 if (tag == 0)
1466                     untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1467                 fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1468             }
1469             else
1470             {
1471                 if (i > n)
1472                     dollar_warning(lineno, i);
1473                 fprintf(f, "yystack.l_mark[%d]", i - n);
1474             }
1475             goto loop;
1476         }
1477         else if (cptr[1] == '-')
1478         {
1479             cptr += 2;
1480             i = get_number();
1481             if (ntags)
1482                 unknown_rhs(-i);
1483             fprintf(f, "yystack.l_mark[%d]", -i - n);
1484             goto loop;
1485         }
1486     }
1487     if (isalpha(c) || c == '_' || c == '$')
1488     {
1489         do
1490         {
1491             putc(c, f);
1492             c = *++cptr;
1493         }
1494         while (isalnum(c) || c == '_' || c == '$');
1495         goto loop;
1496     }
1497     putc(c, f);
1498     ++cptr;
1499     switch (c)
1500     {
1501     case '\n':
1502       next_line:
1503         get_line();
1504         if (line)
1505             goto loop;
1506         unterminated_action(a_lineno, a_line, a_cptr);
1507
1508     case ';':
1509         if (depth > 0)
1510             goto loop;
1511         fprintf(f, "\nbreak;\n");
1512         free(a_line);
1513         return;
1514
1515     case L_CURL:
1516         ++depth;
1517         goto loop;
1518
1519     case R_CURL:
1520         if (--depth > 0)
1521             goto loop;
1522         fprintf(f, "\nbreak;\n");
1523         free(a_line);
1524         return;
1525
1526     case '\'':
1527     case '"':
1528         {
1529             int s_lineno = lineno;
1530             char *s_line = dup_line();
1531             char *s_cptr = s_line + (cptr - line - 1);
1532
1533             quote = c;
1534             for (;;)
1535             {
1536                 c = *cptr++;
1537                 putc(c, f);
1538                 if (c == quote)
1539                 {
1540                     FREE(s_line);
1541                     goto loop;
1542                 }
1543                 if (c == '\n')
1544                     unterminated_string(s_lineno, s_line, s_cptr);
1545                 if (c == '\\')
1546                 {
1547                     c = *cptr++;
1548                     putc(c, f);
1549                     if (c == '\n')
1550                     {
1551                         get_line();
1552                         if (line == 0)
1553                             unterminated_string(s_lineno, s_line, s_cptr);
1554                     }
1555                 }
1556             }
1557         }
1558
1559     case '/':
1560         c = *cptr;
1561         if (c == '/')
1562         {
1563             putc('*', f);
1564             while ((c = *++cptr) != '\n')
1565             {
1566                 if (c == '*' && cptr[1] == '/')
1567                     fprintf(f, "* ");
1568                 else
1569                     putc(c, f);
1570             }
1571             fprintf(f, "*/\n");
1572             goto next_line;
1573         }
1574         if (c == '*')
1575         {
1576             int c_lineno = lineno;
1577             char *c_line = dup_line();
1578             char *c_cptr = c_line + (cptr - line - 1);
1579
1580             putc('*', f);
1581             ++cptr;
1582             for (;;)
1583             {
1584                 c = *cptr++;
1585                 putc(c, f);
1586                 if (c == '*' && *cptr == '/')
1587                 {
1588                     putc('/', f);
1589                     ++cptr;
1590                     FREE(c_line);
1591                     goto loop;
1592                 }
1593                 if (c == '\n')
1594                 {
1595                     get_line();
1596                     if (line == 0)
1597                         unterminated_comment(c_lineno, c_line, c_cptr);
1598                 }
1599             }
1600         }
1601         goto loop;
1602
1603     default:
1604         goto loop;
1605     }
1606 }
1607
1608 static int
1609 mark_symbol(void)
1610 {
1611     int c;
1612     bucket *bp;
1613
1614     c = cptr[1];
1615     if (c == '%' || c == '\\')
1616     {
1617         cptr += 2;
1618         return (1);
1619     }
1620
1621     if (c == '=')
1622         cptr += 2;
1623     else if ((c == 'p' || c == 'P') &&
1624              ((c = cptr[2]) == 'r' || c == 'R') &&
1625              ((c = cptr[3]) == 'e' || c == 'E') &&
1626              ((c = cptr[4]) == 'c' || c == 'C') &&
1627              ((c = cptr[5], !IS_IDENT(c))))
1628         cptr += 5;
1629     else
1630         syntax_error(lineno, line, cptr);
1631
1632     c = nextc();
1633     if (isalpha(c) || c == '_' || c == '.' || c == '$')
1634         bp = get_name();
1635     else if (c == '\'' || c == '"')
1636         bp = get_literal();
1637     else
1638     {
1639         syntax_error(lineno, line, cptr);
1640         /*NOTREACHED */
1641     }
1642
1643     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1644         prec_redeclared();
1645
1646     rprec[nrules] = bp->prec;
1647     rassoc[nrules] = bp->assoc;
1648     return (0);
1649 }
1650
1651 static void
1652 read_grammar(void)
1653 {
1654     int c;
1655
1656     initialize_grammar();
1657     advance_to_start();
1658
1659     for (;;)
1660     {
1661         c = nextc();
1662         if (c == EOF)
1663             break;
1664         if (isalpha(c)
1665             || c == '_'
1666             || c == '.'
1667             || c == '$'
1668             || c == '\''
1669             || c == '"')
1670             add_symbol();
1671         else if (c == L_CURL || c == '=')
1672             copy_action();
1673         else if (c == '|')
1674         {
1675             end_rule();
1676             start_rule(plhs[nrules - 1], 0);
1677             ++cptr;
1678         }
1679         else if (c == '%')
1680         {
1681             if (mark_symbol())
1682                 break;
1683         }
1684         else
1685             syntax_error(lineno, line, cptr);
1686     }
1687     end_rule();
1688 }
1689
1690 static void
1691 free_tags(void)
1692 {
1693     int i;
1694
1695     if (tag_table == 0)
1696         return;
1697
1698     for (i = 0; i < ntags; ++i)
1699     {
1700         assert(tag_table[i]);
1701         FREE(tag_table[i]);
1702     }
1703     FREE(tag_table);
1704 }
1705
1706 static void
1707 pack_names(void)
1708 {
1709     bucket *bp;
1710     char *p, *s, *t;
1711
1712     name_pool_size = 13;        /* 13 == sizeof("$end") + sizeof("$accept") */
1713     for (bp = first_symbol; bp; bp = bp->next)
1714         name_pool_size += strlen(bp->name) + 1;
1715     name_pool = MALLOC(name_pool_size);
1716     if (name_pool == 0)
1717         no_space();
1718
1719     strcpy(name_pool, "$accept");
1720     strcpy(name_pool + 8, "$end");
1721     t = name_pool + 13;
1722     for (bp = first_symbol; bp; bp = bp->next)
1723     {
1724         p = t;
1725         s = bp->name;
1726         while ((*t++ = *s++) != 0)
1727             continue;
1728         FREE(bp->name);
1729         bp->name = p;
1730     }
1731 }
1732
1733 static void
1734 check_symbols(void)
1735 {
1736     bucket *bp;
1737
1738     if (goal->class == UNKNOWN)
1739         undefined_goal(goal->name);
1740
1741     for (bp = first_symbol; bp; bp = bp->next)
1742     {
1743         if (bp->class == UNKNOWN)
1744         {
1745             undefined_symbol_warning(bp->name);
1746             bp->class = TERM;
1747         }
1748     }
1749 }
1750
1751 static void
1752 protect_string(char *src, char **des)
1753 {
1754     unsigned len;
1755     char *s;
1756     char *d;
1757
1758     *des = src;
1759     if (src)
1760     {
1761         len = 1;
1762         s = src;
1763         while (*s)
1764         {
1765             if ('\\' == *s || '"' == *s)
1766                 len++;
1767             s++;
1768             len++;
1769         }
1770         *des = d = (char *)MALLOC(len);
1771         if (0 == *des)
1772             no_space();
1773         s = src;
1774         while (*s)
1775         {
1776             if ('\\' == *s || '"' == *s)
1777                 *d++ = '\\';
1778             *d++ = *s++;
1779         }
1780         *d = '\0';
1781     }
1782 }
1783
1784 static void
1785 pack_symbols(void)
1786 {
1787     bucket *bp;
1788     bucket **v;
1789     Value_t i, j, k, n;
1790
1791     nsyms = 2;
1792     ntokens = 1;
1793     for (bp = first_symbol; bp; bp = bp->next)
1794     {
1795         ++nsyms;
1796         if (bp->class == TERM)
1797             ++ntokens;
1798     }
1799     start_symbol = (Value_t) ntokens;
1800     nvars = nsyms - ntokens;
1801
1802     symbol_name = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
1803     if (symbol_name == 0)
1804         no_space();
1805     symbol_value = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1806     if (symbol_value == 0)
1807         no_space();
1808     symbol_prec = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1809     if (symbol_prec == 0)
1810         no_space();
1811     symbol_assoc = MALLOC(nsyms);
1812     if (symbol_assoc == 0)
1813         no_space();
1814
1815     v = (bucket **)MALLOC((unsigned)nsyms * sizeof(bucket *));
1816     if (v == 0)
1817         no_space();
1818
1819     v[0] = 0;
1820     v[start_symbol] = 0;
1821
1822     i = 1;
1823     j = (Value_t) (start_symbol + 1);
1824     for (bp = first_symbol; bp; bp = bp->next)
1825     {
1826         if (bp->class == TERM)
1827             v[i++] = bp;
1828         else
1829             v[j++] = bp;
1830     }
1831     assert(i == ntokens && j == nsyms);
1832
1833     for (i = 1; i < ntokens; ++i)
1834         v[i]->index = i;
1835
1836     goal->index = (Index_t) (start_symbol + 1);
1837     k = (Value_t) (start_symbol + 2);
1838     while (++i < nsyms)
1839         if (v[i] != goal)
1840         {
1841             v[i]->index = k;
1842             ++k;
1843         }
1844
1845     goal->value = 0;
1846     k = 1;
1847     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
1848     {
1849         if (v[i] != goal)
1850         {
1851             v[i]->value = k;
1852             ++k;
1853         }
1854     }
1855
1856     k = 0;
1857     for (i = 1; i < ntokens; ++i)
1858     {
1859         n = v[i]->value;
1860         if (n > 256)
1861         {
1862             for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
1863                 symbol_value[j] = symbol_value[j - 1];
1864             symbol_value[j] = n;
1865         }
1866     }
1867
1868     if (v[1]->value == UNDEFINED)
1869         v[1]->value = 256;
1870
1871     j = 0;
1872     n = 257;
1873     for (i = 2; i < ntokens; ++i)
1874     {
1875         if (v[i]->value == UNDEFINED)
1876         {
1877             while (j < k && n == symbol_value[j])
1878             {
1879                 while (++j < k && n == symbol_value[j])
1880                     continue;
1881                 ++n;
1882             }
1883             v[i]->value = n;
1884             ++n;
1885         }
1886     }
1887
1888     symbol_name[0] = name_pool + 8;
1889     symbol_value[0] = 0;
1890     symbol_prec[0] = 0;
1891     symbol_assoc[0] = TOKEN;
1892     for (i = 1; i < ntokens; ++i)
1893     {
1894         symbol_name[i] = v[i]->name;
1895         symbol_value[i] = v[i]->value;
1896         symbol_prec[i] = v[i]->prec;
1897         symbol_assoc[i] = v[i]->assoc;
1898     }
1899     symbol_name[start_symbol] = name_pool;
1900     symbol_value[start_symbol] = -1;
1901     symbol_prec[start_symbol] = 0;
1902     symbol_assoc[start_symbol] = TOKEN;
1903     for (++i; i < nsyms; ++i)
1904     {
1905         k = v[i]->index;
1906         symbol_name[k] = v[i]->name;
1907         symbol_value[k] = v[i]->value;
1908         symbol_prec[k] = v[i]->prec;
1909         symbol_assoc[k] = v[i]->assoc;
1910     }
1911
1912     if (gflag)
1913     {
1914         symbol_pname = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
1915         if (symbol_pname == 0)
1916             no_space();
1917
1918         for (i = 0; i < nsyms; ++i)
1919             protect_string(symbol_name[i], &(symbol_pname[i]));
1920     }
1921
1922     FREE(v);
1923 }
1924
1925 static void
1926 pack_grammar(void)
1927 {
1928     int i;
1929     Value_t j;
1930     Assoc_t assoc;
1931     Value_t prec2;
1932
1933     ritem = (short *)MALLOC((unsigned)nitems * sizeof(short));
1934     if (ritem == 0)
1935         no_space();
1936     rlhs = (short *)MALLOC((unsigned)nrules * sizeof(short));
1937     if (rlhs == 0)
1938         no_space();
1939     rrhs = (short *)MALLOC((unsigned)(nrules + 1) * sizeof(short));
1940     if (rrhs == 0)
1941         no_space();
1942     rprec = (short *)REALLOC(rprec, (unsigned)nrules * sizeof(short));
1943     if (rprec == 0)
1944         no_space();
1945     rassoc = REALLOC(rassoc, nrules);
1946     if (rassoc == 0)
1947         no_space();
1948
1949     ritem[0] = -1;
1950     ritem[1] = goal->index;
1951     ritem[2] = 0;
1952     ritem[3] = -2;
1953     rlhs[0] = 0;
1954     rlhs[1] = 0;
1955     rlhs[2] = start_symbol;
1956     rrhs[0] = 0;
1957     rrhs[1] = 0;
1958     rrhs[2] = 1;
1959
1960     j = 4;
1961     for (i = 3; i < nrules; ++i)
1962     {
1963         rlhs[i] = plhs[i]->index;
1964         rrhs[i] = j;
1965         assoc = TOKEN;
1966         prec2 = 0;
1967         while (pitem[j])
1968         {
1969             ritem[j] = pitem[j]->index;
1970             if (pitem[j]->class == TERM)
1971             {
1972                 prec2 = pitem[j]->prec;
1973                 assoc = pitem[j]->assoc;
1974             }
1975             ++j;
1976         }
1977         ritem[j] = (Value_t) - i;
1978         ++j;
1979         if (rprec[i] == UNDEFINED)
1980         {
1981             rprec[i] = prec2;
1982             rassoc[i] = assoc;
1983         }
1984     }
1985     rrhs[i] = j;
1986
1987     FREE(plhs);
1988     FREE(pitem);
1989 }
1990
1991 static void
1992 print_grammar(void)
1993 {
1994     int i, k;
1995     size_t j, spacing = 0;
1996     FILE *f = verbose_file;
1997
1998     if (!vflag)
1999         return;
2000
2001     k = 1;
2002     for (i = 2; i < nrules; ++i)
2003     {
2004         if (rlhs[i] != rlhs[i - 1])
2005         {
2006             if (i != 2)
2007                 fprintf(f, "\n");
2008             fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
2009             spacing = strlen(symbol_name[rlhs[i]]) + 1;
2010         }
2011         else
2012         {
2013             fprintf(f, "%4d  ", i - 2);
2014             j = spacing;
2015             while (j-- != 0)
2016                 putc(' ', f);
2017             putc('|', f);
2018         }
2019
2020         while (ritem[k] >= 0)
2021         {
2022             fprintf(f, " %s", symbol_name[ritem[k]]);
2023             ++k;
2024         }
2025         ++k;
2026         putc('\n', f);
2027     }
2028 }
2029
2030 void
2031 reader(void)
2032 {
2033     write_section(banner);
2034     create_symbol_table();
2035     read_declarations();
2036     read_grammar();
2037     free_symbol_table();
2038     free_tags();
2039     pack_names();
2040     check_symbols();
2041     pack_symbols();
2042     pack_grammar();
2043     free_symbols();
2044     print_grammar();
2045 }
2046
2047 #ifdef NO_LEAKS
2048 void
2049 reader_leaks(void)
2050 {
2051     DO_FREE(line);
2052     DO_FREE(rrhs);
2053     DO_FREE(rlhs);
2054     DO_FREE(rprec);
2055     DO_FREE(ritem);
2056     DO_FREE(rassoc);
2057     DO_FREE(cache);
2058     DO_FREE(name_pool);
2059     DO_FREE(symbol_name);
2060     DO_FREE(symbol_prec);
2061     DO_FREE(symbol_assoc);
2062     DO_FREE(symbol_value);
2063 }
2064 #endif