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