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