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