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