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