Imported Upstream version 20140409
[platform/upstream/byacc.git] / reader.c
1 /* $Id: reader.c,v 1.47 2014/04/09 21:09:27 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 #define L_PAREN '('
15 #define R_PAREN ')'
16 #define L_BRAC  '['
17 #define R_BRAC  ']'
18
19 /* the maximum number of arguments (inherited attributes) to a non-terminal */
20 /* this is a hard limit, but seems more than adequate */
21 #define MAXARGS 20
22
23 static void start_rule(bucket *bp, int s_lineno);
24 #if defined(YYBTYACC)
25 static void copy_destructor(void);
26 static char *process_destructor_XX(char *code, char *tag);
27 #endif
28
29 static char *cache;
30 static int cinc, cache_size;
31
32 int ntags;
33 static int tagmax, havetags;
34 static char **tag_table;
35
36 static char saw_eof;
37 char unionized;
38 char *cptr, *line;
39 static int linesize;
40
41 static bucket *goal;
42 static Value_t prec;
43 static int gensym;
44 static char last_was_action;
45
46 static int maxitems;
47 static bucket **pitem;
48
49 static int maxrules;
50 static bucket **plhs;
51
52 static size_t name_pool_size;
53 static char *name_pool;
54
55 char line_format[] = "#line %d \"%s\"\n";
56
57 param *lex_param;
58 param *parse_param;
59
60 #if defined(YYBTYACC)
61 int destructor = 0;     /* =1 if at least one %destructor */
62
63 static bucket *default_destructor[3] =
64 {0, 0, 0};
65
66 #define UNTYPED_DEFAULT 0
67 #define TYPED_DEFAULT   1
68 #define TYPE_SPECIFIED  2
69
70 static bucket *
71 lookup_type_destructor(char *tag)
72 {
73     char name[1024] = "\0";
74     bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED];
75
76     while ((bp = *bpp) != NULL)
77     {
78         if (bp->tag == tag)
79             return (bp);
80         bpp = &bp->link;
81     }
82
83     *bpp = bp = make_bucket(strcat(strcpy(name, tag), " destructor"));
84     bp->tag = tag;
85
86     return (bp);
87 }
88 #endif /* defined(YYBTYACC) */
89
90 static void
91 cachec(int c)
92 {
93     assert(cinc >= 0);
94     if (cinc >= cache_size)
95     {
96         cache_size += 256;
97         cache = TREALLOC(char, cache, cache_size);
98         NO_SPACE(cache);
99     }
100     cache[cinc] = (char)c;
101     ++cinc;
102 }
103
104 static void
105 get_line(void)
106 {
107     FILE *f = input_file;
108     int c;
109     int i;
110
111     if (saw_eof || (c = getc(f)) == EOF)
112     {
113         if (line)
114         {
115             FREE(line);
116             line = 0;
117         }
118         cptr = 0;
119         saw_eof = 1;
120         return;
121     }
122
123     if (line == 0 || linesize != (LINESIZE + 1))
124     {
125         if (line)
126             FREE(line);
127         linesize = LINESIZE + 1;
128         line = TMALLOC(char, linesize);
129         NO_SPACE(line);
130     }
131
132     i = 0;
133     ++lineno;
134     for (;;)
135     {
136         line[i] = (char)c;
137         if (c == '\n')
138             break;
139         if (++i >= linesize)
140         {
141             linesize += LINESIZE;
142             line = TREALLOC(char, line, linesize);
143             NO_SPACE(line);
144         }
145         c = getc(f);
146         if (c == EOF)
147         {
148             line[i] = '\n';
149             saw_eof = 1;
150             break;
151         }
152     }
153     cptr = line;
154     return;
155 }
156
157 static char *
158 dup_line(void)
159 {
160     char *p, *s, *t;
161
162     if (line == 0)
163         return (0);
164     s = line;
165     while (*s != '\n')
166         ++s;
167     p = TMALLOC(char, s - line + 1);
168     NO_SPACE(p);
169
170     s = line;
171     t = p;
172     while ((*t++ = *s++) != '\n')
173         continue;
174     return (p);
175 }
176
177 static void
178 skip_comment(void)
179 {
180     char *s;
181
182     int st_lineno = lineno;
183     char *st_line = dup_line();
184     char *st_cptr = st_line + (cptr - line);
185
186     s = cptr + 2;
187     for (;;)
188     {
189         if (*s == '*' && s[1] == '/')
190         {
191             cptr = s + 2;
192             FREE(st_line);
193             return;
194         }
195         if (*s == '\n')
196         {
197             get_line();
198             if (line == 0)
199                 unterminated_comment(st_lineno, st_line, st_cptr);
200             s = cptr;
201         }
202         else
203             ++s;
204     }
205 }
206
207 static int
208 nextc(void)
209 {
210     char *s;
211
212     if (line == 0)
213     {
214         get_line();
215         if (line == 0)
216             return (EOF);
217     }
218
219     s = cptr;
220     for (;;)
221     {
222         switch (*s)
223         {
224         case '\n':
225             get_line();
226             if (line == 0)
227                 return (EOF);
228             s = cptr;
229             break;
230
231         case ' ':
232         case '\t':
233         case '\f':
234         case '\r':
235         case '\v':
236         case ',':
237         case ';':
238             ++s;
239             break;
240
241         case '\\':
242             cptr = s;
243             return ('%');
244
245         case '/':
246             if (s[1] == '*')
247             {
248                 cptr = s;
249                 skip_comment();
250                 s = cptr;
251                 break;
252             }
253             else if (s[1] == '/')
254             {
255                 get_line();
256                 if (line == 0)
257                     return (EOF);
258                 s = cptr;
259                 break;
260             }
261             /* FALLTHRU */
262
263         default:
264             cptr = s;
265             return (*s);
266         }
267     }
268 }
269 /* *INDENT-OFF* */
270 static struct keyword
271 {
272     char name[13];
273     int token;
274 }
275 keywords[] = {
276     { "binary",      NONASSOC },
277 #if defined(YYBTYACC)
278     { "destructor",  DESTRUCTOR },
279 #endif
280     { "expect",      EXPECT },
281     { "expect-rr",   EXPECT_RR },
282     { "ident",       IDENT }, 
283     { "left",        LEFT },
284     { "lex-param",   LEX_PARAM },
285 #if defined(YYBTYACC)
286     { "locations",   LOCATIONS },
287 #endif
288     { "nonassoc",    NONASSOC },
289     { "parse-param", PARSE_PARAM },
290     { "pure-parser", PURE_PARSER },
291     { "right",       RIGHT }, 
292     { "start",       START },
293     { "term",        TOKEN }, 
294     { "token",       TOKEN }, 
295     { "token-table", TOKEN_TABLE }, 
296     { "type",        TYPE },
297     { "union",       UNION },
298     { "yacc",        POSIX_YACC },
299 };
300 /* *INDENT-ON* */
301
302 static int
303 compare_keys(const void *a, const void *b)
304 {
305     const struct keyword *p = (const struct keyword *)a;
306     const struct keyword *q = (const struct keyword *)b;
307     return strcmp(p->name, q->name);
308 }
309
310 static int
311 keyword(void)
312 {
313     int c;
314     char *t_cptr = cptr;
315     struct keyword *key;
316
317     c = *++cptr;
318     if (isalpha(c))
319     {
320         cinc = 0;
321         for (;;)
322         {
323             if (isalpha(c))
324             {
325                 if (isupper(c))
326                     c = tolower(c);
327                 cachec(c);
328             }
329             else if (isdigit(c)
330                      || c == '-'
331                      || c == '.'
332                      || c == '$')
333             {
334                 cachec(c);
335             }
336             else if (c == '_')
337             {
338                 /* treat keywords spelled with '_' as if it were '-' */
339                 cachec('-');
340             }
341             else
342             {
343                 break;
344             }
345             c = *++cptr;
346         }
347         cachec(NUL);
348
349         if ((key = bsearch(cache, keywords,
350                            sizeof(keywords) / sizeof(*key),
351                            sizeof(*key), compare_keys)))
352             return key->token;
353     }
354     else
355     {
356         ++cptr;
357         if (c == L_CURL)
358             return (TEXT);
359         if (c == '%' || c == '\\')
360             return (MARK);
361         if (c == '<')
362             return (LEFT);
363         if (c == '>')
364             return (RIGHT);
365         if (c == '0')
366             return (TOKEN);
367         if (c == '2')
368             return (NONASSOC);
369     }
370     syntax_error(lineno, line, t_cptr);
371 }
372
373 static void
374 copy_ident(void)
375 {
376     int c;
377     FILE *f = output_file;
378
379     c = nextc();
380     if (c == EOF)
381         unexpected_EOF();
382     if (c != '"')
383         syntax_error(lineno, line, cptr);
384     ++outline;
385     fprintf(f, "#ident \"");
386     for (;;)
387     {
388         c = *++cptr;
389         if (c == '\n')
390         {
391             fprintf(f, "\"\n");
392             return;
393         }
394         putc(c, f);
395         if (c == '"')
396         {
397             putc('\n', f);
398             ++cptr;
399             return;
400         }
401     }
402 }
403
404 static char *
405 copy_string(int quote)
406 {
407     struct mstring *temp = msnew();
408     int c;
409     int s_lineno = lineno;
410     char *s_line = dup_line();
411     char *s_cptr = s_line + (cptr - line - 1);
412
413     for (;;)
414     {
415         c = *cptr++;
416         mputc(temp, c);
417         if (c == quote)
418         {
419             FREE(s_line);
420             return msdone(temp);
421         }
422         if (c == '\n')
423             unterminated_string(s_lineno, s_line, s_cptr);
424         if (c == '\\')
425         {
426             c = *cptr++;
427             mputc(temp, c);
428             if (c == '\n')
429             {
430                 get_line();
431                 if (line == 0)
432                     unterminated_string(s_lineno, s_line, s_cptr);
433             }
434         }
435     }
436 }
437
438 static char *
439 copy_comment(void)
440 {
441     struct mstring *temp = msnew();
442     int c;
443
444     c = *cptr;
445     if (c == '/')
446     {
447         mputc(temp, '*');
448         while ((c = *++cptr) != '\n')
449         {
450             mputc(temp, c);
451             if (c == '*' && cptr[1] == '/')
452                 mputc(temp, ' ');
453         }
454         mputc(temp, '*');
455         mputc(temp, '/');
456     }
457     else if (c == '*')
458     {
459         int c_lineno = lineno;
460         char *c_line = dup_line();
461         char *c_cptr = c_line + (cptr - line - 1);
462
463         mputc(temp, c);
464         ++cptr;
465         for (;;)
466         {
467             c = *cptr++;
468             mputc(temp, c);
469             if (c == '*' && *cptr == '/')
470             {
471                 mputc(temp, '/');
472                 ++cptr;
473                 FREE(c_line);
474                 return msdone(temp);
475             }
476             if (c == '\n')
477             {
478                 get_line();
479                 if (line == 0)
480                     unterminated_comment(c_lineno, c_line, c_cptr);
481             }
482         }
483     }
484     return msdone(temp);
485 }
486
487 static void
488 copy_text(void)
489 {
490     int c;
491     FILE *f = text_file;
492     int need_newline = 0;
493     int t_lineno = lineno;
494     char *t_line = dup_line();
495     char *t_cptr = t_line + (cptr - line - 2);
496
497     if (*cptr == '\n')
498     {
499         get_line();
500         if (line == 0)
501             unterminated_text(t_lineno, t_line, t_cptr);
502     }
503     if (!lflag)
504         fprintf(f, line_format, lineno, input_file_name);
505
506   loop:
507     c = *cptr++;
508     switch (c)
509     {
510     case '\n':
511         putc('\n', f);
512         need_newline = 0;
513         get_line();
514         if (line)
515             goto loop;
516         unterminated_text(t_lineno, t_line, t_cptr);
517
518     case '\'':
519     case '"':
520         putc(c, f);
521         {
522             char *s = copy_string(c);
523             fputs(s, f);
524             free(s);
525         }
526         need_newline = 1;
527         goto loop;
528
529     case '/':
530         putc(c, f);
531         {
532             char *s = copy_comment();
533             fputs(s, f);
534             free(s);
535         }
536         need_newline = 1;
537         goto loop;
538
539     case '%':
540     case '\\':
541         if (*cptr == R_CURL)
542         {
543             if (need_newline)
544                 putc('\n', f);
545             ++cptr;
546             FREE(t_line);
547             return;
548         }
549         /* FALLTHRU */
550
551     default:
552         putc(c, f);
553         need_newline = 1;
554         goto loop;
555     }
556 }
557
558 static void
559 puts_both(const char *s)
560 {
561     fputs(s, text_file);
562     if (dflag)
563         fputs(s, union_file);
564 }
565
566 static void
567 putc_both(int c)
568 {
569     putc(c, text_file);
570     if (dflag)
571         putc(c, union_file);
572 }
573
574 static void
575 copy_union(void)
576 {
577     int c;
578     int depth;
579     int u_lineno = lineno;
580     char *u_line = dup_line();
581     char *u_cptr = u_line + (cptr - line - 6);
582
583     if (unionized)
584         over_unionized(cptr - 6);
585     unionized = 1;
586
587     if (!lflag)
588         fprintf(text_file, line_format, lineno, input_file_name);
589
590     puts_both("#ifdef YYSTYPE\n");
591     puts_both("#undef  YYSTYPE_IS_DECLARED\n");
592     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
593     puts_both("#endif\n");
594     puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
595     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
596     puts_both("typedef union");
597
598     depth = 0;
599   loop:
600     c = *cptr++;
601     putc_both(c);
602     switch (c)
603     {
604     case '\n':
605         get_line();
606         if (line == 0)
607             unterminated_union(u_lineno, u_line, u_cptr);
608         goto loop;
609
610     case L_CURL:
611         ++depth;
612         goto loop;
613
614     case R_CURL:
615         if (--depth == 0)
616         {
617             puts_both(" YYSTYPE;\n");
618             puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
619             FREE(u_line);
620             return;
621         }
622         goto loop;
623
624     case '\'':
625     case '"':
626         {
627             char *s = copy_string(c);
628             puts_both(s);
629             free(s);
630         }
631         goto loop;
632
633     case '/':
634         {
635             char *s = copy_comment();
636             puts_both(s);
637             free(s);
638         }
639         goto loop;
640
641     default:
642         goto loop;
643     }
644 }
645
646 /*
647  * Keep a linked list of parameters
648  */
649 static void
650 copy_param(int k)
651 {
652     char *buf;
653     int c;
654     param *head, *p;
655     int i;
656     int name, type2;
657
658     c = nextc();
659     if (c == EOF)
660         unexpected_EOF();
661     if (c != L_CURL)
662         goto out;
663     cptr++;
664
665     c = nextc();
666     if (c == EOF)
667         unexpected_EOF();
668     if (c == R_CURL)
669         goto out;
670
671     buf = TMALLOC(char, linesize);
672     NO_SPACE(buf);
673
674     for (i = 0; (c = *cptr++) != R_CURL; i++)
675     {
676         if (c == '\0')
677             missing_brace();
678         if (c == EOF)
679             unexpected_EOF();
680         buf[i] = (char)c;
681     }
682
683     if (i == 0)
684         goto out;
685
686     buf[i--] = '\0';
687     while (i > 0 && isspace(UCH(buf[i])))
688         buf[i--] = '\0';
689
690     if (buf[i] == ']')
691     {
692         int level = 1;
693         while (i >= 0 && level > 0 && buf[i] != '[')
694         {
695             if (buf[i] == ']')
696                 ++level;
697             else if (buf[i] == '[')
698                 --level;
699             i--;
700         }
701         if (i <= 0)
702             unexpected_EOF();
703         type2 = i--;
704     }
705     else
706     {
707         type2 = i + 1;
708     }
709
710     while (i > 0 && (isalnum(UCH(buf[i])) ||
711                      UCH(buf[i]) == '_'))
712         i--;
713
714     if (!isspace(UCH(buf[i])) && buf[i] != '*')
715         goto out;
716
717     name = i + 1;
718
719     p = TMALLOC(param, 1);
720     NO_SPACE(p);
721
722     p->type2 = strdup(buf + type2);
723     NO_SPACE(p->type2);
724
725     buf[type2] = '\0';
726
727     p->name = strdup(buf + name);
728     NO_SPACE(p->name);
729
730     buf[name] = '\0';
731     p->type = buf;
732
733     if (k == LEX_PARAM)
734         head = lex_param;
735     else
736         head = parse_param;
737
738     if (head != NULL)
739     {
740         while (head->next)
741             head = head->next;
742         head->next = p;
743     }
744     else
745     {
746         if (k == LEX_PARAM)
747             lex_param = p;
748         else
749             parse_param = p;
750     }
751     p->next = NULL;
752     return;
753
754   out:
755     syntax_error(lineno, line, cptr);
756 }
757
758 static int
759 hexval(int c)
760 {
761     if (c >= '0' && c <= '9')
762         return (c - '0');
763     if (c >= 'A' && c <= 'F')
764         return (c - 'A' + 10);
765     if (c >= 'a' && c <= 'f')
766         return (c - 'a' + 10);
767     return (-1);
768 }
769
770 static bucket *
771 get_literal(void)
772 {
773     int c, quote;
774     int i;
775     int n;
776     char *s;
777     bucket *bp;
778     int s_lineno = lineno;
779     char *s_line = dup_line();
780     char *s_cptr = s_line + (cptr - line);
781
782     quote = *cptr++;
783     cinc = 0;
784     for (;;)
785     {
786         c = *cptr++;
787         if (c == quote)
788             break;
789         if (c == '\n')
790             unterminated_string(s_lineno, s_line, s_cptr);
791         if (c == '\\')
792         {
793             char *c_cptr = cptr - 1;
794
795             c = *cptr++;
796             switch (c)
797             {
798             case '\n':
799                 get_line();
800                 if (line == 0)
801                     unterminated_string(s_lineno, s_line, s_cptr);
802                 continue;
803
804             case '0':
805             case '1':
806             case '2':
807             case '3':
808             case '4':
809             case '5':
810             case '6':
811             case '7':
812                 n = c - '0';
813                 c = *cptr;
814                 if (IS_OCTAL(c))
815                 {
816                     n = (n << 3) + (c - '0');
817                     c = *++cptr;
818                     if (IS_OCTAL(c))
819                     {
820                         n = (n << 3) + (c - '0');
821                         ++cptr;
822                     }
823                 }
824                 if (n > MAXCHAR)
825                     illegal_character(c_cptr);
826                 c = n;
827                 break;
828
829             case 'x':
830                 c = *cptr++;
831                 n = hexval(c);
832                 if (n < 0 || n >= 16)
833                     illegal_character(c_cptr);
834                 for (;;)
835                 {
836                     c = *cptr;
837                     i = hexval(c);
838                     if (i < 0 || i >= 16)
839                         break;
840                     ++cptr;
841                     n = (n << 4) + i;
842                     if (n > MAXCHAR)
843                         illegal_character(c_cptr);
844                 }
845                 c = n;
846                 break;
847
848             case 'a':
849                 c = 7;
850                 break;
851             case 'b':
852                 c = '\b';
853                 break;
854             case 'f':
855                 c = '\f';
856                 break;
857             case 'n':
858                 c = '\n';
859                 break;
860             case 'r':
861                 c = '\r';
862                 break;
863             case 't':
864                 c = '\t';
865                 break;
866             case 'v':
867                 c = '\v';
868                 break;
869             }
870         }
871         cachec(c);
872     }
873     FREE(s_line);
874
875     n = cinc;
876     s = TMALLOC(char, n);
877     NO_SPACE(s);
878
879     for (i = 0; i < n; ++i)
880         s[i] = cache[i];
881
882     cinc = 0;
883     if (n == 1)
884         cachec('\'');
885     else
886         cachec('"');
887
888     for (i = 0; i < n; ++i)
889     {
890         c = UCH(s[i]);
891         if (c == '\\' || c == cache[0])
892         {
893             cachec('\\');
894             cachec(c);
895         }
896         else if (isprint(c))
897             cachec(c);
898         else
899         {
900             cachec('\\');
901             switch (c)
902             {
903             case 7:
904                 cachec('a');
905                 break;
906             case '\b':
907                 cachec('b');
908                 break;
909             case '\f':
910                 cachec('f');
911                 break;
912             case '\n':
913                 cachec('n');
914                 break;
915             case '\r':
916                 cachec('r');
917                 break;
918             case '\t':
919                 cachec('t');
920                 break;
921             case '\v':
922                 cachec('v');
923                 break;
924             default:
925                 cachec(((c >> 6) & 7) + '0');
926                 cachec(((c >> 3) & 7) + '0');
927                 cachec((c & 7) + '0');
928                 break;
929             }
930         }
931     }
932
933     if (n == 1)
934         cachec('\'');
935     else
936         cachec('"');
937
938     cachec(NUL);
939     bp = lookup(cache);
940     bp->class = TERM;
941     if (n == 1 && bp->value == UNDEFINED)
942         bp->value = UCH(*s);
943     FREE(s);
944
945     return (bp);
946 }
947
948 static int
949 is_reserved(char *name)
950 {
951     char *s;
952
953     if (strcmp(name, ".") == 0 ||
954         strcmp(name, "$accept") == 0 ||
955         strcmp(name, "$end") == 0)
956         return (1);
957
958     if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
959     {
960         s = name + 3;
961         while (isdigit(UCH(*s)))
962             ++s;
963         if (*s == NUL)
964             return (1);
965     }
966
967     return (0);
968 }
969
970 static bucket *
971 get_name(void)
972 {
973     int c;
974
975     cinc = 0;
976     for (c = *cptr; IS_IDENT(c); c = *++cptr)
977         cachec(c);
978     cachec(NUL);
979
980     if (is_reserved(cache))
981         used_reserved(cache);
982
983     return (lookup(cache));
984 }
985
986 static Value_t
987 get_number(void)
988 {
989     int c;
990     Value_t n;
991
992     n = 0;
993     for (c = *cptr; isdigit(c); c = *++cptr)
994         n = (Value_t) (10 * n + (c - '0'));
995
996     return (n);
997 }
998
999 static char *
1000 cache_tag(char *tag, size_t len)
1001 {
1002     int i;
1003     char *s;
1004
1005     for (i = 0; i < ntags; ++i)
1006     {
1007         if (strncmp(tag, tag_table[i], len) == 0 &&
1008             tag_table[i][len] == NUL)
1009             return (tag_table[i]);
1010     }
1011
1012     if (ntags >= tagmax)
1013     {
1014         tagmax += 16;
1015         tag_table =
1016             (tag_table
1017              ? TREALLOC(char *, tag_table, tagmax)
1018              : TMALLOC(char *, tagmax));
1019         NO_SPACE(tag_table);
1020     }
1021
1022     s = TMALLOC(char, len + 1);
1023     NO_SPACE(s);
1024
1025     strncpy(s, tag, len);
1026     s[len] = 0;
1027     tag_table[ntags++] = s;
1028     return s;
1029 }
1030
1031 static char *
1032 get_tag(void)
1033 {
1034     int c;
1035     int t_lineno = lineno;
1036     char *t_line = dup_line();
1037     char *t_cptr = t_line + (cptr - line);
1038
1039     ++cptr;
1040     c = nextc();
1041     if (c == EOF)
1042         unexpected_EOF();
1043     if (!isalpha(c) && c != '_' && c != '$')
1044         illegal_tag(t_lineno, t_line, t_cptr);
1045
1046     cinc = 0;
1047     do
1048     {
1049         cachec(c);
1050         c = *++cptr;
1051     }
1052     while (IS_IDENT(c));
1053     cachec(NUL);
1054
1055     c = nextc();
1056     if (c == EOF)
1057         unexpected_EOF();
1058     if (c != '>')
1059         illegal_tag(t_lineno, t_line, t_cptr);
1060     ++cptr;
1061
1062     FREE(t_line);
1063     havetags = 1;
1064     return cache_tag(cache, (size_t) cinc);
1065 }
1066
1067 #if defined(YYBTYACC)
1068 static char *
1069 scan_id(void)
1070 {
1071     char *b = cptr;
1072
1073     while (isalnum(*cptr) || *cptr == '_' || *cptr == '$')
1074         cptr++;
1075     return cache_tag(b, (size_t) (cptr - b));
1076 }
1077 #endif
1078
1079 static void
1080 declare_tokens(int assoc)
1081 {
1082     int c;
1083     bucket *bp;
1084     Value_t value;
1085     char *tag = 0;
1086
1087     if (assoc != TOKEN)
1088         ++prec;
1089
1090     c = nextc();
1091     if (c == EOF)
1092         unexpected_EOF();
1093     if (c == '<')
1094     {
1095         tag = get_tag();
1096         c = nextc();
1097         if (c == EOF)
1098             unexpected_EOF();
1099     }
1100
1101     for (;;)
1102     {
1103         if (isalpha(c) || c == '_' || c == '.' || c == '$')
1104             bp = get_name();
1105         else if (c == '\'' || c == '"')
1106             bp = get_literal();
1107         else
1108             return;
1109
1110         if (bp == goal)
1111             tokenized_start(bp->name);
1112         bp->class = TERM;
1113
1114         if (tag)
1115         {
1116             if (bp->tag && tag != bp->tag)
1117                 retyped_warning(bp->name);
1118             bp->tag = tag;
1119         }
1120
1121         if (assoc != TOKEN)
1122         {
1123             if (bp->prec && prec != bp->prec)
1124                 reprec_warning(bp->name);
1125             bp->assoc = (Assoc_t) assoc;
1126             bp->prec = prec;
1127         }
1128
1129         c = nextc();
1130         if (c == EOF)
1131             unexpected_EOF();
1132
1133         if (isdigit(c))
1134         {
1135             value = get_number();
1136             if (bp->value != UNDEFINED && value != bp->value)
1137                 revalued_warning(bp->name);
1138             bp->value = value;
1139             c = nextc();
1140             if (c == EOF)
1141                 unexpected_EOF();
1142         }
1143     }
1144 }
1145
1146 /*
1147  * %expect requires special handling
1148  * as it really isn't part of the yacc
1149  * grammar only a flag for yacc proper.
1150  */
1151 static void
1152 declare_expect(int assoc)
1153 {
1154     int c;
1155
1156     if (assoc != EXPECT && assoc != EXPECT_RR)
1157         ++prec;
1158
1159     /*
1160      * Stay away from nextc - doesn't
1161      * detect EOL and will read to EOF.
1162      */
1163     c = *++cptr;
1164     if (c == EOF)
1165         unexpected_EOF();
1166
1167     for (;;)
1168     {
1169         if (isdigit(c))
1170         {
1171             if (assoc == EXPECT)
1172                 SRexpect = get_number();
1173             else
1174                 RRexpect = get_number();
1175             break;
1176         }
1177         /*
1178          * Looking for number before EOL.
1179          * Spaces, tabs, and numbers are ok,
1180          * words, punc., etc. are syntax errors.
1181          */
1182         else if (c == '\n' || isalpha(c) || !isspace(c))
1183         {
1184             syntax_error(lineno, line, cptr);
1185         }
1186         else
1187         {
1188             c = *++cptr;
1189             if (c == EOF)
1190                 unexpected_EOF();
1191         }
1192     }
1193 }
1194
1195 #if defined(YYBTYACC)
1196 static void
1197 declare_argtypes(bucket *bp)
1198 {
1199     char *tags[MAXARGS];
1200     int args = 0, c;
1201
1202     if (bp->args >= 0)
1203         retyped_warning(bp->name);
1204     cptr++;                     /* skip open paren */
1205     for (;;)
1206     {
1207         c = nextc();
1208         if (c == EOF)
1209             unexpected_EOF();
1210         if (c != '<')
1211             syntax_error(lineno, line, cptr);
1212         tags[args++] = get_tag();
1213         c = nextc();
1214         if (c == R_PAREN)
1215             break;
1216         if (c == EOF)
1217             unexpected_EOF();
1218     }
1219     cptr++;                     /* skip close paren */
1220     bp->args = args;
1221     bp->argnames = TMALLOC(char *, args);
1222     NO_SPACE(bp->argnames);
1223     bp->argtags = CALLOC(sizeof(char *), args + 1);
1224     NO_SPACE(bp->argtags);
1225     while (--args >= 0)
1226     {
1227         bp->argtags[args] = tags[args];
1228         bp->argnames[args] = NULL;
1229     }
1230 }
1231 #endif
1232
1233 static void
1234 declare_types(void)
1235 {
1236     int c;
1237     bucket *bp;
1238     char *tag = NULL;
1239
1240     c = nextc();
1241     if (c == EOF)
1242         unexpected_EOF();
1243     if (c == '<')
1244         tag = get_tag();
1245
1246     for (;;)
1247     {
1248         c = nextc();
1249         if (c == EOF)
1250             unexpected_EOF();
1251         if (isalpha(c) || c == '_' || c == '.' || c == '$')
1252         {
1253             bp = get_name();
1254 #if defined(YYBTYACC)
1255             if (nextc() == L_PAREN)
1256                 declare_argtypes(bp);
1257             else
1258                 bp->args = 0;
1259 #endif
1260         }
1261         else if (c == '\'' || c == '"')
1262         {
1263             bp = get_literal();
1264 #if defined(YYBTYACC)
1265             bp->args = 0;
1266 #endif
1267         }
1268         else
1269             return;
1270
1271         if (tag)
1272         {
1273             if (bp->tag && tag != bp->tag)
1274                 retyped_warning(bp->name);
1275             bp->tag = tag;
1276         }
1277     }
1278 }
1279
1280 static void
1281 declare_start(void)
1282 {
1283     int c;
1284     bucket *bp;
1285
1286     c = nextc();
1287     if (c == EOF)
1288         unexpected_EOF();
1289     if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1290         syntax_error(lineno, line, cptr);
1291     bp = get_name();
1292     if (bp->class == TERM)
1293         terminal_start(bp->name);
1294     if (goal && goal != bp)
1295         restarted_warning();
1296     goal = bp;
1297 }
1298
1299 static void
1300 read_declarations(void)
1301 {
1302     int c, k;
1303
1304     cache_size = 256;
1305     cache = TMALLOC(char, cache_size);
1306     NO_SPACE(cache);
1307
1308     for (;;)
1309     {
1310         c = nextc();
1311         if (c == EOF)
1312             unexpected_EOF();
1313         if (c != '%')
1314             syntax_error(lineno, line, cptr);
1315         switch (k = keyword())
1316         {
1317         case MARK:
1318             return;
1319
1320         case IDENT:
1321             copy_ident();
1322             break;
1323
1324         case TEXT:
1325             copy_text();
1326             break;
1327
1328         case UNION:
1329             copy_union();
1330             break;
1331
1332         case TOKEN:
1333         case LEFT:
1334         case RIGHT:
1335         case NONASSOC:
1336             declare_tokens(k);
1337             break;
1338
1339         case EXPECT:
1340         case EXPECT_RR:
1341             declare_expect(k);
1342             break;
1343
1344         case TYPE:
1345             declare_types();
1346             break;
1347
1348         case START:
1349             declare_start();
1350             break;
1351
1352         case PURE_PARSER:
1353             pure_parser = 1;
1354             break;
1355
1356         case PARSE_PARAM:
1357         case LEX_PARAM:
1358             copy_param(k);
1359             break;
1360
1361         case TOKEN_TABLE:
1362             token_table = 1;
1363             break;
1364
1365 #if defined(YYBTYACC)
1366         case LOCATIONS:
1367             locations = 1;
1368             break;
1369
1370         case DESTRUCTOR:
1371             destructor = 1;
1372             copy_destructor();
1373             break;
1374 #endif
1375
1376         case POSIX_YACC:
1377             /* noop for bison compatibility. byacc is already designed to be posix
1378              * yacc compatible. */
1379             break;
1380         }
1381     }
1382 }
1383
1384 static void
1385 initialize_grammar(void)
1386 {
1387     nitems = 4;
1388     maxitems = 300;
1389
1390     pitem = TMALLOC(bucket *, maxitems);
1391     NO_SPACE(pitem);
1392
1393     pitem[0] = 0;
1394     pitem[1] = 0;
1395     pitem[2] = 0;
1396     pitem[3] = 0;
1397
1398     nrules = 3;
1399     maxrules = 100;
1400
1401     plhs = TMALLOC(bucket *, maxrules);
1402     NO_SPACE(plhs);
1403
1404     plhs[0] = 0;
1405     plhs[1] = 0;
1406     plhs[2] = 0;
1407
1408     rprec = TMALLOC(Value_t, maxrules);
1409     NO_SPACE(rprec);
1410
1411     rprec[0] = 0;
1412     rprec[1] = 0;
1413     rprec[2] = 0;
1414
1415     rassoc = TMALLOC(Assoc_t, maxrules);
1416     NO_SPACE(rassoc);
1417
1418     rassoc[0] = TOKEN;
1419     rassoc[1] = TOKEN;
1420     rassoc[2] = TOKEN;
1421 }
1422
1423 static void
1424 expand_items(void)
1425 {
1426     maxitems += 300;
1427     pitem = TREALLOC(bucket *, pitem, maxitems);
1428     NO_SPACE(pitem);
1429 }
1430
1431 static void
1432 expand_rules(void)
1433 {
1434     maxrules += 100;
1435
1436     plhs = TREALLOC(bucket *, plhs, maxrules);
1437     NO_SPACE(plhs);
1438
1439     rprec = TREALLOC(Value_t, rprec, maxrules);
1440     NO_SPACE(rprec);
1441
1442     rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
1443     NO_SPACE(rassoc);
1444 }
1445
1446 /* set immediately prior to where copy_args() could be called, and incremented by
1447    the various routines that will rescan the argument list as appropriate */
1448 static int rescan_lineno;
1449 #if defined(YYBTYACC)
1450
1451 static char *
1452 copy_args(int *alen)
1453 {
1454     struct mstring *s = msnew();
1455     int depth = 0, len = 1;
1456     char c, quote = 0;
1457     int a_lineno = lineno;
1458     char *a_line = dup_line();
1459     char *a_cptr = a_line + (cptr - line - 1);
1460
1461     while ((c = *cptr++) != R_PAREN || depth || quote)
1462     {
1463         if (c == ',' && !quote && !depth)
1464         {
1465             len++;
1466             mputc(s, 0);
1467             continue;
1468         }
1469         mputc(s, c);
1470         if (c == '\n')
1471         {
1472             get_line();
1473             if (!line)
1474             {
1475                 if (quote)
1476                     unterminated_string(a_lineno, a_line, a_cptr);
1477                 else
1478                     unterminated_arglist(a_lineno, a_line, a_cptr);
1479             }
1480         }
1481         else if (quote)
1482         {
1483             if (c == quote)
1484                 quote = 0;
1485             else if (c == '\\')
1486             {
1487                 if (*cptr != '\n')
1488                     mputc(s, *cptr++);
1489             }
1490         }
1491         else
1492         {
1493             if (c == L_PAREN)
1494                 depth++;
1495             else if (c == R_PAREN)
1496                 depth--;
1497             else if (c == '\"' || c == '\'')
1498                 quote = c;
1499         }
1500     }
1501     if (alen)
1502         *alen = len;
1503     FREE(a_line);
1504     return msdone(s);
1505 }
1506
1507 static char *
1508 parse_id(char *p, char **save)
1509 {
1510     char *b;
1511
1512     while (isspace(*p))
1513         if (*p++ == '\n')
1514             rescan_lineno++;
1515     if (!isalpha(*p) && *p != '_')
1516         return NULL;
1517     b = p;
1518     while (isalnum(*p) || *p == '_' || *p == '$')
1519         p++;
1520     if (save)
1521     {
1522         *save = cache_tag(b, (size_t) (p - b));
1523     }
1524     return p;
1525 }
1526
1527 static char *
1528 parse_int(char *p, int *save)
1529 {
1530     int neg = 0, val = 0;
1531
1532     while (isspace(*p))
1533         if (*p++ == '\n')
1534             rescan_lineno++;
1535     if (*p == '-')
1536     {
1537         neg = 1;
1538         p++;
1539     }
1540     if (!isdigit(*p))
1541         return NULL;
1542     while (isdigit(*p))
1543         val = val * 10 + *p++ - '0';
1544     if (neg)
1545         val = -val;
1546     if (save)
1547         *save = val;
1548     return p;
1549 }
1550
1551 static void
1552 parse_arginfo(bucket *a, char *args, int argslen)
1553 {
1554     char *p = args, *tmp;
1555     int i, redec = 0;
1556
1557     if (a->args > 0)
1558     {
1559         if (a->args != argslen)
1560             arg_number_disagree_warning(rescan_lineno, a->name);
1561         redec = 1;
1562     }
1563     else
1564     {
1565         if ((a->args = argslen) == 0)
1566             return;
1567         a->argnames = TMALLOC(char *, argslen);
1568         NO_SPACE(a->argnames);
1569         a->argtags = TMALLOC(char *, argslen);
1570         NO_SPACE(a->argtags);
1571     }
1572     if (!args)
1573         return;
1574     for (i = 0; i < argslen; i++)
1575     {
1576         while (isspace(*p))
1577             if (*p++ == '\n')
1578                 rescan_lineno++;
1579         if (*p++ != '$')
1580             bad_formals();
1581         while (isspace(*p))
1582             if (*p++ == '\n')
1583                 rescan_lineno++;
1584         if (*p == '<')
1585         {
1586             havetags = 1;
1587             if (!(p = parse_id(p + 1, &tmp)))
1588                 bad_formals();
1589             while (isspace(*p))
1590                 if (*p++ == '\n')
1591                     rescan_lineno++;
1592             if (*p++ != '>')
1593                 bad_formals();
1594             if (redec)
1595             {
1596                 if (a->argtags[i] != tmp)
1597                     arg_type_disagree_warning(rescan_lineno, i + 1, a->name);
1598             }
1599             else
1600                 a->argtags[i] = tmp;
1601         }
1602         else if (!redec)
1603             a->argtags[i] = NULL;
1604         if (!(p = parse_id(p, &a->argnames[i])))
1605             bad_formals();
1606         while (isspace(*p))
1607             if (*p++ == '\n')
1608                 rescan_lineno++;
1609         if (*p++)
1610             bad_formals();
1611     }
1612     free(args);
1613 }
1614
1615 static char *
1616 compile_arg(char **theptr, char *yyvaltag)
1617 {
1618     char *p = *theptr;
1619     struct mstring *c = msnew();
1620     int i, j, n;
1621     Value_t *offsets = NULL, maxoffset;
1622     bucket **rhs;
1623
1624     maxoffset = 0;
1625     n = 0;
1626     for (i = nitems - 1; pitem[i]; --i)
1627     {
1628         n++;
1629         if (pitem[i]->class != ARGUMENT)
1630             maxoffset++;
1631     }
1632     if (maxoffset > 0)
1633     {
1634         offsets = TMALLOC(Value_t, maxoffset + 1);
1635         NO_SPACE(offsets);
1636     }
1637     for (j = 0, i++; i < nitems; i++)
1638         if (pitem[i]->class != ARGUMENT)
1639             offsets[++j] = (Value_t) (i - nitems + 1);
1640     rhs = pitem + nitems - 1;
1641
1642     if (yyvaltag)
1643         msprintf(c, "yyval.%s = ", yyvaltag);
1644     else
1645         msprintf(c, "yyval = ");
1646     while (*p)
1647     {
1648         if (*p == '$')
1649         {
1650             char *tag = NULL;
1651             if (*++p == '<')
1652                 if (!(p = parse_id(++p, &tag)) || *p++ != '>')
1653                     illegal_tag(rescan_lineno, NULL, NULL);
1654             if (isdigit(*p) || *p == '-')
1655             {
1656                 int val;
1657                 if (!(p = parse_int(p, &val)))
1658                     dollar_error(rescan_lineno, NULL, NULL);
1659                 if (val <= 0)
1660                     i = val - n;
1661                 else if (val > maxoffset)
1662                 {
1663                     dollar_warning(rescan_lineno, val);
1664                     i = val - maxoffset;
1665                 }
1666                 else
1667                 {
1668                     i = offsets[val];
1669                     if (!tag && !(tag = rhs[i]->tag) && havetags)
1670                         untyped_rhs(val, rhs[i]->name);
1671                 }
1672                 msprintf(c, "yystack.l_mark[%d]", i);
1673                 if (tag)
1674                     msprintf(c, ".%s", tag);
1675                 else if (havetags)
1676                     unknown_rhs(val);
1677             }
1678             else if (isalpha(*p) || *p == '_')
1679             {
1680                 char *arg;
1681                 if (!(p = parse_id(p, &arg)))
1682                     dollar_error(rescan_lineno, NULL, NULL);
1683                 for (i = plhs[nrules]->args - 1; i >= 0; i--)
1684                     if (arg == plhs[nrules]->argnames[i])
1685                         break;
1686                 if (i < 0)
1687                     unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL);
1688                 else if (!tag)
1689                     tag = plhs[nrules]->argtags[i];
1690                 msprintf(c, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1
1691                          - n);
1692                 if (tag)
1693                     msprintf(c, ".%s", tag);
1694                 else if (havetags)
1695                     untyped_arg_warning(rescan_lineno, "$", arg);
1696             }
1697             else
1698                 dollar_error(rescan_lineno, NULL, NULL);
1699         }
1700         else if (*p == '@')
1701         {
1702             at_error(rescan_lineno, NULL, NULL);
1703         }
1704         else
1705         {
1706             if (*p == '\n')
1707                 rescan_lineno++;
1708             mputc(c, *p++);
1709         }
1710     }
1711     *theptr = p;
1712     if (maxoffset > 0)
1713         FREE(offsets);
1714     return msdone(c);
1715 }
1716
1717 #define ARG_CACHE_SIZE  1024
1718 static struct arg_cache
1719 {
1720     struct arg_cache *next;
1721     char *code;
1722     int rule;
1723 }
1724  *arg_cache[ARG_CACHE_SIZE];
1725
1726 static int
1727 lookup_arg_cache(char *code)
1728 {
1729     struct arg_cache *entry;
1730
1731     entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE];
1732     while (entry)
1733     {
1734         if (!strnscmp(entry->code, code))
1735             return entry->rule;
1736         entry = entry->next;
1737     }
1738     return -1;
1739 }
1740
1741 static void
1742 insert_arg_cache(char *code, int rule)
1743 {
1744     struct arg_cache *entry = NEW(struct arg_cache);
1745     int i;
1746
1747     NO_SPACE(entry);
1748     i = strnshash(code) % ARG_CACHE_SIZE;
1749     entry->code = code;
1750     entry->rule = rule;
1751     entry->next = arg_cache[i];
1752     arg_cache[i] = entry;
1753 }
1754
1755 static void
1756 clean_arg_cache(void)
1757 {
1758     struct arg_cache *e, *t;
1759     int i;
1760
1761     for (i = 0; i < ARG_CACHE_SIZE; i++)
1762     {
1763         for (e = arg_cache[i]; (t = e); e = e->next, FREE(t))
1764             free(e->code);
1765         arg_cache[i] = NULL;
1766     }
1767 }
1768 #endif
1769
1770 static void
1771 advance_to_start(void)
1772 {
1773     int c;
1774     bucket *bp;
1775     char *s_cptr;
1776     int s_lineno;
1777 #if defined(YYBTYACC)
1778     char *args = NULL;
1779     int argslen = 0;
1780 #endif
1781
1782     for (;;)
1783     {
1784         c = nextc();
1785         if (c != '%')
1786             break;
1787         s_cptr = cptr;
1788         switch (keyword())
1789         {
1790         case MARK:
1791             no_grammar();
1792
1793         case TEXT:
1794             copy_text();
1795             break;
1796
1797         case START:
1798             declare_start();
1799             break;
1800
1801         default:
1802             syntax_error(lineno, line, s_cptr);
1803         }
1804     }
1805
1806     c = nextc();
1807     if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1808         syntax_error(lineno, line, cptr);
1809     bp = get_name();
1810     if (goal == 0)
1811     {
1812         if (bp->class == TERM)
1813             terminal_start(bp->name);
1814         goal = bp;
1815     }
1816
1817     s_lineno = lineno;
1818     c = nextc();
1819     if (c == EOF)
1820         unexpected_EOF();
1821     rescan_lineno = lineno;     /* line# for possible inherited args rescan */
1822 #if defined(YYBTYACC)
1823     if (c == L_PAREN)
1824     {
1825         ++cptr;
1826         args = copy_args(&argslen);
1827         NO_SPACE(args);
1828         c = nextc();
1829     }
1830 #endif
1831     if (c != ':')
1832         syntax_error(lineno, line, cptr);
1833     start_rule(bp, s_lineno);
1834 #if defined(YYBTYACC)
1835     parse_arginfo(bp, args, argslen);
1836 #endif
1837     ++cptr;
1838 }
1839
1840 static void
1841 start_rule(bucket *bp, int s_lineno)
1842 {
1843     if (bp->class == TERM)
1844         terminal_lhs(s_lineno);
1845     bp->class = NONTERM;
1846     if (!bp->index)
1847         bp->index = nrules;
1848     if (nrules >= maxrules)
1849         expand_rules();
1850     plhs[nrules] = bp;
1851     rprec[nrules] = UNDEFINED;
1852     rassoc[nrules] = TOKEN;
1853 }
1854
1855 static void
1856 end_rule(void)
1857 {
1858     int i;
1859
1860     if (!last_was_action && plhs[nrules]->tag)
1861     {
1862         if (pitem[nitems - 1])
1863         {
1864             for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1865                 continue;
1866             if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1867                 default_action_warning();
1868         }
1869         else
1870         {
1871             default_action_warning();
1872         }
1873     }
1874
1875     last_was_action = 0;
1876     if (nitems >= maxitems)
1877         expand_items();
1878     pitem[nitems] = 0;
1879     ++nitems;
1880     ++nrules;
1881 }
1882
1883 static void
1884 insert_empty_rule(void)
1885 {
1886     bucket *bp, **bpp;
1887
1888     assert(cache);
1889     sprintf(cache, "$$%d", ++gensym);
1890     bp = make_bucket(cache);
1891     last_symbol->next = bp;
1892     last_symbol = bp;
1893     bp->tag = plhs[nrules]->tag;
1894     bp->class = ACTION;
1895 #if defined(YYBTYACC)
1896     bp->args = 0;
1897 #endif
1898
1899     nitems = (Value_t) (nitems + 2);
1900     if (nitems > maxitems)
1901         expand_items();
1902     bpp = pitem + nitems - 1;
1903     *bpp-- = bp;
1904     while ((bpp[0] = bpp[-1]) != 0)
1905         --bpp;
1906
1907     if (++nrules >= maxrules)
1908         expand_rules();
1909     plhs[nrules] = plhs[nrules - 1];
1910     plhs[nrules - 1] = bp;
1911     rprec[nrules] = rprec[nrules - 1];
1912     rprec[nrules - 1] = 0;
1913     rassoc[nrules] = rassoc[nrules - 1];
1914     rassoc[nrules - 1] = TOKEN;
1915 }
1916
1917 #if defined(YYBTYACC)
1918 static char *
1919 insert_arg_rule(char *arg, char *tag)
1920 {
1921     int line_number = rescan_lineno;
1922     char *code = compile_arg(&arg, tag);
1923     int rule = lookup_arg_cache(code);
1924     FILE *f = action_file;
1925
1926     if (rule < 0)
1927     {
1928         rule = nrules;
1929         insert_arg_cache(code, rule);
1930         fprintf(f, "case %d:\n", rule - 2);
1931         if (!lflag)
1932             fprintf(f, line_format, line_number, input_file_name);
1933         fprintf(f, "%s;\n", code);
1934         fprintf(f, "break;\n");
1935         insert_empty_rule();
1936         plhs[rule]->tag = tag;
1937         plhs[rule]->class = ARGUMENT;
1938     }
1939     else
1940     {
1941         if (++nitems > maxitems)
1942             expand_items();
1943         pitem[nitems - 1] = plhs[rule];
1944         free(code);
1945     }
1946     return arg + 1;
1947 }
1948 #endif
1949
1950 static void
1951 add_symbol(void)
1952 {
1953     int c;
1954     bucket *bp;
1955     int s_lineno = lineno;
1956 #if defined(YYBTYACC)
1957     char *args = NULL;
1958     int argslen = 0;
1959 #endif
1960
1961     c = *cptr;
1962     if (c == '\'' || c == '"')
1963         bp = get_literal();
1964     else
1965         bp = get_name();
1966
1967     c = nextc();
1968     rescan_lineno = lineno;     /* line# for possible inherited args rescan */
1969 #if defined(YYBTYACC)
1970     if (c == L_PAREN)
1971     {
1972         ++cptr;
1973         args = copy_args(&argslen);
1974         NO_SPACE(args);
1975         c = nextc();
1976     }
1977 #endif
1978     if (c == ':')
1979     {
1980         end_rule();
1981         start_rule(bp, s_lineno);
1982 #if defined(YYBTYACC)
1983         parse_arginfo(bp, args, argslen);
1984 #endif
1985         ++cptr;
1986         return;
1987     }
1988
1989     if (last_was_action)
1990         insert_empty_rule();
1991     last_was_action = 0;
1992
1993 #if defined(YYBTYACC)
1994     if (bp->args < 0)
1995         bp->args = argslen;
1996     if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
1997     {
1998         int i;
1999         if (plhs[nrules]->args != bp->args)
2000             wrong_number_args_warning("default ", bp->name);
2001         for (i = bp->args - 1; i >= 0; i--)
2002             if (plhs[nrules]->argtags[i] != bp->argtags[i])
2003                 wrong_type_for_arg_warning(i + 1, bp->name);
2004     }
2005     else if (bp->args != argslen)
2006         wrong_number_args_warning("", bp->name);
2007     if (bp->args > 0 && argslen > 0)
2008     {
2009         char *ap;
2010         int i;
2011         for (ap = args, i = 0; i < argslen; i++)
2012             ap = insert_arg_rule(ap, bp->argtags[i]);
2013         free(args);
2014     }
2015 #endif /* defined(YYBTYACC) */
2016
2017     if (++nitems > maxitems)
2018         expand_items();
2019     pitem[nitems - 1] = bp;
2020 }
2021
2022 static char *
2023 after_blanks(char *s)
2024 {
2025     while (*s != '\0' && isspace(UCH(*s)))
2026         ++s;
2027     return s;
2028 }
2029
2030 static void
2031 copy_action(void)
2032 {
2033     int c;
2034     int i, j, n;
2035     int depth;
2036 #if defined(YYBTYACC)
2037     int trialaction = 0;
2038     int haveyyval = 0;
2039 #endif
2040     char *tag;
2041     FILE *f = action_file;
2042     int a_lineno = lineno;
2043     char *a_line = dup_line();
2044     char *a_cptr = a_line + (cptr - line);
2045     Value_t *offsets = NULL, maxoffset;
2046     bucket **rhs;
2047
2048     if (last_was_action)
2049         insert_empty_rule();
2050     last_was_action = 1;
2051
2052     fprintf(f, "case %d:\n", nrules - 2);
2053 #if defined(YYBTYACC)
2054     if (backtrack)
2055     {
2056         if (*cptr != L_BRAC)
2057             fprintf(f, "  if (!yytrial)\n");
2058         else
2059             trialaction = 1;
2060     }
2061 #endif
2062     if (!lflag)
2063         fprintf(f, line_format, lineno, input_file_name);
2064     if (*cptr == '=')
2065         ++cptr;
2066
2067     /* avoid putting curly-braces in first column, to ease editing */
2068     if (*after_blanks(cptr) == L_CURL)
2069     {
2070         putc('\t', f);
2071         cptr = after_blanks(cptr);
2072     }
2073
2074     maxoffset = 0;
2075     n = 0;
2076     for (i = nitems - 1; pitem[i]; --i)
2077     {
2078         ++n;
2079         if (pitem[i]->class != ARGUMENT)
2080             maxoffset++;
2081     }
2082     if (maxoffset > 0)
2083     {
2084         offsets = TMALLOC(Value_t, maxoffset + 1);
2085         NO_SPACE(offsets);
2086     }
2087     for (j = 0, i++; i < nitems; i++)
2088     {
2089         if (pitem[i]->class != ARGUMENT)
2090         {
2091             offsets[++j] = (Value_t) (i - nitems + 1);
2092         }
2093     }
2094     rhs = pitem + nitems - 1;
2095
2096     depth = 0;
2097   loop:
2098     c = *cptr;
2099     if (c == '$')
2100     {
2101         if (cptr[1] == '<')
2102         {
2103             int d_lineno = lineno;
2104             char *d_line = dup_line();
2105             char *d_cptr = d_line + (cptr - line);
2106
2107             ++cptr;
2108             tag = get_tag();
2109             c = *cptr;
2110             if (c == '$')
2111             {
2112                 fprintf(f, "yyval.%s", tag);
2113                 ++cptr;
2114                 FREE(d_line);
2115                 goto loop;
2116             }
2117             else if (isdigit(c))
2118             {
2119                 i = get_number();
2120                 if (i == 0)
2121                     fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
2122                 else if (i > maxoffset)
2123                 {
2124                     dollar_warning(d_lineno, i);
2125                     fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag);
2126                 }
2127                 else if (offsets)
2128                     fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2129                 FREE(d_line);
2130                 goto loop;
2131             }
2132             else if (c == '-' && isdigit(UCH(cptr[1])))
2133             {
2134                 ++cptr;
2135                 i = -get_number() - n;
2136                 fprintf(f, "yystack.l_mark[%d].%s", i, tag);
2137                 FREE(d_line);
2138                 goto loop;
2139             }
2140 #if defined(YYBTYACC)
2141             else if (isalpha(c) || c == '_')
2142             {
2143                 char *arg = scan_id();
2144                 for (i = plhs[nrules]->args - 1; i >= 0; i--)
2145                     if (arg == plhs[nrules]->argnames[i])
2146                         break;
2147                 if (i < 0)
2148                     unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
2149                 fprintf(f, "yystack.l_mark[%d].%s", i - plhs[nrules]->args +
2150                         1 - n, tag);
2151                 FREE(d_line);
2152                 goto loop;
2153             }
2154 #endif
2155             else
2156                 dollar_error(d_lineno, d_line, d_cptr);
2157         }
2158         else if (cptr[1] == '$')
2159         {
2160             if (havetags)
2161             {
2162                 tag = plhs[nrules]->tag;
2163                 if (tag == 0)
2164                     untyped_lhs();
2165                 fprintf(f, "yyval.%s", tag);
2166             }
2167             else
2168                 fprintf(f, "yyval");
2169             cptr += 2;
2170 #if defined(YYBTYACC)
2171             haveyyval = 1;
2172 #endif
2173             goto loop;
2174         }
2175         else if (isdigit(UCH(cptr[1])))
2176         {
2177             ++cptr;
2178             i = get_number();
2179             if (havetags)
2180             {
2181                 if (i <= 0 || i > maxoffset)
2182                     unknown_rhs(i);
2183                 tag = rhs[offsets[i]]->tag;
2184                 if (tag == 0)
2185                     untyped_rhs(i, rhs[offsets[i]]->name);
2186                 fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2187             }
2188             else
2189             {
2190                 if (i == 0)
2191                     fprintf(f, "yystack.l_mark[%d]", -n);
2192                 else if (i > maxoffset)
2193                 {
2194                     dollar_warning(lineno, i);
2195                     fprintf(f, "yystack.l_mark[%d]", i - maxoffset);
2196                 }
2197                 else if (offsets)
2198                     fprintf(f, "yystack.l_mark[%d]", offsets[i]);
2199             }
2200             goto loop;
2201         }
2202         else if (cptr[1] == '-')
2203         {
2204             cptr += 2;
2205             i = get_number();
2206             if (havetags)
2207                 unknown_rhs(-i);
2208             fprintf(f, "yystack.l_mark[%d]", -i - n);
2209             goto loop;
2210         }
2211 #if defined(YYBTYACC)
2212         else if (isalpha(cptr[1]) || cptr[1] == '_')
2213         {
2214             char *arg;
2215             ++cptr;
2216             arg = scan_id();
2217             for (i = plhs[nrules]->args - 1; i >= 0; i--)
2218                 if (arg == plhs[nrules]->argnames[i])
2219                     break;
2220             if (i < 0)
2221                 unknown_arg_warning(lineno, "$", arg, line, cptr);
2222             tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]);
2223             fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n);
2224             if (tag)
2225                 fprintf(f, ".%s", tag);
2226             else if (havetags)
2227                 untyped_arg_warning(lineno, "$", arg);
2228             goto loop;
2229         }
2230 #endif
2231     }
2232 #if defined(YYBTYACC)
2233     if (c == '@')
2234     {
2235         if (!locations)
2236         {
2237             int l_lineno = lineno;
2238             char *l_line = dup_line();
2239             char *l_cptr = l_line + (cptr - line);
2240             syntax_error(l_lineno, l_line, l_cptr);
2241         }
2242         if (cptr[1] == '$')
2243         {
2244             fprintf(f, "yyloc");
2245             cptr += 2;
2246             goto loop;
2247         }
2248         else if (isdigit(UCH(cptr[1])))
2249         {
2250             ++cptr;
2251             i = get_number();
2252             if (i == 0)
2253                 fprintf(f, "yystack.p_mark[%d]", -n);
2254             else if (i > maxoffset)
2255             {
2256                 at_warning(lineno, i);
2257                 fprintf(f, "yystack.p_mark[%d]", i - maxoffset);
2258             }
2259             else if (offsets)
2260                 fprintf(f, "yystack.p_mark[%d]", offsets[i]);
2261             goto loop;
2262         }
2263     }
2264 #endif
2265     if (isalpha(c) || c == '_' || c == '$')
2266     {
2267         do
2268         {
2269             putc(c, f);
2270             c = *++cptr;
2271         }
2272         while (isalnum(c) || c == '_' || c == '$');
2273         goto loop;
2274     }
2275     ++cptr;
2276 #if defined(YYBTYACC)
2277     if (backtrack)
2278     {
2279         if (trialaction && c == L_BRAC && depth == 0)
2280         {
2281             ++depth;
2282             putc(L_CURL, f);
2283             goto loop;
2284         }
2285         if (trialaction && c == R_BRAC && depth == 1)
2286         {
2287             --depth;
2288             putc(R_CURL, f);
2289             c = nextc();
2290             if (c == L_BRAC && !haveyyval)
2291             {
2292                 goto loop;
2293             }
2294             if (c == L_CURL && !haveyyval)
2295             {
2296                 fprintf(f, "  if (!yytrial)\n");
2297                 if (!lflag)
2298                     fprintf(f, line_format, lineno, input_file_name);
2299                 trialaction = 0;
2300                 goto loop;
2301             }
2302             fprintf(f, "\nbreak;\n");
2303             FREE(a_line);
2304             if (maxoffset > 0)
2305                 FREE(offsets);
2306             return;
2307         }
2308     }
2309 #endif
2310     putc(c, f);
2311     switch (c)
2312     {
2313     case '\n':
2314         get_line();
2315         if (line)
2316             goto loop;
2317         unterminated_action(a_lineno, a_line, a_cptr);
2318
2319     case ';':
2320         if (depth > 0)
2321             goto loop;
2322         fprintf(f, "\nbreak;\n");
2323         free(a_line);
2324         if (maxoffset > 0)
2325             FREE(offsets);
2326         return;
2327
2328 #if defined(YYBTYACC)
2329     case L_BRAC:
2330         if (backtrack)
2331             ++depth;
2332         goto loop;
2333
2334     case R_BRAC:
2335         if (backtrack)
2336             --depth;
2337         goto loop;
2338 #endif
2339
2340     case L_CURL:
2341         ++depth;
2342         goto loop;
2343
2344     case R_CURL:
2345         if (--depth > 0)
2346             goto loop;
2347 #if defined(YYBTYACC)
2348         if (backtrack)
2349         {
2350             c = nextc();
2351             if (c == L_BRAC && !haveyyval)
2352             {
2353                 trialaction = 1;
2354                 goto loop;
2355             }
2356             if (c == L_CURL && !haveyyval)
2357             {
2358                 fprintf(f, "  if (!yytrial)\n");
2359                 if (!lflag)
2360                     fprintf(f, line_format, lineno, input_file_name);
2361                 goto loop;
2362             }
2363         }
2364 #endif
2365         fprintf(f, "\nbreak;\n");
2366         free(a_line);
2367         if (maxoffset > 0)
2368             FREE(offsets);
2369         return;
2370
2371     case '\'':
2372     case '"':
2373         {
2374             char *s = copy_string(c);
2375             fputs(s, f);
2376             free(s);
2377         }
2378         goto loop;
2379
2380     case '/':
2381         {
2382             char *s = copy_comment();
2383             fputs(s, f);
2384             free(s);
2385         }
2386         goto loop;
2387
2388     default:
2389         goto loop;
2390     }
2391 }
2392
2393 #if defined(YYBTYACC)
2394 static void
2395 copy_destructor(void)
2396 {
2397     int c;
2398     int depth;
2399     char *tag;
2400     bucket *bp;
2401     struct mstring *destructor_text = msnew();
2402     char *code_text;
2403     int a_lineno;
2404     char *a_line;
2405     char *a_cptr;
2406
2407     if (!lflag)
2408         msprintf(destructor_text, line_format, lineno, input_file_name);
2409
2410     cptr = after_blanks(cptr);
2411     if (*cptr == L_CURL)
2412         /* avoid putting curly-braces in first column, to ease editing */
2413         mputc(destructor_text, '\t');
2414     else
2415         syntax_error(lineno, line, cptr);
2416
2417     a_lineno = lineno;
2418     a_line = dup_line();
2419     a_cptr = a_line + (cptr - line);
2420
2421     depth = 0;
2422   loop:
2423     c = *cptr;
2424     if (c == '$')
2425     {
2426         if (cptr[1] == '<')
2427         {
2428             int d_lineno = lineno;
2429             char *d_line = dup_line();
2430             char *d_cptr = d_line + (cptr - line);
2431
2432             ++cptr;
2433             tag = get_tag();
2434             c = *cptr;
2435             if (c == '$')
2436             {
2437                 msprintf(destructor_text, "(*val).%s", tag);
2438                 ++cptr;
2439                 FREE(d_line);
2440                 goto loop;
2441             }
2442             else
2443                 dollar_error(d_lineno, d_line, d_cptr);
2444         }
2445         else if (cptr[1] == '$')
2446         {
2447             /* process '$$' later; replacement is context dependent */
2448             msprintf(destructor_text, "$$");
2449             cptr += 2;
2450             goto loop;
2451         }
2452     }
2453     if (c == '@' && cptr[1] == '$')
2454     {
2455         if (!locations)
2456         {
2457             int l_lineno = lineno;
2458             char *l_line = dup_line();
2459             char *l_cptr = l_line + (cptr - line);
2460             syntax_error(l_lineno, l_line, l_cptr);
2461         }
2462         msprintf(destructor_text, "(*loc)");
2463         cptr += 2;
2464         goto loop;
2465     }
2466     if (isalpha(c) || c == '_' || c == '$')
2467     {
2468         do
2469         {
2470             mputc(destructor_text, c);
2471             c = *++cptr;
2472         }
2473         while (isalnum(c) || c == '_' || c == '$');
2474         goto loop;
2475     }
2476     ++cptr;
2477     mputc(destructor_text, c);
2478     switch (c)
2479     {
2480     case '\n':
2481         get_line();
2482         if (line)
2483             goto loop;
2484         unterminated_action(a_lineno, a_line, a_cptr);
2485
2486     case L_CURL:
2487         ++depth;
2488         goto loop;
2489
2490     case R_CURL:
2491         if (--depth > 0)
2492             goto loop;
2493         goto process_symbols;
2494
2495     case '\'':
2496     case '"':
2497         {
2498             char *s = copy_string(c);
2499             msprintf(destructor_text, "%s", s);
2500             free(s);
2501         }
2502         goto loop;
2503
2504     case '/':
2505         {
2506             char *s = copy_comment();
2507             msprintf(destructor_text, "%s", s);
2508             free(s);
2509         }
2510         goto loop;
2511
2512     default:
2513         goto loop;
2514     }
2515   process_symbols:
2516     code_text = msdone(destructor_text);
2517     for (;;)
2518     {
2519         c = nextc();
2520         if (c == EOF)
2521             unexpected_EOF();
2522         if (c == '<')
2523         {
2524             if (cptr[1] == '>')
2525             {                   /* "no semantic type" default destructor */
2526                 cptr += 2;
2527                 if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
2528                 {
2529                     static char untyped_default[] = "<>";
2530                     bp = make_bucket("untyped default");
2531                     bp->tag = untyped_default;
2532                     default_destructor[UNTYPED_DEFAULT] = bp;
2533                 }
2534                 if (bp->destructor != NULL)
2535                     destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2536                 else
2537                     /* replace "$$" with "(*val)" in destructor code */
2538                     bp->destructor = process_destructor_XX(code_text, NULL);
2539             }
2540             else if (cptr[1] == '*' && cptr[2] == '>')
2541             {                   /* "no per-symbol or per-type" default destructor */
2542                 cptr += 3;
2543                 if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
2544                 {
2545                     static char typed_default[] = "<*>";
2546                     bp = make_bucket("typed default");
2547                     bp->tag = typed_default;
2548                     default_destructor[TYPED_DEFAULT] = bp;
2549                 }
2550                 if (bp->destructor != NULL)
2551                     destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2552                 else
2553                 {
2554                     /* postpone re-processing destructor $$s until end of grammar spec */
2555                     bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2556                     NO_SPACE(bp->destructor);
2557                     strcpy(bp->destructor, code_text);
2558                 }
2559             }
2560             else
2561             {                   /* "semantic type" default destructor */
2562                 tag = get_tag();
2563                 bp = lookup_type_destructor(tag);
2564                 if (bp->destructor != NULL)
2565                     destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2566                 else
2567                     /* replace "$$" with "(*val).tag" in destructor code */
2568                     bp->destructor = process_destructor_XX(code_text, tag);
2569             }
2570         }
2571         else if (isalpha(c) || c == '_' || c == '.' || c == '$')
2572         {                       /* "symbol" destructor */
2573             bp = get_name();
2574             if (bp->destructor != NULL)
2575                 destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2576             else
2577             {
2578                 /* postpone re-processing destructor $$s until end of grammar spec */
2579                 bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2580                 NO_SPACE(bp->destructor);
2581                 strcpy(bp->destructor, code_text);
2582             }
2583         }
2584         else
2585             break;
2586     }
2587     free(a_line);
2588     free(code_text);
2589 }
2590
2591 static char *
2592 process_destructor_XX(char *code, char *tag)
2593 {
2594     int c;
2595     int quote;
2596     int depth;
2597     struct mstring *new_code = msnew();
2598     char *codeptr = code;
2599
2600     depth = 0;
2601   loop:                 /* step thru code */
2602     c = *codeptr;
2603     if (c == '$' && codeptr[1] == '$')
2604     {
2605         codeptr += 2;
2606         if (tag == NULL)
2607             msprintf(new_code, "(*val)");
2608         else
2609             msprintf(new_code, "(*val).%s", tag);
2610         goto loop;
2611     }
2612     if (isalpha(c) || c == '_' || c == '$')
2613     {
2614         do
2615         {
2616             mputc(new_code, c);
2617             c = *++codeptr;
2618         }
2619         while (isalnum(c) || c == '_' || c == '$');
2620         goto loop;
2621     }
2622     ++codeptr;
2623     mputc(new_code, c);
2624     switch (c)
2625     {
2626     case L_CURL:
2627         ++depth;
2628         goto loop;
2629
2630     case R_CURL:
2631         if (--depth > 0)
2632             goto loop;
2633         return msdone(new_code);
2634
2635     case '\'':
2636     case '"':
2637         quote = c;
2638         for (;;)
2639         {
2640             c = *codeptr++;
2641             mputc(new_code, c);
2642             if (c == quote)
2643                 goto loop;
2644             if (c == '\\')
2645             {
2646                 c = *codeptr++;
2647                 mputc(new_code, c);
2648             }
2649         }
2650
2651     case '/':
2652         c = *codeptr;
2653         if (c == '*')
2654         {
2655             mputc(new_code, c);
2656             ++codeptr;
2657             for (;;)
2658             {
2659                 c = *codeptr++;
2660                 mputc(new_code, c);
2661                 if (c == '*' && *codeptr == '/')
2662                 {
2663                     mputc(new_code, '/');
2664                     ++codeptr;
2665                     goto loop;
2666                 }
2667             }
2668         }
2669         goto loop;
2670
2671     default:
2672         goto loop;
2673     }
2674 }
2675 #endif /* defined(YYBTYACC) */
2676
2677 static int
2678 mark_symbol(void)
2679 {
2680     int c;
2681     bucket *bp = NULL;
2682
2683     c = cptr[1];
2684     if (c == '%' || c == '\\')
2685     {
2686         cptr += 2;
2687         return (1);
2688     }
2689
2690     if (c == '=')
2691         cptr += 2;
2692     else if ((c == 'p' || c == 'P') &&
2693              ((c = cptr[2]) == 'r' || c == 'R') &&
2694              ((c = cptr[3]) == 'e' || c == 'E') &&
2695              ((c = cptr[4]) == 'c' || c == 'C') &&
2696              ((c = cptr[5], !IS_IDENT(c))))
2697         cptr += 5;
2698     else
2699         syntax_error(lineno, line, cptr);
2700
2701     c = nextc();
2702     if (isalpha(c) || c == '_' || c == '.' || c == '$')
2703         bp = get_name();
2704     else if (c == '\'' || c == '"')
2705         bp = get_literal();
2706     else
2707     {
2708         syntax_error(lineno, line, cptr);
2709     }
2710
2711     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
2712         prec_redeclared();
2713
2714     rprec[nrules] = bp->prec;
2715     rassoc[nrules] = bp->assoc;
2716     return (0);
2717 }
2718
2719 static void
2720 read_grammar(void)
2721 {
2722     int c;
2723
2724     initialize_grammar();
2725     advance_to_start();
2726
2727     for (;;)
2728     {
2729         c = nextc();
2730         if (c == EOF)
2731             break;
2732         if (isalpha(c)
2733             || c == '_'
2734             || c == '.'
2735             || c == '$'
2736             || c == '\''
2737             || c == '"')
2738             add_symbol();
2739 #if defined(YYBTYACC)
2740         else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC))
2741 #else
2742         else if (c == L_CURL || c == '=')
2743 #endif
2744             copy_action();
2745         else if (c == '|')
2746         {
2747             end_rule();
2748             start_rule(plhs[nrules - 1], 0);
2749             ++cptr;
2750         }
2751         else if (c == '%')
2752         {
2753             if (mark_symbol())
2754                 break;
2755         }
2756         else
2757             syntax_error(lineno, line, cptr);
2758     }
2759     end_rule();
2760 #if defined(YYBTYACC)
2761     if (goal->args > 0)
2762         start_requires_args(goal->name);
2763 #endif
2764 }
2765
2766 static void
2767 free_tags(void)
2768 {
2769     int i;
2770
2771     if (tag_table == 0)
2772         return;
2773
2774     for (i = 0; i < ntags; ++i)
2775     {
2776         assert(tag_table[i]);
2777         FREE(tag_table[i]);
2778     }
2779     FREE(tag_table);
2780 }
2781
2782 static void
2783 pack_names(void)
2784 {
2785     bucket *bp;
2786     char *p, *s, *t;
2787
2788     name_pool_size = 13;        /* 13 == sizeof("$end") + sizeof("$accept") */
2789     for (bp = first_symbol; bp; bp = bp->next)
2790         name_pool_size += strlen(bp->name) + 1;
2791
2792     name_pool = TMALLOC(char, name_pool_size);
2793     NO_SPACE(name_pool);
2794
2795     strcpy(name_pool, "$accept");
2796     strcpy(name_pool + 8, "$end");
2797     t = name_pool + 13;
2798     for (bp = first_symbol; bp; bp = bp->next)
2799     {
2800         p = t;
2801         s = bp->name;
2802         while ((*t++ = *s++) != 0)
2803             continue;
2804         FREE(bp->name);
2805         bp->name = p;
2806     }
2807 }
2808
2809 static void
2810 check_symbols(void)
2811 {
2812     bucket *bp;
2813
2814     if (goal->class == UNKNOWN)
2815         undefined_goal(goal->name);
2816
2817     for (bp = first_symbol; bp; bp = bp->next)
2818     {
2819         if (bp->class == UNKNOWN)
2820         {
2821             undefined_symbol_warning(bp->name);
2822             bp->class = TERM;
2823         }
2824     }
2825 }
2826
2827 static void
2828 protect_string(char *src, char **des)
2829 {
2830     unsigned len;
2831     char *s;
2832     char *d;
2833
2834     *des = src;
2835     if (src)
2836     {
2837         len = 1;
2838         s = src;
2839         while (*s)
2840         {
2841             if ('\\' == *s || '"' == *s)
2842                 len++;
2843             s++;
2844             len++;
2845         }
2846
2847         *des = d = TMALLOC(char, len);
2848         NO_SPACE(d);
2849
2850         s = src;
2851         while (*s)
2852         {
2853             if ('\\' == *s || '"' == *s)
2854                 *d++ = '\\';
2855             *d++ = *s++;
2856         }
2857         *d = '\0';
2858     }
2859 }
2860
2861 static void
2862 pack_symbols(void)
2863 {
2864     bucket *bp;
2865     bucket **v;
2866     Value_t i, j, k, n;
2867 #if defined(YYBTYACC)
2868     Value_t max_tok_pval;
2869 #endif
2870
2871     nsyms = 2;
2872     ntokens = 1;
2873     for (bp = first_symbol; bp; bp = bp->next)
2874     {
2875         ++nsyms;
2876         if (bp->class == TERM)
2877             ++ntokens;
2878     }
2879     start_symbol = (Value_t) ntokens;
2880     nvars = (Value_t) (nsyms - ntokens);
2881
2882     symbol_name = TMALLOC(char *, nsyms);
2883     NO_SPACE(symbol_name);
2884
2885     symbol_value = TMALLOC(Value_t, nsyms);
2886     NO_SPACE(symbol_value);
2887
2888     symbol_prec = TMALLOC(Value_t, nsyms);
2889     NO_SPACE(symbol_prec);
2890
2891     symbol_assoc = TMALLOC(char, nsyms);
2892     NO_SPACE(symbol_assoc);
2893
2894 #if defined(YYBTYACC)
2895     symbol_pval = TMALLOC(Value_t, nsyms);
2896     NO_SPACE(symbol_pval);
2897
2898     if (destructor)
2899     {
2900         symbol_destructor = CALLOC(sizeof(char *), nsyms);
2901         NO_SPACE(symbol_destructor);
2902
2903         symbol_type_tag = CALLOC(sizeof(char *), nsyms);
2904         NO_SPACE(symbol_type_tag);
2905     }
2906 #endif
2907
2908     v = TMALLOC(bucket *, nsyms);
2909     NO_SPACE(v);
2910
2911     v[0] = 0;
2912     v[start_symbol] = 0;
2913
2914     i = 1;
2915     j = (Value_t) (start_symbol + 1);
2916     for (bp = first_symbol; bp; bp = bp->next)
2917     {
2918         if (bp->class == TERM)
2919             v[i++] = bp;
2920         else
2921             v[j++] = bp;
2922     }
2923     assert(i == ntokens && j == nsyms);
2924
2925     for (i = 1; i < ntokens; ++i)
2926         v[i]->index = i;
2927
2928     goal->index = (Index_t) (start_symbol + 1);
2929     k = (Value_t) (start_symbol + 2);
2930     while (++i < nsyms)
2931         if (v[i] != goal)
2932         {
2933             v[i]->index = k;
2934             ++k;
2935         }
2936
2937     goal->value = 0;
2938     k = 1;
2939     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2940     {
2941         if (v[i] != goal)
2942         {
2943             v[i]->value = k;
2944             ++k;
2945         }
2946     }
2947
2948     k = 0;
2949     for (i = 1; i < ntokens; ++i)
2950     {
2951         n = v[i]->value;
2952         if (n > 256)
2953         {
2954             for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2955                 symbol_value[j] = symbol_value[j - 1];
2956             symbol_value[j] = n;
2957         }
2958     }
2959
2960     assert(v[1] != 0);
2961
2962     if (v[1]->value == UNDEFINED)
2963         v[1]->value = 256;
2964
2965     j = 0;
2966     n = 257;
2967     for (i = 2; i < ntokens; ++i)
2968     {
2969         if (v[i]->value == UNDEFINED)
2970         {
2971             while (j < k && n == symbol_value[j])
2972             {
2973                 while (++j < k && n == symbol_value[j])
2974                     continue;
2975                 ++n;
2976             }
2977             v[i]->value = n;
2978             ++n;
2979         }
2980     }
2981
2982     symbol_name[0] = name_pool + 8;
2983     symbol_value[0] = 0;
2984     symbol_prec[0] = 0;
2985     symbol_assoc[0] = TOKEN;
2986 #if defined(YYBTYACC)
2987     symbol_pval[0] = 0;
2988     max_tok_pval = 0;
2989 #endif
2990     for (i = 1; i < ntokens; ++i)
2991     {
2992         symbol_name[i] = v[i]->name;
2993         symbol_value[i] = v[i]->value;
2994         symbol_prec[i] = v[i]->prec;
2995         symbol_assoc[i] = v[i]->assoc;
2996 #if defined(YYBTYACC)
2997         symbol_pval[i] = v[i]->value;
2998         if (symbol_pval[i] > max_tok_pval)
2999             max_tok_pval = symbol_pval[i];
3000         if (destructor)
3001         {
3002             symbol_destructor[i] = v[i]->destructor;
3003             symbol_type_tag[i] = v[i]->tag;
3004         }
3005 #endif
3006     }
3007     symbol_name[start_symbol] = name_pool;
3008     symbol_value[start_symbol] = -1;
3009     symbol_prec[start_symbol] = 0;
3010     symbol_assoc[start_symbol] = TOKEN;
3011 #if defined(YYBTYACC)
3012     symbol_pval[start_symbol] = (Value_t) (max_tok_pval + 1);
3013 #endif
3014     for (++i; i < nsyms; ++i)
3015     {
3016         k = v[i]->index;
3017         symbol_name[k] = v[i]->name;
3018         symbol_value[k] = v[i]->value;
3019         symbol_prec[k] = v[i]->prec;
3020         symbol_assoc[k] = v[i]->assoc;
3021 #if defined(YYBTYACC)
3022         symbol_pval[k] = (Value_t) ((max_tok_pval + 1) + v[i]->value + 1);
3023         if (destructor)
3024         {
3025             symbol_destructor[k] = v[i]->destructor;
3026             symbol_type_tag[k] = v[i]->tag;
3027         }
3028 #endif
3029     }
3030
3031     if (gflag)
3032     {
3033         symbol_pname = TMALLOC(char *, nsyms);
3034         NO_SPACE(symbol_pname);
3035
3036         for (i = 0; i < nsyms; ++i)
3037             protect_string(symbol_name[i], &(symbol_pname[i]));
3038     }
3039
3040     FREE(v);
3041 }
3042
3043 static void
3044 pack_grammar(void)
3045 {
3046     int i;
3047     Value_t j;
3048     Assoc_t assoc;
3049     Value_t prec2;
3050
3051     ritem = TMALLOC(Value_t, nitems);
3052     NO_SPACE(ritem);
3053
3054     rlhs = TMALLOC(Value_t, nrules);
3055     NO_SPACE(rlhs);
3056
3057     rrhs = TMALLOC(Value_t, nrules + 1);
3058     NO_SPACE(rrhs);
3059
3060     rprec = TREALLOC(Value_t, rprec, nrules);
3061     NO_SPACE(rprec);
3062
3063     rassoc = TREALLOC(Assoc_t, rassoc, nrules);
3064     NO_SPACE(rassoc);
3065
3066     ritem[0] = -1;
3067     ritem[1] = goal->index;
3068     ritem[2] = 0;
3069     ritem[3] = -2;
3070     rlhs[0] = 0;
3071     rlhs[1] = 0;
3072     rlhs[2] = start_symbol;
3073     rrhs[0] = 0;
3074     rrhs[1] = 0;
3075     rrhs[2] = 1;
3076
3077     j = 4;
3078     for (i = 3; i < nrules; ++i)
3079     {
3080 #if defined(YYBTYACC)
3081         if (plhs[i]->args > 0)
3082         {
3083             if (plhs[i]->argnames)
3084             {
3085                 FREE(plhs[i]->argnames);
3086                 plhs[i]->argnames = NULL;
3087             }
3088             if (plhs[i]->argtags)
3089             {
3090                 FREE(plhs[i]->argtags);
3091                 plhs[i]->argtags = NULL;
3092             }
3093         }
3094 #endif /* defined(YYBTYACC) */
3095         rlhs[i] = plhs[i]->index;
3096         rrhs[i] = j;
3097         assoc = TOKEN;
3098         prec2 = 0;
3099         while (pitem[j])
3100         {
3101             ritem[j] = pitem[j]->index;
3102             if (pitem[j]->class == TERM)
3103             {
3104                 prec2 = pitem[j]->prec;
3105                 assoc = pitem[j]->assoc;
3106             }
3107             ++j;
3108         }
3109         ritem[j] = (Value_t) - i;
3110         ++j;
3111         if (rprec[i] == UNDEFINED)
3112         {
3113             rprec[i] = prec2;
3114             rassoc[i] = assoc;
3115         }
3116     }
3117     rrhs[i] = j;
3118
3119     FREE(plhs);
3120     FREE(pitem);
3121 #if defined(YYBTYACC)
3122     clean_arg_cache();
3123 #endif
3124 }
3125
3126 static void
3127 print_grammar(void)
3128 {
3129     int i, k;
3130     size_t j, spacing = 0;
3131     FILE *f = verbose_file;
3132
3133     if (!vflag)
3134         return;
3135
3136     k = 1;
3137     for (i = 2; i < nrules; ++i)
3138     {
3139         if (rlhs[i] != rlhs[i - 1])
3140         {
3141             if (i != 2)
3142                 fprintf(f, "\n");
3143             fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
3144             spacing = strlen(symbol_name[rlhs[i]]) + 1;
3145         }
3146         else
3147         {
3148             fprintf(f, "%4d  ", i - 2);
3149             j = spacing;
3150             while (j-- != 0)
3151                 putc(' ', f);
3152             putc('|', f);
3153         }
3154
3155         while (ritem[k] >= 0)
3156         {
3157             fprintf(f, " %s", symbol_name[ritem[k]]);
3158             ++k;
3159         }
3160         ++k;
3161         putc('\n', f);
3162     }
3163 }
3164
3165 #if defined(YYBTYACC)
3166 static void
3167 finalize_destructors(void)
3168 {
3169     int i;
3170     bucket *bp;
3171     char *tag;
3172
3173     for (i = 2; i < nsyms; ++i)
3174     {
3175         tag = symbol_type_tag[i];
3176         if (symbol_destructor[i] == NULL)
3177         {
3178             if (tag == NULL)
3179             {                   /* use <> destructor, if there is one */
3180                 if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3181                 {
3182                     symbol_destructor[i] = TMALLOC(char,
3183                                                    strlen(bp->destructor) + 1);
3184                     NO_SPACE(symbol_destructor[i]);
3185                     strcpy(symbol_destructor[i], bp->destructor);
3186                 }
3187             }
3188             else
3189             {                   /* use type destructor for this tag, if there is one */
3190                 bp = lookup_type_destructor(tag);
3191                 if (bp->destructor != NULL)
3192                 {
3193                     symbol_destructor[i] = TMALLOC(char,
3194                                                    strlen(bp->destructor) + 1);
3195                     NO_SPACE(symbol_destructor[i]);
3196                     strcpy(symbol_destructor[i], bp->destructor);
3197                 }
3198                 else
3199                 {               /* use <*> destructor, if there is one */
3200                     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3201                         /* replace "$$" with "(*val).tag" in destructor code */
3202                         symbol_destructor[i]
3203                             = process_destructor_XX(bp->destructor, tag);
3204                 }
3205             }
3206         }
3207         else
3208         {                       /* replace "$$" with "(*val)[.tag]" in destructor code */
3209             symbol_destructor[i]
3210                 = process_destructor_XX(symbol_destructor[i], tag);
3211         }
3212     }
3213     /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
3214     DO_FREE(symbol_type_tag);   /* no longer needed */
3215     if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3216     {
3217         FREE(bp->name);
3218         /* 'bp->tag' is a static value, don't free */
3219         FREE(bp->destructor);
3220         FREE(bp);
3221     }
3222     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3223     {
3224         FREE(bp->name);
3225         /* 'bp->tag' is a static value, don't free */
3226         FREE(bp->destructor);
3227         FREE(bp);
3228     }
3229     if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
3230     {
3231         bucket *p;
3232         for (; bp; bp = p)
3233         {
3234             p = bp->link;
3235             FREE(bp->name);
3236             /* 'bp->tag' freed by 'free_tags()' */
3237             FREE(bp->destructor);
3238             FREE(bp);
3239         }
3240     }
3241 }
3242 #endif /* defined(YYBTYACC) */
3243
3244 void
3245 reader(void)
3246 {
3247     write_section(code_file, banner);
3248     create_symbol_table();
3249     read_declarations();
3250     read_grammar();
3251     free_symbol_table();
3252     pack_names();
3253     check_symbols();
3254     pack_symbols();
3255     pack_grammar();
3256     free_symbols();
3257     print_grammar();
3258 #if defined(YYBTYACC)
3259     if (destructor)
3260         finalize_destructors();
3261 #endif
3262     free_tags();
3263 }
3264
3265 #ifdef NO_LEAKS
3266 static param *
3267 free_declarations(param * list)
3268 {
3269     while (list != 0)
3270     {
3271         param *next = list->next;
3272         free(list->type);
3273         free(list->name);
3274         free(list->type2);
3275         free(list);
3276         list = next;
3277     }
3278     return list;
3279 }
3280
3281 void
3282 reader_leaks(void)
3283 {
3284     lex_param = free_declarations(lex_param);
3285     parse_param = free_declarations(parse_param);
3286
3287     DO_FREE(line);
3288     DO_FREE(rrhs);
3289     DO_FREE(rlhs);
3290     DO_FREE(rprec);
3291     DO_FREE(ritem);
3292     DO_FREE(rassoc);
3293     DO_FREE(cache);
3294     DO_FREE(name_pool);
3295     DO_FREE(symbol_name);
3296     DO_FREE(symbol_prec);
3297     DO_FREE(symbol_assoc);
3298     DO_FREE(symbol_value);
3299 #if defined(YYBTYACC)
3300     DO_FREE(symbol_pval);
3301     DO_FREE(symbol_destructor);
3302     DO_FREE(symbol_type_tag);
3303 #endif
3304 }
3305 #endif