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