Imported Upstream version 20101126
[platform/upstream/byacc.git] / reader.c
1 /* $Id: reader.c,v 1.31 2010/11/26 12:30:40 tom Exp $ */
2
3 #include "defs.h"
4
5 /*  The line size must be a positive integer.  One hundred was chosen   */
6 /*  because few lines in Yacc input grammars exceed 100 characters.     */
7 /*  Note that if a line exceeds LINESIZE characters, the line buffer    */
8 /*  will be expanded to accomodate it.                                  */
9
10 #define LINESIZE 100
11
12 #define L_CURL '{'
13 #define R_CURL '}'
14
15 static void start_rule(bucket *bp, int s_lineno);
16
17 static char *cache;
18 static int cinc, cache_size;
19
20 int ntags;
21 static int tagmax;
22 static char **tag_table;
23
24 static char saw_eof;
25 char unionized;
26 char *cptr, *line;
27 static int linesize;
28
29 static bucket *goal;
30 static Value_t prec;
31 static int gensym;
32 static char last_was_action;
33
34 static int maxitems;
35 static bucket **pitem;
36
37 static int maxrules;
38 static bucket **plhs;
39
40 static size_t name_pool_size;
41 static char *name_pool;
42
43 char line_format[] = "#line %d \"%s\"\n";
44
45 param *lex_param;
46 param *parse_param;
47
48 static void
49 cachec(int c)
50 {
51     assert(cinc >= 0);
52     if (cinc >= cache_size)
53     {
54         cache_size += 256;
55         cache = REALLOC(cache, cache_size);
56         NO_SPACE(cache);
57     }
58     cache[cinc] = (char)c;
59     ++cinc;
60 }
61
62 static void
63 get_line(void)
64 {
65     FILE *f = input_file;
66     int c;
67     int i;
68
69     if (saw_eof || (c = getc(f)) == EOF)
70     {
71         if (line)
72         {
73             FREE(line);
74             line = 0;
75         }
76         cptr = 0;
77         saw_eof = 1;
78         return;
79     }
80
81     if (line == 0 || linesize != (LINESIZE + 1))
82     {
83         if (line)
84             FREE(line);
85         linesize = LINESIZE + 1;
86         line = MALLOC(linesize);
87         NO_SPACE(line);
88     }
89
90     i = 0;
91     ++lineno;
92     for (;;)
93     {
94         line[i] = (char)c;
95         if (c == '\n')
96         {
97             cptr = line;
98             return;
99         }
100         if (++i >= linesize)
101         {
102             linesize += LINESIZE;
103             line = REALLOC(line, linesize);
104             NO_SPACE(line);
105         }
106         c = getc(f);
107         if (c == EOF)
108         {
109             line[i] = '\n';
110             saw_eof = 1;
111             cptr = line;
112             return;
113         }
114     }
115 }
116
117 static char *
118 dup_line(void)
119 {
120     char *p, *s, *t;
121
122     if (line == 0)
123         return (0);
124     s = line;
125     while (*s != '\n')
126         ++s;
127     p = MALLOC(s - line + 1);
128     NO_SPACE(p);
129
130     s = line;
131     t = p;
132     while ((*t++ = *s++) != '\n')
133         continue;
134     return (p);
135 }
136
137 static void
138 skip_comment(void)
139 {
140     char *s;
141
142     int st_lineno = lineno;
143     char *st_line = dup_line();
144     char *st_cptr = st_line + (cptr - line);
145
146     s = cptr + 2;
147     for (;;)
148     {
149         if (*s == '*' && s[1] == '/')
150         {
151             cptr = s + 2;
152             FREE(st_line);
153             return;
154         }
155         if (*s == '\n')
156         {
157             get_line();
158             if (line == 0)
159                 unterminated_comment(st_lineno, st_line, st_cptr);
160             s = cptr;
161         }
162         else
163             ++s;
164     }
165 }
166
167 static int
168 nextc(void)
169 {
170     char *s;
171
172     if (line == 0)
173     {
174         get_line();
175         if (line == 0)
176             return (EOF);
177     }
178
179     s = cptr;
180     for (;;)
181     {
182         switch (*s)
183         {
184         case '\n':
185             get_line();
186             if (line == 0)
187                 return (EOF);
188             s = cptr;
189             break;
190
191         case ' ':
192         case '\t':
193         case '\f':
194         case '\r':
195         case '\v':
196         case ',':
197         case ';':
198             ++s;
199             break;
200
201         case '\\':
202             cptr = s;
203             return ('%');
204
205         case '/':
206             if (s[1] == '*')
207             {
208                 cptr = s;
209                 skip_comment();
210                 s = cptr;
211                 break;
212             }
213             else if (s[1] == '/')
214             {
215                 get_line();
216                 if (line == 0)
217                     return (EOF);
218                 s = cptr;
219                 break;
220             }
221             /* FALLTHRU */
222
223         default:
224             cptr = s;
225             return (*s);
226         }
227     }
228 }
229
230 /*
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 = MALLOC(linesize);
688     NO_SPACE(buf);
689
690     for (i = 0; (c = *cptr++) != '}'; i++)
691     {
692         if (c == EOF)
693             unexpected_EOF();
694         buf[i] = (char)c;
695     }
696
697     if (i == 0)
698         goto out;
699
700     buf[i--] = '\0';
701     while (i >= 0 && isspace(UCH(buf[i])))
702         buf[i--] = '\0';
703
704     if (buf[i] == ']')
705     {
706         int level = 1;
707         while (i >= 0 && level > 0 && buf[i] != '[')
708         {
709             if (buf[i] == ']')
710                 ++level;
711             else if (buf[i] == '[')
712                 --level;
713             i--;
714         }
715         if (i <= 0)
716             unexpected_EOF();
717         type2 = i--;
718     }
719     else
720     {
721         type2 = i + 1;
722     }
723
724     while (i >= 0 && (isalnum(UCH(buf[i])) ||
725                       UCH(buf[i]) == '_'))
726         i--;
727
728     if (!isspace(UCH(buf[i])) && buf[i] != '*')
729         goto out;
730
731     name = i + 1;
732
733     p = MALLOC(sizeof(*p));
734     NO_SPACE(p);
735
736     p->type2 = strdup(buf + type2);
737     NO_SPACE(p->type2);
738
739     buf[type2] = '\0';
740
741     p->name = strdup(buf + name);
742     NO_SPACE(p->name);
743
744     buf[name] = '\0';
745     p->type = buf;
746
747     if (k == LEX_PARAM)
748         head = lex_param;
749     else
750         head = parse_param;
751
752     if (head != NULL)
753     {
754         while (head->next)
755             head = head->next;
756         head->next = p;
757     }
758     else
759     {
760         if (k == LEX_PARAM)
761             lex_param = p;
762         else
763             parse_param = p;
764     }
765     p->next = NULL;
766     return;
767
768   out:
769     syntax_error(lineno, line, cptr);
770 }
771
772 static int
773 hexval(int c)
774 {
775     if (c >= '0' && c <= '9')
776         return (c - '0');
777     if (c >= 'A' && c <= 'F')
778         return (c - 'A' + 10);
779     if (c >= 'a' && c <= 'f')
780         return (c - 'a' + 10);
781     return (-1);
782 }
783
784 static bucket *
785 get_literal(void)
786 {
787     int c, quote;
788     int i;
789     int n;
790     char *s;
791     bucket *bp;
792     int s_lineno = lineno;
793     char *s_line = dup_line();
794     char *s_cptr = s_line + (cptr - line);
795
796     quote = *cptr++;
797     cinc = 0;
798     for (;;)
799     {
800         c = *cptr++;
801         if (c == quote)
802             break;
803         if (c == '\n')
804             unterminated_string(s_lineno, s_line, s_cptr);
805         if (c == '\\')
806         {
807             char *c_cptr = cptr - 1;
808
809             c = *cptr++;
810             switch (c)
811             {
812             case '\n':
813                 get_line();
814                 if (line == 0)
815                     unterminated_string(s_lineno, s_line, s_cptr);
816                 continue;
817
818             case '0':
819             case '1':
820             case '2':
821             case '3':
822             case '4':
823             case '5':
824             case '6':
825             case '7':
826                 n = c - '0';
827                 c = *cptr;
828                 if (IS_OCTAL(c))
829                 {
830                     n = (n << 3) + (c - '0');
831                     c = *++cptr;
832                     if (IS_OCTAL(c))
833                     {
834                         n = (n << 3) + (c - '0');
835                         ++cptr;
836                     }
837                 }
838                 if (n > MAXCHAR)
839                     illegal_character(c_cptr);
840                 c = n;
841                 break;
842
843             case 'x':
844                 c = *cptr++;
845                 n = hexval(c);
846                 if (n < 0 || n >= 16)
847                     illegal_character(c_cptr);
848                 for (;;)
849                 {
850                     c = *cptr;
851                     i = hexval(c);
852                     if (i < 0 || i >= 16)
853                         break;
854                     ++cptr;
855                     n = (n << 4) + i;
856                     if (n > MAXCHAR)
857                         illegal_character(c_cptr);
858                 }
859                 c = n;
860                 break;
861
862             case 'a':
863                 c = 7;
864                 break;
865             case 'b':
866                 c = '\b';
867                 break;
868             case 'f':
869                 c = '\f';
870                 break;
871             case 'n':
872                 c = '\n';
873                 break;
874             case 'r':
875                 c = '\r';
876                 break;
877             case 't':
878                 c = '\t';
879                 break;
880             case 'v':
881                 c = '\v';
882                 break;
883             }
884         }
885         cachec(c);
886     }
887     FREE(s_line);
888
889     n = cinc;
890     s = MALLOC(n);
891     NO_SPACE(s);
892
893     for (i = 0; i < n; ++i)
894         s[i] = cache[i];
895
896     cinc = 0;
897     if (n == 1)
898         cachec('\'');
899     else
900         cachec('"');
901
902     for (i = 0; i < n; ++i)
903     {
904         c = UCH(s[i]);
905         if (c == '\\' || c == cache[0])
906         {
907             cachec('\\');
908             cachec(c);
909         }
910         else if (isprint(c))
911             cachec(c);
912         else
913         {
914             cachec('\\');
915             switch (c)
916             {
917             case 7:
918                 cachec('a');
919                 break;
920             case '\b':
921                 cachec('b');
922                 break;
923             case '\f':
924                 cachec('f');
925                 break;
926             case '\n':
927                 cachec('n');
928                 break;
929             case '\r':
930                 cachec('r');
931                 break;
932             case '\t':
933                 cachec('t');
934                 break;
935             case '\v':
936                 cachec('v');
937                 break;
938             default:
939                 cachec(((c >> 6) & 7) + '0');
940                 cachec(((c >> 3) & 7) + '0');
941                 cachec((c & 7) + '0');
942                 break;
943             }
944         }
945     }
946
947     if (n == 1)
948         cachec('\'');
949     else
950         cachec('"');
951
952     cachec(NUL);
953     bp = lookup(cache);
954     bp->class = TERM;
955     if (n == 1 && bp->value == UNDEFINED)
956         bp->value = UCH(*s);
957     FREE(s);
958
959     return (bp);
960 }
961
962 static int
963 is_reserved(char *name)
964 {
965     char *s;
966
967     if (strcmp(name, ".") == 0 ||
968         strcmp(name, "$accept") == 0 ||
969         strcmp(name, "$end") == 0)
970         return (1);
971
972     if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
973     {
974         s = name + 3;
975         while (isdigit(UCH(*s)))
976             ++s;
977         if (*s == NUL)
978             return (1);
979     }
980
981     return (0);
982 }
983
984 static bucket *
985 get_name(void)
986 {
987     int c;
988
989     cinc = 0;
990     for (c = *cptr; IS_IDENT(c); c = *++cptr)
991         cachec(c);
992     cachec(NUL);
993
994     if (is_reserved(cache))
995         used_reserved(cache);
996
997     return (lookup(cache));
998 }
999
1000 static Value_t
1001 get_number(void)
1002 {
1003     int c;
1004     Value_t n;
1005
1006     n = 0;
1007     for (c = *cptr; isdigit(c); c = *++cptr)
1008         n = (Value_t) (10 * n + (c - '0'));
1009
1010     return (n);
1011 }
1012
1013 static char *
1014 get_tag(void)
1015 {
1016     int c;
1017     int i;
1018     char *s;
1019     int t_lineno = lineno;
1020     char *t_line = dup_line();
1021     char *t_cptr = t_line + (cptr - line);
1022
1023     ++cptr;
1024     c = nextc();
1025     if (c == EOF)
1026         unexpected_EOF();
1027     if (!isalpha(c) && c != '_' && c != '$')
1028         illegal_tag(t_lineno, t_line, t_cptr);
1029
1030     cinc = 0;
1031     do
1032     {
1033         cachec(c);
1034         c = *++cptr;
1035     }
1036     while (IS_IDENT(c));
1037     cachec(NUL);
1038
1039     c = nextc();
1040     if (c == EOF)
1041         unexpected_EOF();
1042     if (c != '>')
1043         illegal_tag(t_lineno, t_line, t_cptr);
1044     ++cptr;
1045
1046     for (i = 0; i < ntags; ++i)
1047     {
1048         if (strcmp(cache, tag_table[i]) == 0)
1049         {
1050             FREE(t_line);
1051             return (tag_table[i]);
1052         }
1053     }
1054
1055     if (ntags >= tagmax)
1056     {
1057         tagmax += 16;
1058         tag_table = (char **)
1059             (tag_table
1060              ? REALLOC(tag_table, (unsigned)tagmax * sizeof(char *))
1061              : MALLOC((unsigned)tagmax * sizeof(char *)));
1062         NO_SPACE(tag_table);
1063     }
1064
1065     s = MALLOC(cinc);
1066     NO_SPACE(s);
1067
1068     strcpy(s, cache);
1069     tag_table[ntags] = s;
1070     ++ntags;
1071     FREE(t_line);
1072     return (s);
1073 }
1074
1075 static void
1076 declare_tokens(int assoc)
1077 {
1078     int c;
1079     bucket *bp;
1080     Value_t value;
1081     char *tag = 0;
1082
1083     if (assoc != TOKEN)
1084         ++prec;
1085
1086     c = nextc();
1087     if (c == EOF)
1088         unexpected_EOF();
1089     if (c == '<')
1090     {
1091         tag = get_tag();
1092         c = nextc();
1093         if (c == EOF)
1094             unexpected_EOF();
1095     }
1096
1097     for (;;)
1098     {
1099         if (isalpha(c) || c == '_' || c == '.' || c == '$')
1100             bp = get_name();
1101         else if (c == '\'' || c == '"')
1102             bp = get_literal();
1103         else
1104             return;
1105
1106         if (bp == goal)
1107             tokenized_start(bp->name);
1108         bp->class = TERM;
1109
1110         if (tag)
1111         {
1112             if (bp->tag && tag != bp->tag)
1113                 retyped_warning(bp->name);
1114             bp->tag = tag;
1115         }
1116
1117         if (assoc != TOKEN)
1118         {
1119             if (bp->prec && prec != bp->prec)
1120                 reprec_warning(bp->name);
1121             bp->assoc = (Assoc_t) assoc;
1122             bp->prec = prec;
1123         }
1124
1125         c = nextc();
1126         if (c == EOF)
1127             unexpected_EOF();
1128
1129         if (isdigit(c))
1130         {
1131             value = get_number();
1132             if (bp->value != UNDEFINED && value != bp->value)
1133                 revalued_warning(bp->name);
1134             bp->value = value;
1135             c = nextc();
1136             if (c == EOF)
1137                 unexpected_EOF();
1138         }
1139     }
1140 }
1141
1142 /*
1143  * %expect requires special handling
1144  * as it really isn't part of the yacc
1145  * grammar only a flag for yacc proper.
1146  */
1147 static void
1148 declare_expect(int assoc)
1149 {
1150     int c;
1151
1152     if (assoc != EXPECT && assoc != EXPECT_RR)
1153         ++prec;
1154
1155     /*
1156      * Stay away from nextc - doesn't
1157      * detect EOL and will read to EOF.
1158      */
1159     c = *++cptr;
1160     if (c == EOF)
1161         unexpected_EOF();
1162
1163     for (;;)
1164     {
1165         if (isdigit(c))
1166         {
1167             if (assoc == EXPECT)
1168                 SRexpect = get_number();
1169             else
1170                 RRexpect = get_number();
1171             break;
1172         }
1173         /*
1174          * Looking for number before EOL.
1175          * Spaces, tabs, and numbers are ok,
1176          * words, punc., etc. are syntax errors.
1177          */
1178         else if (c == '\n' || isalpha(c) || !isspace(c))
1179         {
1180             syntax_error(lineno, line, cptr);
1181         }
1182         else
1183         {
1184             c = *++cptr;
1185             if (c == EOF)
1186                 unexpected_EOF();
1187         }
1188     }
1189 }
1190
1191 static void
1192 declare_types(void)
1193 {
1194     int c;
1195     bucket *bp;
1196     char *tag;
1197
1198     c = nextc();
1199     if (c == EOF)
1200         unexpected_EOF();
1201     if (c != '<')
1202         syntax_error(lineno, line, cptr);
1203     tag = get_tag();
1204
1205     for (;;)
1206     {
1207         c = nextc();
1208         if (isalpha(c) || c == '_' || c == '.' || c == '$')
1209             bp = get_name();
1210         else if (c == '\'' || c == '"')
1211             bp = get_literal();
1212         else
1213             return;
1214
1215         if (bp->tag && tag != bp->tag)
1216             retyped_warning(bp->name);
1217         bp->tag = tag;
1218     }
1219 }
1220
1221 static void
1222 declare_start(void)
1223 {
1224     int c;
1225     bucket *bp;
1226
1227     c = nextc();
1228     if (c == EOF)
1229         unexpected_EOF();
1230     if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1231         syntax_error(lineno, line, cptr);
1232     bp = get_name();
1233     if (bp->class == TERM)
1234         terminal_start(bp->name);
1235     if (goal && goal != bp)
1236         restarted_warning();
1237     goal = bp;
1238 }
1239
1240 static void
1241 read_declarations(void)
1242 {
1243     int c, k;
1244
1245     cache_size = 256;
1246     cache = MALLOC(cache_size);
1247     NO_SPACE(cache);
1248
1249     for (;;)
1250     {
1251         c = nextc();
1252         if (c == EOF)
1253             unexpected_EOF();
1254         if (c != '%')
1255             syntax_error(lineno, line, cptr);
1256         switch (k = keyword())
1257         {
1258         case MARK:
1259             return;
1260
1261         case IDENT:
1262             copy_ident();
1263             break;
1264
1265         case TEXT:
1266             copy_text();
1267             break;
1268
1269         case UNION:
1270             copy_union();
1271             break;
1272
1273         case TOKEN:
1274         case LEFT:
1275         case RIGHT:
1276         case NONASSOC:
1277             declare_tokens(k);
1278             break;
1279
1280         case EXPECT:
1281         case EXPECT_RR:
1282             declare_expect(k);
1283             break;
1284
1285         case TYPE:
1286             declare_types();
1287             break;
1288
1289         case START:
1290             declare_start();
1291             break;
1292
1293         case PURE_PARSER:
1294             pure_parser = 1;
1295             break;
1296
1297         case PARSE_PARAM:
1298         case LEX_PARAM:
1299             copy_param(k);
1300             break;
1301
1302         case POSIX_YACC:
1303             /* noop for bison compatibility. byacc is already designed to be posix
1304              * yacc compatible. */
1305             break;
1306         }
1307     }
1308 }
1309
1310 static void
1311 initialize_grammar(void)
1312 {
1313     nitems = 4;
1314     maxitems = 300;
1315
1316     pitem = (bucket **)MALLOC((unsigned)maxitems * sizeof(bucket *));
1317     NO_SPACE(pitem);
1318
1319     pitem[0] = 0;
1320     pitem[1] = 0;
1321     pitem[2] = 0;
1322     pitem[3] = 0;
1323
1324     nrules = 3;
1325     maxrules = 100;
1326
1327     plhs = (bucket **)MALLOC((unsigned)maxrules * sizeof(bucket *));
1328     NO_SPACE(plhs);
1329
1330     plhs[0] = 0;
1331     plhs[1] = 0;
1332     plhs[2] = 0;
1333
1334     rprec = (short *)MALLOC((unsigned)maxrules * sizeof(short));
1335     NO_SPACE(rprec);
1336
1337     rprec[0] = 0;
1338     rprec[1] = 0;
1339     rprec[2] = 0;
1340
1341     rassoc = (char *)MALLOC((unsigned)maxrules * sizeof(char));
1342     NO_SPACE(rassoc);
1343
1344     rassoc[0] = TOKEN;
1345     rassoc[1] = TOKEN;
1346     rassoc[2] = TOKEN;
1347 }
1348
1349 static void
1350 expand_items(void)
1351 {
1352     maxitems += 300;
1353     pitem = (bucket **)REALLOC(pitem, (unsigned)maxitems * sizeof(bucket *));
1354     NO_SPACE(pitem);
1355 }
1356
1357 static void
1358 expand_rules(void)
1359 {
1360     maxrules += 100;
1361
1362     plhs = (bucket **)REALLOC(plhs, (unsigned)maxrules * sizeof(bucket *));
1363     NO_SPACE(plhs);
1364
1365     rprec = (short *)REALLOC(rprec, (unsigned)maxrules * sizeof(short));
1366     NO_SPACE(rprec);
1367
1368     rassoc = (char *)REALLOC(rassoc, (unsigned)maxrules * sizeof(char));
1369     NO_SPACE(rassoc);
1370 }
1371
1372 static void
1373 advance_to_start(void)
1374 {
1375     int c;
1376     bucket *bp;
1377     char *s_cptr;
1378     int s_lineno;
1379
1380     for (;;)
1381     {
1382         c = nextc();
1383         if (c != '%')
1384             break;
1385         s_cptr = cptr;
1386         switch (keyword())
1387         {
1388         case MARK:
1389             no_grammar();
1390
1391         case TEXT:
1392             copy_text();
1393             break;
1394
1395         case START:
1396             declare_start();
1397             break;
1398
1399         default:
1400             syntax_error(lineno, line, s_cptr);
1401         }
1402     }
1403
1404     c = nextc();
1405     if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1406         syntax_error(lineno, line, cptr);
1407     bp = get_name();
1408     if (goal == 0)
1409     {
1410         if (bp->class == TERM)
1411             terminal_start(bp->name);
1412         goal = bp;
1413     }
1414
1415     s_lineno = lineno;
1416     c = nextc();
1417     if (c == EOF)
1418         unexpected_EOF();
1419     if (c != ':')
1420         syntax_error(lineno, line, cptr);
1421     start_rule(bp, s_lineno);
1422     ++cptr;
1423 }
1424
1425 static void
1426 start_rule(bucket *bp, int s_lineno)
1427 {
1428     if (bp->class == TERM)
1429         terminal_lhs(s_lineno);
1430     bp->class = NONTERM;
1431     if (nrules >= maxrules)
1432         expand_rules();
1433     plhs[nrules] = bp;
1434     rprec[nrules] = UNDEFINED;
1435     rassoc[nrules] = TOKEN;
1436 }
1437
1438 static void
1439 end_rule(void)
1440 {
1441     int i;
1442
1443     if (!last_was_action && plhs[nrules]->tag)
1444     {
1445         if (pitem[nitems - 1])
1446         {
1447             for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1448                 continue;
1449             if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1450                 default_action_warning();
1451         }
1452         else
1453         {
1454             default_action_warning();
1455         }
1456     }
1457
1458     last_was_action = 0;
1459     if (nitems >= maxitems)
1460         expand_items();
1461     pitem[nitems] = 0;
1462     ++nitems;
1463     ++nrules;
1464 }
1465
1466 static void
1467 insert_empty_rule(void)
1468 {
1469     bucket *bp, **bpp;
1470
1471     assert(cache);
1472     sprintf(cache, "$$%d", ++gensym);
1473     bp = make_bucket(cache);
1474     last_symbol->next = bp;
1475     last_symbol = bp;
1476     bp->tag = plhs[nrules]->tag;
1477     bp->class = NONTERM;
1478
1479     if ((nitems += 2) > maxitems)
1480         expand_items();
1481     bpp = pitem + nitems - 1;
1482     *bpp-- = bp;
1483     while ((bpp[0] = bpp[-1]) != 0)
1484         --bpp;
1485
1486     if (++nrules >= maxrules)
1487         expand_rules();
1488     plhs[nrules] = plhs[nrules - 1];
1489     plhs[nrules - 1] = bp;
1490     rprec[nrules] = rprec[nrules - 1];
1491     rprec[nrules - 1] = 0;
1492     rassoc[nrules] = rassoc[nrules - 1];
1493     rassoc[nrules - 1] = TOKEN;
1494 }
1495
1496 static void
1497 add_symbol(void)
1498 {
1499     int c;
1500     bucket *bp;
1501     int s_lineno = lineno;
1502
1503     c = *cptr;
1504     if (c == '\'' || c == '"')
1505         bp = get_literal();
1506     else
1507         bp = get_name();
1508
1509     c = nextc();
1510     if (c == ':')
1511     {
1512         end_rule();
1513         start_rule(bp, s_lineno);
1514         ++cptr;
1515         return;
1516     }
1517
1518     if (last_was_action)
1519         insert_empty_rule();
1520     last_was_action = 0;
1521
1522     if (++nitems > maxitems)
1523         expand_items();
1524     pitem[nitems - 1] = bp;
1525 }
1526
1527 static char *
1528 after_blanks(char *s)
1529 {
1530     while (*s != '\0' && isspace(UCH(*s)))
1531         ++s;
1532     return s;
1533 }
1534
1535 static void
1536 copy_action(void)
1537 {
1538     int c;
1539     int i, n;
1540     int depth;
1541     int quote;
1542     char *tag;
1543     FILE *f = action_file;
1544     int a_lineno = lineno;
1545     char *a_line = dup_line();
1546     char *a_cptr = a_line + (cptr - line);
1547
1548     if (last_was_action)
1549         insert_empty_rule();
1550     last_was_action = 1;
1551
1552     fprintf(f, "case %d:\n", nrules - 2);
1553     if (!lflag)
1554         fprintf(f, line_format, lineno, input_file_name);
1555     if (*cptr == '=')
1556         ++cptr;
1557
1558     /* avoid putting curly-braces in first column, to ease editing */
1559     if (*after_blanks(cptr) == L_CURL)
1560     {
1561         putc('\t', f);
1562         cptr = after_blanks(cptr);
1563     }
1564
1565     n = 0;
1566     for (i = nitems - 1; pitem[i]; --i)
1567         ++n;
1568
1569     depth = 0;
1570   loop:
1571     c = *cptr;
1572     if (c == '$')
1573     {
1574         if (cptr[1] == '<')
1575         {
1576             int d_lineno = lineno;
1577             char *d_line = dup_line();
1578             char *d_cptr = d_line + (cptr - line);
1579
1580             ++cptr;
1581             tag = get_tag();
1582             c = *cptr;
1583             if (c == '$')
1584             {
1585                 fprintf(f, "yyval.%s", tag);
1586                 ++cptr;
1587                 FREE(d_line);
1588                 goto loop;
1589             }
1590             else if (isdigit(c))
1591             {
1592                 i = get_number();
1593                 if (i > n)
1594                     dollar_warning(d_lineno, i);
1595                 fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1596                 FREE(d_line);
1597                 goto loop;
1598             }
1599             else if (c == '-' && isdigit(UCH(cptr[1])))
1600             {
1601                 ++cptr;
1602                 i = -get_number() - n;
1603                 fprintf(f, "yystack.l_mark[%d].%s", i, tag);
1604                 FREE(d_line);
1605                 goto loop;
1606             }
1607             else
1608                 dollar_error(d_lineno, d_line, d_cptr);
1609         }
1610         else if (cptr[1] == '$')
1611         {
1612             if (ntags)
1613             {
1614                 tag = plhs[nrules]->tag;
1615                 if (tag == 0)
1616                     untyped_lhs();
1617                 fprintf(f, "yyval.%s", tag);
1618             }
1619             else
1620                 fprintf(f, "yyval");
1621             cptr += 2;
1622             goto loop;
1623         }
1624         else if (isdigit(UCH(cptr[1])))
1625         {
1626             ++cptr;
1627             i = get_number();
1628             if (ntags)
1629             {
1630                 if (i <= 0 || i > n)
1631                     unknown_rhs(i);
1632                 tag = pitem[nitems + i - n - 1]->tag;
1633                 if (tag == 0)
1634                     untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1635                 fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1636             }
1637             else
1638             {
1639                 if (i > n)
1640                     dollar_warning(lineno, i);
1641                 fprintf(f, "yystack.l_mark[%d]", i - n);
1642             }
1643             goto loop;
1644         }
1645         else if (cptr[1] == '-')
1646         {
1647             cptr += 2;
1648             i = get_number();
1649             if (ntags)
1650                 unknown_rhs(-i);
1651             fprintf(f, "yystack.l_mark[%d]", -i - n);
1652             goto loop;
1653         }
1654     }
1655     if (isalpha(c) || c == '_' || c == '$')
1656     {
1657         do
1658         {
1659             putc(c, f);
1660             c = *++cptr;
1661         }
1662         while (isalnum(c) || c == '_' || c == '$');
1663         goto loop;
1664     }
1665     putc(c, f);
1666     ++cptr;
1667     switch (c)
1668     {
1669     case '\n':
1670       next_line:
1671         get_line();
1672         if (line)
1673             goto loop;
1674         unterminated_action(a_lineno, a_line, a_cptr);
1675
1676     case ';':
1677         if (depth > 0)
1678             goto loop;
1679         fprintf(f, "\nbreak;\n");
1680         free(a_line);
1681         return;
1682
1683     case L_CURL:
1684         ++depth;
1685         goto loop;
1686
1687     case R_CURL:
1688         if (--depth > 0)
1689             goto loop;
1690         fprintf(f, "\nbreak;\n");
1691         free(a_line);
1692         return;
1693
1694     case '\'':
1695     case '"':
1696         {
1697             int s_lineno = lineno;
1698             char *s_line = dup_line();
1699             char *s_cptr = s_line + (cptr - line - 1);
1700
1701             quote = c;
1702             for (;;)
1703             {
1704                 c = *cptr++;
1705                 putc(c, f);
1706                 if (c == quote)
1707                 {
1708                     FREE(s_line);
1709                     goto loop;
1710                 }
1711                 if (c == '\n')
1712                     unterminated_string(s_lineno, s_line, s_cptr);
1713                 if (c == '\\')
1714                 {
1715                     c = *cptr++;
1716                     putc(c, f);
1717                     if (c == '\n')
1718                     {
1719                         get_line();
1720                         if (line == 0)
1721                             unterminated_string(s_lineno, s_line, s_cptr);
1722                     }
1723                 }
1724             }
1725         }
1726
1727     case '/':
1728         c = *cptr;
1729         if (c == '/')
1730         {
1731             putc('*', f);
1732             while ((c = *++cptr) != '\n')
1733             {
1734                 if (c == '*' && cptr[1] == '/')
1735                     fprintf(f, "* ");
1736                 else
1737                     putc(c, f);
1738             }
1739             fprintf(f, "*/\n");
1740             goto next_line;
1741         }
1742         if (c == '*')
1743         {
1744             int c_lineno = lineno;
1745             char *c_line = dup_line();
1746             char *c_cptr = c_line + (cptr - line - 1);
1747
1748             putc('*', f);
1749             ++cptr;
1750             for (;;)
1751             {
1752                 c = *cptr++;
1753                 putc(c, f);
1754                 if (c == '*' && *cptr == '/')
1755                 {
1756                     putc('/', f);
1757                     ++cptr;
1758                     FREE(c_line);
1759                     goto loop;
1760                 }
1761                 if (c == '\n')
1762                 {
1763                     get_line();
1764                     if (line == 0)
1765                         unterminated_comment(c_lineno, c_line, c_cptr);
1766                 }
1767             }
1768         }
1769         goto loop;
1770
1771     default:
1772         goto loop;
1773     }
1774 }
1775
1776 static int
1777 mark_symbol(void)
1778 {
1779     int c;
1780     bucket *bp;
1781
1782     c = cptr[1];
1783     if (c == '%' || c == '\\')
1784     {
1785         cptr += 2;
1786         return (1);
1787     }
1788
1789     if (c == '=')
1790         cptr += 2;
1791     else if ((c == 'p' || c == 'P') &&
1792              ((c = cptr[2]) == 'r' || c == 'R') &&
1793              ((c = cptr[3]) == 'e' || c == 'E') &&
1794              ((c = cptr[4]) == 'c' || c == 'C') &&
1795              ((c = cptr[5], !IS_IDENT(c))))
1796         cptr += 5;
1797     else
1798         syntax_error(lineno, line, cptr);
1799
1800     c = nextc();
1801     if (isalpha(c) || c == '_' || c == '.' || c == '$')
1802         bp = get_name();
1803     else if (c == '\'' || c == '"')
1804         bp = get_literal();
1805     else
1806     {
1807         syntax_error(lineno, line, cptr);
1808         /*NOTREACHED */
1809     }
1810
1811     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1812         prec_redeclared();
1813
1814     rprec[nrules] = bp->prec;
1815     rassoc[nrules] = bp->assoc;
1816     return (0);
1817 }
1818
1819 static void
1820 read_grammar(void)
1821 {
1822     int c;
1823
1824     initialize_grammar();
1825     advance_to_start();
1826
1827     for (;;)
1828     {
1829         c = nextc();
1830         if (c == EOF)
1831             break;
1832         if (isalpha(c)
1833             || c == '_'
1834             || c == '.'
1835             || c == '$'
1836             || c == '\''
1837             || c == '"')
1838             add_symbol();
1839         else if (c == L_CURL || c == '=')
1840             copy_action();
1841         else if (c == '|')
1842         {
1843             end_rule();
1844             start_rule(plhs[nrules - 1], 0);
1845             ++cptr;
1846         }
1847         else if (c == '%')
1848         {
1849             if (mark_symbol())
1850                 break;
1851         }
1852         else
1853             syntax_error(lineno, line, cptr);
1854     }
1855     end_rule();
1856 }
1857
1858 static void
1859 free_tags(void)
1860 {
1861     int i;
1862
1863     if (tag_table == 0)
1864         return;
1865
1866     for (i = 0; i < ntags; ++i)
1867     {
1868         assert(tag_table[i]);
1869         FREE(tag_table[i]);
1870     }
1871     FREE(tag_table);
1872 }
1873
1874 static void
1875 pack_names(void)
1876 {
1877     bucket *bp;
1878     char *p, *s, *t;
1879
1880     name_pool_size = 13;        /* 13 == sizeof("$end") + sizeof("$accept") */
1881     for (bp = first_symbol; bp; bp = bp->next)
1882         name_pool_size += strlen(bp->name) + 1;
1883
1884     name_pool = MALLOC(name_pool_size);
1885     NO_SPACE(name_pool);
1886
1887     strcpy(name_pool, "$accept");
1888     strcpy(name_pool + 8, "$end");
1889     t = name_pool + 13;
1890     for (bp = first_symbol; bp; bp = bp->next)
1891     {
1892         p = t;
1893         s = bp->name;
1894         while ((*t++ = *s++) != 0)
1895             continue;
1896         FREE(bp->name);
1897         bp->name = p;
1898     }
1899 }
1900
1901 static void
1902 check_symbols(void)
1903 {
1904     bucket *bp;
1905
1906     if (goal->class == UNKNOWN)
1907         undefined_goal(goal->name);
1908
1909     for (bp = first_symbol; bp; bp = bp->next)
1910     {
1911         if (bp->class == UNKNOWN)
1912         {
1913             undefined_symbol_warning(bp->name);
1914             bp->class = TERM;
1915         }
1916     }
1917 }
1918
1919 static void
1920 protect_string(char *src, char **des)
1921 {
1922     unsigned len;
1923     char *s;
1924     char *d;
1925
1926     *des = src;
1927     if (src)
1928     {
1929         len = 1;
1930         s = src;
1931         while (*s)
1932         {
1933             if ('\\' == *s || '"' == *s)
1934                 len++;
1935             s++;
1936             len++;
1937         }
1938
1939         *des = d = (char *)MALLOC(len);
1940         NO_SPACE(d);
1941
1942         s = src;
1943         while (*s)
1944         {
1945             if ('\\' == *s || '"' == *s)
1946                 *d++ = '\\';
1947             *d++ = *s++;
1948         }
1949         *d = '\0';
1950     }
1951 }
1952
1953 static void
1954 pack_symbols(void)
1955 {
1956     bucket *bp;
1957     bucket **v;
1958     Value_t i, j, k, n;
1959
1960     nsyms = 2;
1961     ntokens = 1;
1962     for (bp = first_symbol; bp; bp = bp->next)
1963     {
1964         ++nsyms;
1965         if (bp->class == TERM)
1966             ++ntokens;
1967     }
1968     start_symbol = (Value_t) ntokens;
1969     nvars = nsyms - ntokens;
1970
1971     symbol_name = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
1972     NO_SPACE(symbol_name);
1973
1974     symbol_value = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1975     NO_SPACE(symbol_value);
1976
1977     symbol_prec = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1978     NO_SPACE(symbol_prec);
1979
1980     symbol_assoc = MALLOC(nsyms);
1981     NO_SPACE(symbol_assoc);
1982
1983     v = (bucket **)MALLOC((unsigned)nsyms * sizeof(bucket *));
1984     NO_SPACE(v);
1985
1986     v[0] = 0;
1987     v[start_symbol] = 0;
1988
1989     i = 1;
1990     j = (Value_t) (start_symbol + 1);
1991     for (bp = first_symbol; bp; bp = bp->next)
1992     {
1993         if (bp->class == TERM)
1994             v[i++] = bp;
1995         else
1996             v[j++] = bp;
1997     }
1998     assert(i == ntokens && j == nsyms);
1999
2000     for (i = 1; i < ntokens; ++i)
2001         v[i]->index = i;
2002
2003     goal->index = (Index_t) (start_symbol + 1);
2004     k = (Value_t) (start_symbol + 2);
2005     while (++i < nsyms)
2006         if (v[i] != goal)
2007         {
2008             v[i]->index = k;
2009             ++k;
2010         }
2011
2012     goal->value = 0;
2013     k = 1;
2014     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2015     {
2016         if (v[i] != goal)
2017         {
2018             v[i]->value = k;
2019             ++k;
2020         }
2021     }
2022
2023     k = 0;
2024     for (i = 1; i < ntokens; ++i)
2025     {
2026         n = v[i]->value;
2027         if (n > 256)
2028         {
2029             for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2030                 symbol_value[j] = symbol_value[j - 1];
2031             symbol_value[j] = n;
2032         }
2033     }
2034
2035     assert(v[1] != 0);
2036
2037     if (v[1]->value == UNDEFINED)
2038         v[1]->value = 256;
2039
2040     j = 0;
2041     n = 257;
2042     for (i = 2; i < ntokens; ++i)
2043     {
2044         if (v[i]->value == UNDEFINED)
2045         {
2046             while (j < k && n == symbol_value[j])
2047             {
2048                 while (++j < k && n == symbol_value[j])
2049                     continue;
2050                 ++n;
2051             }
2052             v[i]->value = n;
2053             ++n;
2054         }
2055     }
2056
2057     symbol_name[0] = name_pool + 8;
2058     symbol_value[0] = 0;
2059     symbol_prec[0] = 0;
2060     symbol_assoc[0] = TOKEN;
2061     for (i = 1; i < ntokens; ++i)
2062     {
2063         symbol_name[i] = v[i]->name;
2064         symbol_value[i] = v[i]->value;
2065         symbol_prec[i] = v[i]->prec;
2066         symbol_assoc[i] = v[i]->assoc;
2067     }
2068     symbol_name[start_symbol] = name_pool;
2069     symbol_value[start_symbol] = -1;
2070     symbol_prec[start_symbol] = 0;
2071     symbol_assoc[start_symbol] = TOKEN;
2072     for (++i; i < nsyms; ++i)
2073     {
2074         k = v[i]->index;
2075         symbol_name[k] = v[i]->name;
2076         symbol_value[k] = v[i]->value;
2077         symbol_prec[k] = v[i]->prec;
2078         symbol_assoc[k] = v[i]->assoc;
2079     }
2080
2081     if (gflag)
2082     {
2083         symbol_pname = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
2084         NO_SPACE(symbol_pname);
2085
2086         for (i = 0; i < nsyms; ++i)
2087             protect_string(symbol_name[i], &(symbol_pname[i]));
2088     }
2089
2090     FREE(v);
2091 }
2092
2093 static void
2094 pack_grammar(void)
2095 {
2096     int i;
2097     Value_t j;
2098     Assoc_t assoc;
2099     Value_t prec2;
2100
2101     ritem = (short *)MALLOC((unsigned)nitems * sizeof(short));
2102     NO_SPACE(ritem);
2103
2104     rlhs = (short *)MALLOC((unsigned)nrules * sizeof(short));
2105     NO_SPACE(rlhs);
2106
2107     rrhs = (short *)MALLOC((unsigned)(nrules + 1) * sizeof(short));
2108     NO_SPACE(rrhs);
2109
2110     rprec = (short *)REALLOC(rprec, (unsigned)nrules * sizeof(short));
2111     NO_SPACE(rprec);
2112
2113     rassoc = REALLOC(rassoc, nrules);
2114     NO_SPACE(rassoc);
2115
2116     ritem[0] = -1;
2117     ritem[1] = goal->index;
2118     ritem[2] = 0;
2119     ritem[3] = -2;
2120     rlhs[0] = 0;
2121     rlhs[1] = 0;
2122     rlhs[2] = start_symbol;
2123     rrhs[0] = 0;
2124     rrhs[1] = 0;
2125     rrhs[2] = 1;
2126
2127     j = 4;
2128     for (i = 3; i < nrules; ++i)
2129     {
2130         rlhs[i] = plhs[i]->index;
2131         rrhs[i] = j;
2132         assoc = TOKEN;
2133         prec2 = 0;
2134         while (pitem[j])
2135         {
2136             ritem[j] = pitem[j]->index;
2137             if (pitem[j]->class == TERM)
2138             {
2139                 prec2 = pitem[j]->prec;
2140                 assoc = pitem[j]->assoc;
2141             }
2142             ++j;
2143         }
2144         ritem[j] = (Value_t) - i;
2145         ++j;
2146         if (rprec[i] == UNDEFINED)
2147         {
2148             rprec[i] = prec2;
2149             rassoc[i] = assoc;
2150         }
2151     }
2152     rrhs[i] = j;
2153
2154     FREE(plhs);
2155     FREE(pitem);
2156 }
2157
2158 static void
2159 print_grammar(void)
2160 {
2161     int i, k;
2162     size_t j, spacing = 0;
2163     FILE *f = verbose_file;
2164
2165     if (!vflag)
2166         return;
2167
2168     k = 1;
2169     for (i = 2; i < nrules; ++i)
2170     {
2171         if (rlhs[i] != rlhs[i - 1])
2172         {
2173             if (i != 2)
2174                 fprintf(f, "\n");
2175             fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
2176             spacing = strlen(symbol_name[rlhs[i]]) + 1;
2177         }
2178         else
2179         {
2180             fprintf(f, "%4d  ", i - 2);
2181             j = spacing;
2182             while (j-- != 0)
2183                 putc(' ', f);
2184             putc('|', f);
2185         }
2186
2187         while (ritem[k] >= 0)
2188         {
2189             fprintf(f, " %s", symbol_name[ritem[k]]);
2190             ++k;
2191         }
2192         ++k;
2193         putc('\n', f);
2194     }
2195 }
2196
2197 void
2198 reader(void)
2199 {
2200     write_section(banner);
2201     create_symbol_table();
2202     read_declarations();
2203     read_grammar();
2204     free_symbol_table();
2205     free_tags();
2206     pack_names();
2207     check_symbols();
2208     pack_symbols();
2209     pack_grammar();
2210     free_symbols();
2211     print_grammar();
2212 }
2213
2214 #ifdef NO_LEAKS
2215 static param *
2216 free_declarations(param * list)
2217 {
2218     while (list != 0)
2219     {
2220         param *next = list->next;
2221         free(list->type);
2222         free(list->name);
2223         free(list->type2);
2224         free(list);
2225         list = next;
2226     }
2227     return list;
2228 }
2229
2230 void
2231 reader_leaks(void)
2232 {
2233     lex_param = free_declarations(lex_param);
2234     parse_param = free_declarations(parse_param);
2235
2236     DO_FREE(line);
2237     DO_FREE(rrhs);
2238     DO_FREE(rlhs);
2239     DO_FREE(rprec);
2240     DO_FREE(ritem);
2241     DO_FREE(rassoc);
2242     DO_FREE(cache);
2243     DO_FREE(name_pool);
2244     DO_FREE(symbol_name);
2245     DO_FREE(symbol_prec);
2246     DO_FREE(symbol_assoc);
2247     DO_FREE(symbol_value);
2248 }
2249 #endif