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