Imported Upstream version 20170709
[platform/upstream/byacc.git] / reader.c
1 /* $Id: reader.c,v 1.73 2017/07/09 19:15:35 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[14];
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             n = 0;
1357             break;
1358         }
1359     }
1360
1361     return (Value_t)(n);
1362 }
1363
1364 static char *
1365 cache_tag(char *tag, size_t len)
1366 {
1367     int i;
1368     char *s;
1369
1370     for (i = 0; i < ntags; ++i)
1371     {
1372         if (strncmp(tag, tag_table[i], len) == 0 &&
1373             tag_table[i][len] == NUL)
1374             return (tag_table[i]);
1375     }
1376
1377     if (ntags >= tagmax)
1378     {
1379         tagmax += 16;
1380         tag_table =
1381             (tag_table
1382              ? TREALLOC(char *, tag_table, tagmax)
1383              : TMALLOC(char *, tagmax));
1384         NO_SPACE(tag_table);
1385     }
1386
1387     s = TMALLOC(char, len + 1);
1388     NO_SPACE(s);
1389
1390     strncpy(s, tag, len);
1391     s[len] = 0;
1392     tag_table[ntags++] = s;
1393     return s;
1394 }
1395
1396 static char *
1397 get_tag(void)
1398 {
1399     int c;
1400     int t_lineno = lineno;
1401     char *t_line = dup_line();
1402     char *t_cptr = t_line + (cptr - line);
1403
1404     ++cptr;
1405     c = nextc();
1406     if (c == EOF)
1407         unexpected_EOF();
1408     if (!IS_NAME1(c))
1409         illegal_tag(t_lineno, t_line, t_cptr);
1410
1411     cinc = 0;
1412     do
1413     {
1414         cachec(c);
1415         c = *++cptr;
1416     }
1417     while (IS_IDENT(c));
1418     cachec(NUL);
1419
1420     c = nextc();
1421     if (c == EOF)
1422         unexpected_EOF();
1423     if (c != '>')
1424         illegal_tag(t_lineno, t_line, t_cptr);
1425     ++cptr;
1426
1427     FREE(t_line);
1428     havetags = 1;
1429     return cache_tag(cache, (size_t) cinc);
1430 }
1431
1432 #if defined(YYBTYACC)
1433 static char *
1434 scan_id(void)
1435 {
1436     char *b = cptr;
1437
1438     while (IS_NAME2(UCH(*cptr)))
1439         cptr++;
1440     return cache_tag(b, (size_t) (cptr - b));
1441 }
1442 #endif
1443
1444 static void
1445 declare_tokens(int assoc)
1446 {
1447     int c;
1448     bucket *bp;
1449     Value_t value;
1450     char *tag = 0;
1451
1452     if (assoc != TOKEN)
1453         ++prec;
1454
1455     c = nextc();
1456     if (c == EOF)
1457         unexpected_EOF();
1458     if (c == '<')
1459     {
1460         tag = get_tag();
1461         c = nextc();
1462         if (c == EOF)
1463             unexpected_EOF();
1464     }
1465
1466     for (;;)
1467     {
1468         if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
1469             bp = get_name();
1470         else if (c == '\'' || c == '"')
1471             bp = get_literal();
1472         else
1473             return;
1474
1475         if (bp == goal)
1476             tokenized_start(bp->name);
1477         bp->class = TERM;
1478
1479         if (tag)
1480         {
1481             if (bp->tag && tag != bp->tag)
1482                 retyped_warning(bp->name);
1483             bp->tag = tag;
1484         }
1485
1486         if (assoc != TOKEN)
1487         {
1488             if (bp->prec && prec != bp->prec)
1489                 reprec_warning(bp->name);
1490             bp->assoc = (Assoc_t)assoc;
1491             bp->prec = prec;
1492         }
1493
1494         c = nextc();
1495         if (c == EOF)
1496             unexpected_EOF();
1497
1498         if (isdigit(UCH(c)))
1499         {
1500             value = get_number();
1501             if (bp->value != UNDEFINED && value != bp->value)
1502                 revalued_warning(bp->name);
1503             bp->value = value;
1504             c = nextc();
1505             if (c == EOF)
1506                 unexpected_EOF();
1507         }
1508     }
1509 }
1510
1511 /*
1512  * %expect requires special handling
1513  * as it really isn't part of the yacc
1514  * grammar only a flag for yacc proper.
1515  */
1516 static void
1517 declare_expect(int assoc)
1518 {
1519     int c;
1520
1521     if (assoc != EXPECT && assoc != EXPECT_RR)
1522         ++prec;
1523
1524     /*
1525      * Stay away from nextc - doesn't
1526      * detect EOL and will read to EOF.
1527      */
1528     c = *++cptr;
1529     if (c == EOF)
1530         unexpected_EOF();
1531
1532     for (;;)
1533     {
1534         if (isdigit(UCH(c)))
1535         {
1536             if (assoc == EXPECT)
1537                 SRexpect = get_number();
1538             else
1539                 RRexpect = get_number();
1540             break;
1541         }
1542         /*
1543          * Looking for number before EOL.
1544          * Spaces, tabs, and numbers are ok,
1545          * words, punc., etc. are syntax errors.
1546          */
1547         else if (c == '\n' || isalpha(UCH(c)) || !isspace(UCH(c)))
1548         {
1549             syntax_error(lineno, line, cptr);
1550         }
1551         else
1552         {
1553             c = *++cptr;
1554             if (c == EOF)
1555                 unexpected_EOF();
1556         }
1557     }
1558 }
1559
1560 #if defined(YYBTYACC)
1561 static void
1562 declare_argtypes(bucket *bp)
1563 {
1564     char *tags[MAXARGS];
1565     int args = 0, c;
1566
1567     if (bp->args >= 0)
1568         retyped_warning(bp->name);
1569     cptr++;                     /* skip open paren */
1570     for (;;)
1571     {
1572         c = nextc();
1573         if (c == EOF)
1574             unexpected_EOF();
1575         if (c != '<')
1576             syntax_error(lineno, line, cptr);
1577         tags[args++] = get_tag();
1578         c = nextc();
1579         if (c == R_PAREN)
1580             break;
1581         if (c == EOF)
1582             unexpected_EOF();
1583     }
1584     cptr++;                     /* skip close paren */
1585     bp->args = args;
1586     bp->argnames = TMALLOC(char *, args);
1587     NO_SPACE(bp->argnames);
1588     bp->argtags = CALLOC(sizeof(char *), args + 1);
1589     NO_SPACE(bp->argtags);
1590     while (--args >= 0)
1591     {
1592         bp->argtags[args] = tags[args];
1593         bp->argnames[args] = NULL;
1594     }
1595 }
1596 #endif
1597
1598 static void
1599 declare_types(void)
1600 {
1601     int c;
1602     bucket *bp = NULL;
1603     char *tag = NULL;
1604
1605     c = nextc();
1606     if (c == EOF)
1607         unexpected_EOF();
1608     if (c == '<')
1609         tag = get_tag();
1610
1611     for (;;)
1612     {
1613         c = nextc();
1614         if (c == EOF)
1615             unexpected_EOF();
1616         if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
1617         {
1618             bp = get_name();
1619 #if defined(YYBTYACC)
1620             if (nextc() == L_PAREN)
1621                 declare_argtypes(bp);
1622             else
1623                 bp->args = 0;
1624 #endif
1625         }
1626         else if (c == '\'' || c == '"')
1627         {
1628             bp = get_literal();
1629 #if defined(YYBTYACC)
1630             bp->args = 0;
1631 #endif
1632         }
1633         else
1634             return;
1635
1636         if (tag)
1637         {
1638             if (bp->tag && tag != bp->tag)
1639                 retyped_warning(bp->name);
1640             bp->tag = tag;
1641         }
1642     }
1643 }
1644
1645 static void
1646 declare_start(void)
1647 {
1648     int c;
1649     bucket *bp;
1650
1651     c = nextc();
1652     if (c == EOF)
1653         unexpected_EOF();
1654     if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '$')
1655         syntax_error(lineno, line, cptr);
1656     bp = get_name();
1657     if (bp->class == TERM)
1658         terminal_start(bp->name);
1659     if (goal && goal != bp)
1660         restarted_warning();
1661     goal = bp;
1662 }
1663
1664 static void
1665 read_declarations(void)
1666 {
1667     int c, k;
1668
1669     cache_size = CACHE_SIZE;
1670     cache = TMALLOC(char, cache_size);
1671     NO_SPACE(cache);
1672
1673     for (;;)
1674     {
1675         c = nextc();
1676         if (c == EOF)
1677             unexpected_EOF();
1678         if (c != '%')
1679             syntax_error(lineno, line, cptr);
1680         switch (k = keyword())
1681         {
1682         case MARK:
1683             return;
1684
1685         case IDENT:
1686             copy_ident();
1687             break;
1688
1689         case TEXT:
1690             copy_text();
1691             break;
1692
1693         case UNION:
1694             copy_union();
1695             break;
1696
1697         case TOKEN:
1698         case LEFT:
1699         case RIGHT:
1700         case NONASSOC:
1701             declare_tokens(k);
1702             break;
1703
1704         case EXPECT:
1705         case EXPECT_RR:
1706             declare_expect(k);
1707             break;
1708
1709         case TYPE:
1710             declare_types();
1711             break;
1712
1713         case START:
1714             declare_start();
1715             break;
1716
1717         case PURE_PARSER:
1718             pure_parser = 1;
1719             break;
1720
1721         case PARSE_PARAM:
1722         case LEX_PARAM:
1723             copy_param(k);
1724             break;
1725
1726         case TOKEN_TABLE:
1727             token_table = 1;
1728             break;
1729
1730         case ERROR_VERBOSE:
1731             error_verbose = 1;
1732             break;
1733
1734 #if defined(YYBTYACC)
1735         case LOCATIONS:
1736             locations = 1;
1737             break;
1738
1739         case DESTRUCTOR:
1740             destructor = 1;
1741             copy_destructor();
1742             break;
1743         case INITIAL_ACTION:
1744             copy_initial_action();
1745             break;
1746 #endif
1747
1748         case XXXDEBUG:
1749             /* XXX: FIXME */
1750             break;
1751
1752         case POSIX_YACC:
1753             /* noop for bison compatibility. byacc is already designed to be posix
1754              * yacc compatible. */
1755             break;
1756         }
1757     }
1758 }
1759
1760 static void
1761 initialize_grammar(void)
1762 {
1763     nitems = 4;
1764     maxitems = 300;
1765
1766     pitem = TMALLOC(bucket *, maxitems);
1767     NO_SPACE(pitem);
1768
1769     pitem[0] = 0;
1770     pitem[1] = 0;
1771     pitem[2] = 0;
1772     pitem[3] = 0;
1773
1774     nrules = 3;
1775     maxrules = 100;
1776
1777     plhs = TMALLOC(bucket *, maxrules);
1778     NO_SPACE(plhs);
1779
1780     plhs[0] = 0;
1781     plhs[1] = 0;
1782     plhs[2] = 0;
1783
1784     rprec = TMALLOC(Value_t, maxrules);
1785     NO_SPACE(rprec);
1786
1787     rprec[0] = 0;
1788     rprec[1] = 0;
1789     rprec[2] = 0;
1790
1791     rassoc = TMALLOC(Assoc_t, maxrules);
1792     NO_SPACE(rassoc);
1793
1794     rassoc[0] = TOKEN;
1795     rassoc[1] = TOKEN;
1796     rassoc[2] = TOKEN;
1797 }
1798
1799 static void
1800 expand_items(void)
1801 {
1802     maxitems += 300;
1803     pitem = TREALLOC(bucket *, pitem, maxitems);
1804     NO_SPACE(pitem);
1805 }
1806
1807 static void
1808 expand_rules(void)
1809 {
1810     maxrules += 100;
1811
1812     plhs = TREALLOC(bucket *, plhs, maxrules);
1813     NO_SPACE(plhs);
1814
1815     rprec = TREALLOC(Value_t, rprec, maxrules);
1816     NO_SPACE(rprec);
1817
1818     rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
1819     NO_SPACE(rassoc);
1820 }
1821
1822 /* set immediately prior to where copy_args() could be called, and incremented by
1823    the various routines that will rescan the argument list as appropriate */
1824 static int rescan_lineno;
1825 #if defined(YYBTYACC)
1826
1827 static char *
1828 copy_args(int *alen)
1829 {
1830     struct mstring *s = msnew();
1831     int depth = 0, len = 1;
1832     char c, quote = 0;
1833     struct ainfo a;
1834
1835     a.a_lineno = lineno;
1836     a.a_line = dup_line();
1837     a.a_cptr = a.a_line + (cptr - line - 1);
1838
1839     while ((c = *cptr++) != R_PAREN || depth || quote)
1840     {
1841         if (c == ',' && !quote && !depth)
1842         {
1843             len++;
1844             mputc(s, 0);
1845             continue;
1846         }
1847         mputc(s, c);
1848         if (c == '\n')
1849         {
1850             get_line();
1851             if (!line)
1852             {
1853                 if (quote)
1854                     unterminated_string(&a);
1855                 else
1856                     unterminated_arglist(&a);
1857             }
1858         }
1859         else if (quote)
1860         {
1861             if (c == quote)
1862                 quote = 0;
1863             else if (c == '\\')
1864             {
1865                 if (*cptr != '\n')
1866                     mputc(s, *cptr++);
1867             }
1868         }
1869         else
1870         {
1871             if (c == L_PAREN)
1872                 depth++;
1873             else if (c == R_PAREN)
1874                 depth--;
1875             else if (c == '\"' || c == '\'')
1876                 quote = c;
1877         }
1878     }
1879     if (alen)
1880         *alen = len;
1881     FREE(a.a_line);
1882     return msdone(s);
1883 }
1884
1885 static char *
1886 parse_id(char *p, char **save)
1887 {
1888     char *b;
1889
1890     while (isspace(UCH(*p)))
1891         if (*p++ == '\n')
1892             rescan_lineno++;
1893     if (!isalpha(UCH(*p)) && *p != '_')
1894         return NULL;
1895     b = p;
1896     while (IS_NAME2(UCH(*p)))
1897         p++;
1898     if (save)
1899     {
1900         *save = cache_tag(b, (size_t) (p - b));
1901     }
1902     return p;
1903 }
1904
1905 static char *
1906 parse_int(char *p, int *save)
1907 {
1908     int neg = 0, val = 0;
1909
1910     while (isspace(UCH(*p)))
1911         if (*p++ == '\n')
1912             rescan_lineno++;
1913     if (*p == '-')
1914     {
1915         neg = 1;
1916         p++;
1917     }
1918     if (!isdigit(UCH(*p)))
1919         return NULL;
1920     while (isdigit(UCH(*p)))
1921         val = val * 10 + *p++ - '0';
1922     if (neg)
1923         val = -val;
1924     if (save)
1925         *save = val;
1926     return p;
1927 }
1928
1929 static void
1930 parse_arginfo(bucket *a, char *args, int argslen)
1931 {
1932     char *p = args, *tmp;
1933     int i, redec = 0;
1934
1935     if (a->args >= 0)
1936     {
1937         if (a->args != argslen)
1938             arg_number_disagree_warning(rescan_lineno, a->name);
1939         redec = 1;
1940     }
1941     else
1942     {
1943         if ((a->args = argslen) == 0)
1944             return;
1945         a->argnames = TMALLOC(char *, argslen);
1946         NO_SPACE(a->argnames);
1947         a->argtags = TMALLOC(char *, argslen);
1948         NO_SPACE(a->argtags);
1949     }
1950     if (!args)
1951         return;
1952     for (i = 0; i < argslen; i++)
1953     {
1954         while (isspace(UCH(*p)))
1955             if (*p++ == '\n')
1956                 rescan_lineno++;
1957         if (*p++ != '$')
1958             bad_formals();
1959         while (isspace(UCH(*p)))
1960             if (*p++ == '\n')
1961                 rescan_lineno++;
1962         if (*p == '<')
1963         {
1964             havetags = 1;
1965             if (!(p = parse_id(p + 1, &tmp)))
1966                 bad_formals();
1967             while (isspace(UCH(*p)))
1968                 if (*p++ == '\n')
1969                     rescan_lineno++;
1970             if (*p++ != '>')
1971                 bad_formals();
1972             if (redec)
1973             {
1974                 if (a->argtags[i] != tmp)
1975                     arg_type_disagree_warning(rescan_lineno, i + 1, a->name);
1976             }
1977             else
1978                 a->argtags[i] = tmp;
1979         }
1980         else if (!redec)
1981             a->argtags[i] = NULL;
1982         if (!(p = parse_id(p, &a->argnames[i])))
1983             bad_formals();
1984         while (isspace(UCH(*p)))
1985             if (*p++ == '\n')
1986                 rescan_lineno++;
1987         if (*p++)
1988             bad_formals();
1989     }
1990     free(args);
1991 }
1992
1993 static char *
1994 compile_arg(char **theptr, char *yyvaltag)
1995 {
1996     char *p = *theptr;
1997     struct mstring *c = msnew();
1998     int i, j, n;
1999     Value_t *offsets = NULL, maxoffset;
2000     bucket **rhs;
2001
2002     maxoffset = 0;
2003     n = 0;
2004     for (i = nitems - 1; pitem[i]; --i)
2005     {
2006         n++;
2007         if (pitem[i]->class != ARGUMENT)
2008             maxoffset++;
2009     }
2010     if (maxoffset > 0)
2011     {
2012         offsets = TMALLOC(Value_t, maxoffset + 1);
2013         NO_SPACE(offsets);
2014
2015         for (j = 0, i++; i < nitems; i++)
2016             if (pitem[i]->class != ARGUMENT)
2017                 offsets[++j] = (Value_t)(i - nitems + 1);
2018     }
2019     rhs = pitem + nitems - 1;
2020
2021     if (yyvaltag)
2022         msprintf(c, "yyval.%s = ", yyvaltag);
2023     else
2024         msprintf(c, "yyval = ");
2025     while (*p)
2026     {
2027         if (*p == '$')
2028         {
2029             char *tag = NULL;
2030             if (*++p == '<')
2031                 if (!(p = parse_id(++p, &tag)) || *p++ != '>')
2032                     illegal_tag(rescan_lineno, NULL, NULL);
2033             if (isdigit(UCH(*p)) || *p == '-')
2034             {
2035                 int val;
2036                 if (!(p = parse_int(p, &val)))
2037                     dollar_error(rescan_lineno, NULL, NULL);
2038                 if (val <= 0)
2039                     i = val - n;
2040                 else if (val > maxoffset)
2041                 {
2042                     dollar_warning(rescan_lineno, val);
2043                     i = val - maxoffset;
2044                 }
2045                 else if (maxoffset > 0)
2046                 {
2047                     i = offsets[val];
2048                     if (!tag && !(tag = rhs[i]->tag) && havetags)
2049                         untyped_rhs(val, rhs[i]->name);
2050                 }
2051                 msprintf(c, "yystack.l_mark[%d]", i);
2052                 if (tag)
2053                     msprintf(c, ".%s", tag);
2054                 else if (havetags)
2055                     unknown_rhs(val);
2056             }
2057             else if (isalpha(UCH(*p)) || *p == '_')
2058             {
2059                 char *arg;
2060                 if (!(p = parse_id(p, &arg)))
2061                     dollar_error(rescan_lineno, NULL, NULL);
2062                 for (i = plhs[nrules]->args - 1; i >= 0; i--)
2063                     if (arg == plhs[nrules]->argnames[i])
2064                         break;
2065                 if (i < 0)
2066                     unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL);
2067                 else if (!tag)
2068                     tag = plhs[nrules]->argtags[i];
2069                 msprintf(c, "yystack.l_mark[%d]",
2070                          i - plhs[nrules]->args + 1 - n);
2071                 if (tag)
2072                     msprintf(c, ".%s", tag);
2073                 else if (havetags)
2074                     untyped_arg_warning(rescan_lineno, "$", arg);
2075             }
2076             else
2077                 dollar_error(rescan_lineno, NULL, NULL);
2078         }
2079         else if (*p == '@')
2080         {
2081             at_error(rescan_lineno, NULL, NULL);
2082         }
2083         else
2084         {
2085             if (*p == '\n')
2086                 rescan_lineno++;
2087             mputc(c, *p++);
2088         }
2089     }
2090     *theptr = p;
2091     if (maxoffset > 0)
2092         FREE(offsets);
2093     return msdone(c);
2094 }
2095
2096 static int
2097 can_elide_arg(char **theptr, char *yyvaltag)
2098 {
2099     char *p = *theptr;
2100     int rv = 0;
2101     int i, j, n = 0;
2102     Value_t *offsets = NULL, maxoffset = 0;
2103     bucket **rhs;
2104     char *tag = 0;
2105
2106     if (*p++ != '$')
2107         return 0;
2108     if (*p == '<')
2109     {
2110         if (!(p = parse_id(++p, &tag)) || *p++ != '>')
2111             return 0;
2112     }
2113     for (i = nitems - 1; pitem[i]; --i)
2114     {
2115         n++;
2116         if (pitem[i]->class != ARGUMENT)
2117             maxoffset++;
2118     }
2119     if (maxoffset > 0)
2120     {
2121         offsets = TMALLOC(Value_t, maxoffset + 1);
2122         NO_SPACE(offsets);
2123
2124         for (j = 0, i++; i < nitems; i++)
2125             if (pitem[i]->class != ARGUMENT)
2126                 offsets[++j] = (Value_t)(i - nitems + 1);
2127     }
2128     rhs = pitem + nitems - 1;
2129
2130     if (isdigit(UCH(*p)) || *p == '-')
2131     {
2132         int val;
2133         if (!(p = parse_int(p, &val)))
2134             rv = 0;
2135         else
2136         {
2137             if (val <= 0)
2138                 rv = 1 - val + n;
2139             else if (val > maxoffset)
2140                 rv = 0;
2141             else
2142             {
2143                 i = offsets[val];
2144                 rv = 1 - i;
2145                 if (!tag)
2146                     tag = rhs[i]->tag;
2147             }
2148         }
2149     }
2150     else if (isalpha(UCH(*p)) || *p == '_')
2151     {
2152         char *arg;
2153         if (!(p = parse_id(p, &arg)))
2154             return 0;
2155         for (i = plhs[nrules]->args - 1; i >= 0; i--)
2156             if (arg == plhs[nrules]->argnames[i])
2157                 break;
2158         if (i >= 0)
2159         {
2160             if (!tag)
2161                 tag = plhs[nrules]->argtags[i];
2162             rv = plhs[nrules]->args + n - i;
2163         }
2164     }
2165     if (tag && yyvaltag)
2166     {
2167         if (strcmp(tag, yyvaltag))
2168             rv = 0;
2169     }
2170     else if (tag || yyvaltag)
2171         rv = 0;
2172     if (maxoffset > 0)
2173         FREE(offsets);
2174     if (*p || rv <= 0)
2175         return 0;
2176     *theptr = p + 1;
2177     return rv;
2178 }
2179
2180 #define ARG_CACHE_SIZE  1024
2181 static struct arg_cache
2182 {
2183     struct arg_cache *next;
2184     char *code;
2185     int rule;
2186 }
2187  *arg_cache[ARG_CACHE_SIZE];
2188
2189 static int
2190 lookup_arg_cache(char *code)
2191 {
2192     struct arg_cache *entry;
2193
2194     entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE];
2195     while (entry)
2196     {
2197         if (!strnscmp(entry->code, code))
2198             return entry->rule;
2199         entry = entry->next;
2200     }
2201     return -1;
2202 }
2203
2204 static void
2205 insert_arg_cache(char *code, int rule)
2206 {
2207     struct arg_cache *entry = NEW(struct arg_cache);
2208     int i;
2209
2210     NO_SPACE(entry);
2211     i = strnshash(code) % ARG_CACHE_SIZE;
2212     entry->code = code;
2213     entry->rule = rule;
2214     entry->next = arg_cache[i];
2215     arg_cache[i] = entry;
2216 }
2217
2218 static void
2219 clean_arg_cache(void)
2220 {
2221     struct arg_cache *e, *t;
2222     int i;
2223
2224     for (i = 0; i < ARG_CACHE_SIZE; i++)
2225     {
2226         for (e = arg_cache[i]; (t = e); e = e->next, FREE(t))
2227             free(e->code);
2228         arg_cache[i] = NULL;
2229     }
2230 }
2231 #endif /* defined(YYBTYACC) */
2232
2233 static void
2234 advance_to_start(void)
2235 {
2236     int c;
2237     bucket *bp;
2238     char *s_cptr;
2239     int s_lineno;
2240 #if defined(YYBTYACC)
2241     char *args = NULL;
2242     int argslen = 0;
2243 #endif
2244
2245     for (;;)
2246     {
2247         c = nextc();
2248         if (c != '%')
2249             break;
2250         s_cptr = cptr;
2251         switch (keyword())
2252         {
2253         case MARK:
2254             no_grammar();
2255
2256         case TEXT:
2257             copy_text();
2258             break;
2259
2260         case START:
2261             declare_start();
2262             break;
2263
2264         default:
2265             syntax_error(lineno, line, s_cptr);
2266         }
2267     }
2268
2269     c = nextc();
2270     if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '_')
2271         syntax_error(lineno, line, cptr);
2272     bp = get_name();
2273     if (goal == 0)
2274     {
2275         if (bp->class == TERM)
2276             terminal_start(bp->name);
2277         goal = bp;
2278     }
2279
2280     s_lineno = lineno;
2281     c = nextc();
2282     if (c == EOF)
2283         unexpected_EOF();
2284     rescan_lineno = lineno;     /* line# for possible inherited args rescan */
2285 #if defined(YYBTYACC)
2286     if (c == L_PAREN)
2287     {
2288         ++cptr;
2289         args = copy_args(&argslen);
2290         NO_SPACE(args);
2291         c = nextc();
2292     }
2293 #endif
2294     if (c != ':')
2295         syntax_error(lineno, line, cptr);
2296     start_rule(bp, s_lineno);
2297 #if defined(YYBTYACC)
2298     parse_arginfo(bp, args, argslen);
2299 #endif
2300     ++cptr;
2301 }
2302
2303 static void
2304 start_rule(bucket *bp, int s_lineno)
2305 {
2306     if (bp->class == TERM)
2307         terminal_lhs(s_lineno);
2308     bp->class = NONTERM;
2309     if (!bp->index)
2310         bp->index = nrules;
2311     if (nrules >= maxrules)
2312         expand_rules();
2313     plhs[nrules] = bp;
2314     rprec[nrules] = UNDEFINED;
2315     rassoc[nrules] = TOKEN;
2316 }
2317
2318 static void
2319 end_rule(void)
2320 {
2321     int i;
2322
2323     if (!last_was_action && plhs[nrules]->tag)
2324     {
2325         if (pitem[nitems - 1])
2326         {
2327             for (i = nitems - 1; (i > 0) && pitem[i]; --i)
2328                 continue;
2329             if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
2330                 default_action_warning(plhs[nrules]->name);
2331         }
2332         else
2333             default_action_warning(plhs[nrules]->name);
2334     }
2335
2336     last_was_action = 0;
2337     if (nitems >= maxitems)
2338         expand_items();
2339     pitem[nitems] = 0;
2340     ++nitems;
2341     ++nrules;
2342 }
2343
2344 static void
2345 insert_empty_rule(void)
2346 {
2347     bucket *bp, **bpp;
2348
2349     assert(cache);
2350     assert(cache_size >= CACHE_SIZE);
2351     sprintf(cache, "$$%d", ++gensym);
2352     bp = make_bucket(cache);
2353     last_symbol->next = bp;
2354     last_symbol = bp;
2355     bp->tag = plhs[nrules]->tag;
2356     bp->class = ACTION;
2357 #if defined(YYBTYACC)
2358     bp->args = 0;
2359 #endif
2360
2361     nitems = (Value_t)(nitems + 2);
2362     if (nitems > maxitems)
2363         expand_items();
2364     bpp = pitem + nitems - 1;
2365     *bpp-- = bp;
2366     while ((bpp[0] = bpp[-1]) != 0)
2367         --bpp;
2368
2369     if (++nrules >= maxrules)
2370         expand_rules();
2371     plhs[nrules] = plhs[nrules - 1];
2372     plhs[nrules - 1] = bp;
2373     rprec[nrules] = rprec[nrules - 1];
2374     rprec[nrules - 1] = 0;
2375     rassoc[nrules] = rassoc[nrules - 1];
2376     rassoc[nrules - 1] = TOKEN;
2377 }
2378
2379 #if defined(YYBTYACC)
2380 static char *
2381 insert_arg_rule(char *arg, char *tag)
2382 {
2383     int line_number = rescan_lineno;
2384     char *code = compile_arg(&arg, tag);
2385     int rule = lookup_arg_cache(code);
2386     FILE *f = action_file;
2387
2388     if (rule < 0)
2389     {
2390         rule = nrules;
2391         insert_arg_cache(code, rule);
2392         trialaction = 1;        /* arg rules always run in trial mode */
2393         fprintf(f, "case %d:\n", rule - 2);
2394         if (!lflag)
2395             fprintf(f, line_format, line_number, input_file_name);
2396         fprintf(f, "%s;\n", code);
2397         fprintf(f, "break;\n");
2398         insert_empty_rule();
2399         plhs[rule]->tag = cache_tag(tag, strlen(tag));
2400         plhs[rule]->class = ARGUMENT;
2401     }
2402     else
2403     {
2404         if (++nitems > maxitems)
2405             expand_items();
2406         pitem[nitems - 1] = plhs[rule];
2407         free(code);
2408     }
2409     return arg + 1;
2410 }
2411 #endif
2412
2413 static void
2414 add_symbol(void)
2415 {
2416     int c;
2417     bucket *bp;
2418     int s_lineno = lineno;
2419 #if defined(YYBTYACC)
2420     char *args = NULL;
2421     int argslen = 0;
2422 #endif
2423
2424     c = *cptr;
2425     if (c == '\'' || c == '"')
2426         bp = get_literal();
2427     else
2428         bp = get_name();
2429
2430     c = nextc();
2431     rescan_lineno = lineno;     /* line# for possible inherited args rescan */
2432 #if defined(YYBTYACC)
2433     if (c == L_PAREN)
2434     {
2435         ++cptr;
2436         args = copy_args(&argslen);
2437         NO_SPACE(args);
2438         c = nextc();
2439     }
2440 #endif
2441     if (c == ':')
2442     {
2443         end_rule();
2444         start_rule(bp, s_lineno);
2445 #if defined(YYBTYACC)
2446         parse_arginfo(bp, args, argslen);
2447 #endif
2448         ++cptr;
2449         return;
2450     }
2451
2452     if (last_was_action)
2453         insert_empty_rule();
2454     last_was_action = 0;
2455
2456 #if defined(YYBTYACC)
2457     if (bp->args < 0)
2458         bp->args = argslen;
2459     if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
2460     {
2461         int i;
2462         if (plhs[nrules]->args != bp->args)
2463             wrong_number_args_warning("default ", bp->name);
2464         for (i = bp->args - 1; i >= 0; i--)
2465             if (plhs[nrules]->argtags[i] != bp->argtags[i])
2466                 wrong_type_for_arg_warning(i + 1, bp->name);
2467     }
2468     else if (bp->args != argslen)
2469         wrong_number_args_warning("", bp->name);
2470     if (args != 0)
2471     {
2472         char *ap = args;
2473         int i = 0;
2474         int elide_cnt = can_elide_arg(&ap, bp->argtags[0]);
2475
2476         if (elide_cnt > argslen)
2477             elide_cnt = 0;
2478         if (elide_cnt)
2479         {
2480             for (i = 1; i < elide_cnt; i++)
2481                 if (can_elide_arg(&ap, bp->argtags[i]) != elide_cnt - i)
2482                 {
2483                     elide_cnt = 0;
2484                     break;
2485                 }
2486         }
2487         if (elide_cnt)
2488         {
2489             assert(i == elide_cnt);
2490         }
2491         else
2492         {
2493             ap = args;
2494             i = 0;
2495         }
2496         for (; i < argslen; i++)
2497             ap = insert_arg_rule(ap, bp->argtags[i]);
2498         free(args);
2499     }
2500 #endif /* defined(YYBTYACC) */
2501
2502     if (++nitems > maxitems)
2503         expand_items();
2504     pitem[nitems - 1] = bp;
2505 }
2506
2507 static void
2508 copy_action(void)
2509 {
2510     int c;
2511     int i, j, n;
2512     int depth;
2513 #if defined(YYBTYACC)
2514     int haveyyval = 0;
2515 #endif
2516     char *tag;
2517     FILE *f = action_file;
2518     struct ainfo a;
2519     Value_t *offsets = NULL, maxoffset;
2520     bucket **rhs;
2521
2522     a.a_lineno = lineno;
2523     a.a_line = dup_line();
2524     a.a_cptr = a.a_line + (cptr - line);
2525
2526     if (last_was_action)
2527         insert_empty_rule();
2528     last_was_action = 1;
2529 #if defined(YYBTYACC)
2530     trialaction = (*cptr == L_BRAC);
2531 #endif
2532
2533     fprintf(f, "case %d:\n", nrules - 2);
2534 #if defined(YYBTYACC)
2535     if (backtrack)
2536     {
2537         if (!trialaction)
2538             fprintf(f, "  if (!yytrial)\n");
2539     }
2540 #endif
2541     if (!lflag)
2542         fprintf(f, line_format, lineno, input_file_name);
2543     if (*cptr == '=')
2544         ++cptr;
2545
2546     /* avoid putting curly-braces in first column, to ease editing */
2547     if (*after_blanks(cptr) == L_CURL)
2548     {
2549         putc('\t', f);
2550         cptr = after_blanks(cptr);
2551     }
2552
2553     maxoffset = 0;
2554     n = 0;
2555     for (i = nitems - 1; pitem[i]; --i)
2556     {
2557         ++n;
2558         if (pitem[i]->class != ARGUMENT)
2559             maxoffset++;
2560     }
2561     if (maxoffset > 0)
2562     {
2563         offsets = TMALLOC(Value_t, maxoffset + 1);
2564         NO_SPACE(offsets);
2565
2566         for (j = 0, i++; i < nitems; i++)
2567         {
2568             if (pitem[i]->class != ARGUMENT)
2569             {
2570                 offsets[++j] = (Value_t)(i - nitems + 1);
2571             }
2572         }
2573     }
2574     rhs = pitem + nitems - 1;
2575
2576     depth = 0;
2577   loop:
2578     c = *cptr;
2579     if (c == '$')
2580     {
2581         if (cptr[1] == '<')
2582         {
2583             int d_lineno = lineno;
2584             char *d_line = dup_line();
2585             char *d_cptr = d_line + (cptr - line);
2586
2587             ++cptr;
2588             tag = get_tag();
2589             c = *cptr;
2590             if (c == '$')
2591             {
2592                 fprintf(f, "yyval.%s", tag);
2593                 ++cptr;
2594                 FREE(d_line);
2595                 goto loop;
2596             }
2597             else if (isdigit(UCH(c)))
2598             {
2599                 i = get_number();
2600                 if (i == 0)
2601                     fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
2602                 else if (i > maxoffset)
2603                 {
2604                     dollar_warning(d_lineno, i);
2605                     fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag);
2606                 }
2607                 else if (offsets)
2608                     fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2609                 FREE(d_line);
2610                 goto loop;
2611             }
2612             else if (c == '-' && isdigit(UCH(cptr[1])))
2613             {
2614                 ++cptr;
2615                 i = -get_number() - n;
2616                 fprintf(f, "yystack.l_mark[%d].%s", i, tag);
2617                 FREE(d_line);
2618                 goto loop;
2619             }
2620 #if defined(YYBTYACC)
2621             else if (isalpha(UCH(c)) || c == '_')
2622             {
2623                 char *arg = scan_id();
2624                 for (i = plhs[nrules]->args - 1; i >= 0; i--)
2625                     if (arg == plhs[nrules]->argnames[i])
2626                         break;
2627                 if (i < 0)
2628                     unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
2629                 fprintf(f, "yystack.l_mark[%d].%s",
2630                         i - plhs[nrules]->args + 1 - n, tag);
2631                 FREE(d_line);
2632                 goto loop;
2633             }
2634 #endif
2635             else
2636                 dollar_error(d_lineno, d_line, d_cptr);
2637         }
2638         else if (cptr[1] == '$')
2639         {
2640             if (havetags)
2641             {
2642                 tag = plhs[nrules]->tag;
2643                 if (tag == 0)
2644                     untyped_lhs();
2645                 fprintf(f, "yyval.%s", tag);
2646             }
2647             else
2648                 fprintf(f, "yyval");
2649             cptr += 2;
2650 #if defined(YYBTYACC)
2651             haveyyval = 1;
2652 #endif
2653             goto loop;
2654         }
2655         else if (isdigit(UCH(cptr[1])))
2656         {
2657             ++cptr;
2658             i = get_number();
2659             if (havetags && offsets)
2660             {
2661                 if (i <= 0 || i > maxoffset)
2662                     unknown_rhs(i);
2663                 tag = rhs[offsets[i]]->tag;
2664                 if (tag == 0)
2665                     untyped_rhs(i, rhs[offsets[i]]->name);
2666                 fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2667             }
2668             else
2669             {
2670                 if (i == 0)
2671                     fprintf(f, "yystack.l_mark[%d]", -n);
2672                 else if (i > maxoffset)
2673                 {
2674                     dollar_warning(lineno, i);
2675                     fprintf(f, "yystack.l_mark[%d]", i - maxoffset);
2676                 }
2677                 else if (offsets)
2678                     fprintf(f, "yystack.l_mark[%d]", offsets[i]);
2679             }
2680             goto loop;
2681         }
2682         else if (cptr[1] == '-')
2683         {
2684             cptr += 2;
2685             i = get_number();
2686             if (havetags)
2687                 unknown_rhs(-i);
2688             fprintf(f, "yystack.l_mark[%d]", -i - n);
2689             goto loop;
2690         }
2691 #if defined(YYBTYACC)
2692         else if (isalpha(UCH(cptr[1])) || cptr[1] == '_')
2693         {
2694             char *arg;
2695             ++cptr;
2696             arg = scan_id();
2697             for (i = plhs[nrules]->args - 1; i >= 0; i--)
2698                 if (arg == plhs[nrules]->argnames[i])
2699                     break;
2700             if (i < 0)
2701                 unknown_arg_warning(lineno, "$", arg, line, cptr);
2702             tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]);
2703             fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n);
2704             if (tag)
2705                 fprintf(f, ".%s", tag);
2706             else if (havetags)
2707                 untyped_arg_warning(lineno, "$", arg);
2708             goto loop;
2709         }
2710 #endif
2711     }
2712 #if defined(YYBTYACC)
2713     if (c == '@')
2714     {
2715         if (!locations)
2716         {
2717             int l_lineno = lineno;
2718             char *l_line = dup_line();
2719             char *l_cptr = l_line + (cptr - line);
2720             syntax_error(l_lineno, l_line, l_cptr);
2721         }
2722         if (cptr[1] == '$')
2723         {
2724             fprintf(f, "yyloc");
2725             cptr += 2;
2726             goto loop;
2727         }
2728         else if (isdigit(UCH(cptr[1])))
2729         {
2730             ++cptr;
2731             i = get_number();
2732             if (i == 0)
2733                 fprintf(f, "yystack.p_mark[%d]", -n);
2734             else if (i > maxoffset)
2735             {
2736                 at_warning(lineno, i);
2737                 fprintf(f, "yystack.p_mark[%d]", i - maxoffset);
2738             }
2739             else if (offsets)
2740                 fprintf(f, "yystack.p_mark[%d]", offsets[i]);
2741             goto loop;
2742         }
2743         else if (cptr[1] == '-')
2744         {
2745             cptr += 2;
2746             i = get_number();
2747             fprintf(f, "yystack.p_mark[%d]", -i - n);
2748             goto loop;
2749         }
2750     }
2751 #endif
2752     if (IS_NAME1(c))
2753     {
2754         do
2755         {
2756             putc(c, f);
2757             c = *++cptr;
2758         }
2759         while (IS_NAME2(c));
2760         goto loop;
2761     }
2762     ++cptr;
2763 #if defined(YYBTYACC)
2764     if (backtrack)
2765     {
2766         if (trialaction && c == L_BRAC && depth == 0)
2767         {
2768             ++depth;
2769             putc(L_CURL, f);
2770             goto loop;
2771         }
2772         if (trialaction && c == R_BRAC && depth == 1)
2773         {
2774             --depth;
2775             putc(R_CURL, f);
2776             c = nextc();
2777             if (c == L_BRAC && !haveyyval)
2778             {
2779                 goto loop;
2780             }
2781             if (c == L_CURL && !haveyyval)
2782             {
2783                 fprintf(f, "  if (!yytrial)\n");
2784                 if (!lflag)
2785                     fprintf(f, line_format, lineno, input_file_name);
2786                 trialaction = 0;
2787                 goto loop;
2788             }
2789             fprintf(f, "\nbreak;\n");
2790             FREE(a.a_line);
2791             if (maxoffset > 0)
2792                 FREE(offsets);
2793             return;
2794         }
2795     }
2796 #endif
2797     putc(c, f);
2798     switch (c)
2799     {
2800     case '\n':
2801         get_line();
2802         if (line)
2803             goto loop;
2804         unterminated_action(&a);
2805
2806     case ';':
2807         if (depth > 0)
2808             goto loop;
2809         fprintf(f, "\nbreak;\n");
2810         free(a.a_line);
2811         if (maxoffset > 0)
2812             FREE(offsets);
2813         return;
2814
2815 #if defined(YYBTYACC)
2816     case L_BRAC:
2817         if (backtrack)
2818             ++depth;
2819         goto loop;
2820
2821     case R_BRAC:
2822         if (backtrack)
2823             --depth;
2824         goto loop;
2825 #endif
2826
2827     case L_CURL:
2828         ++depth;
2829         goto loop;
2830
2831     case R_CURL:
2832         if (--depth > 0)
2833             goto loop;
2834 #if defined(YYBTYACC)
2835         if (backtrack)
2836         {
2837             c = nextc();
2838             if (c == L_BRAC && !haveyyval)
2839             {
2840                 trialaction = 1;
2841                 goto loop;
2842             }
2843             if (c == L_CURL && !haveyyval)
2844             {
2845                 fprintf(f, "  if (!yytrial)\n");
2846                 if (!lflag)
2847                     fprintf(f, line_format, lineno, input_file_name);
2848                 goto loop;
2849             }
2850         }
2851 #endif
2852         fprintf(f, "\nbreak;\n");
2853         free(a.a_line);
2854         if (maxoffset > 0)
2855             FREE(offsets);
2856         return;
2857
2858     case '\'':
2859     case '"':
2860         {
2861             char *s = copy_string(c);
2862             fputs(s, f);
2863             free(s);
2864         }
2865         goto loop;
2866
2867     case '/':
2868         {
2869             char *s = copy_comment();
2870             fputs(s, f);
2871             free(s);
2872         }
2873         goto loop;
2874
2875     default:
2876         goto loop;
2877     }
2878 }
2879
2880 #if defined(YYBTYACC)
2881 static char *
2882 get_code(struct ainfo *a, const char *loc)
2883 {
2884     int c;
2885     int depth;
2886     char *tag;
2887     struct mstring *code_mstr = msnew();
2888
2889     if (!lflag)
2890         msprintf(code_mstr, line_format, lineno, input_file_name);
2891
2892     cptr = after_blanks(cptr);
2893     if (*cptr == L_CURL)
2894         /* avoid putting curly-braces in first column, to ease editing */
2895         mputc(code_mstr, '\t');
2896     else
2897         syntax_error(lineno, line, cptr);
2898
2899     a->a_lineno = lineno;
2900     a->a_line = dup_line();
2901     a->a_cptr = a->a_line + (cptr - line);
2902
2903     depth = 0;
2904   loop:
2905     c = *cptr;
2906     if (c == '$')
2907     {
2908         if (cptr[1] == '<')
2909         {
2910             int d_lineno = lineno;
2911             char *d_line = dup_line();
2912             char *d_cptr = d_line + (cptr - line);
2913
2914             ++cptr;
2915             tag = get_tag();
2916             c = *cptr;
2917             if (c == '$')
2918             {
2919                 msprintf(code_mstr, "(*val).%s", tag);
2920                 ++cptr;
2921                 FREE(d_line);
2922                 goto loop;
2923             }
2924             else
2925                 dollar_error(d_lineno, d_line, d_cptr);
2926         }
2927         else if (cptr[1] == '$')
2928         {
2929             /* process '$$' later; replacement is context dependent */
2930             msprintf(code_mstr, "$$");
2931             cptr += 2;
2932             goto loop;
2933         }
2934     }
2935     if (c == '@' && cptr[1] == '$')
2936     {
2937         if (!locations)
2938         {
2939             int l_lineno = lineno;
2940             char *l_line = dup_line();
2941             char *l_cptr = l_line + (cptr - line);
2942             syntax_error(l_lineno, l_line, l_cptr);
2943         }
2944         msprintf(code_mstr, "%s", loc);
2945         cptr += 2;
2946         goto loop;
2947     }
2948     if (IS_NAME1(c))
2949     {
2950         do
2951         {
2952             mputc(code_mstr, c);
2953             c = *++cptr;
2954         }
2955         while (IS_NAME2(c));
2956         goto loop;
2957     }
2958     ++cptr;
2959     mputc(code_mstr, c);
2960     switch (c)
2961     {
2962     case '\n':
2963         get_line();
2964         if (line)
2965             goto loop;
2966         unterminated_action(a);
2967
2968     case L_CURL:
2969         ++depth;
2970         goto loop;
2971
2972     case R_CURL:
2973         if (--depth > 0)
2974             goto loop;
2975         goto out;
2976
2977     case '\'':
2978     case '"':
2979         {
2980             char *s = copy_string(c);
2981             msprintf(code_mstr, "%s", s);
2982             free(s);
2983         }
2984         goto loop;
2985
2986     case '/':
2987         {
2988             char *s = copy_comment();
2989             msprintf(code_mstr, "%s", s);
2990             free(s);
2991         }
2992         goto loop;
2993
2994     default:
2995         goto loop;
2996     }
2997   out:
2998     return msdone(code_mstr);
2999 }
3000
3001 static void
3002 copy_initial_action(void)
3003 {
3004     struct ainfo a;
3005
3006     initial_action = get_code(&a, "yyloc");
3007     free(a.a_line);
3008 }
3009
3010 static void
3011 copy_destructor(void)
3012 {
3013     char *code_text;
3014     int c;
3015     struct ainfo a;
3016     bucket *bp;
3017
3018     code_text = get_code(&a, "(*loc)");
3019
3020     for (;;)
3021     {
3022         c = nextc();
3023         if (c == EOF)
3024             unexpected_EOF();
3025         if (c == '<')
3026         {
3027             if (cptr[1] == '>')
3028             {                   /* "no semantic type" default destructor */
3029                 cptr += 2;
3030                 if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
3031                 {
3032                     static char untyped_default[] = "<>";
3033                     bp = make_bucket("untyped default");
3034                     bp->tag = untyped_default;
3035                     default_destructor[UNTYPED_DEFAULT] = bp;
3036                 }
3037                 if (bp->destructor != NULL)
3038                     destructor_redeclared_warning(&a);
3039                 else
3040                     /* replace "$$" with "(*val)" in destructor code */
3041                     bp->destructor = process_destructor_XX(code_text, NULL);
3042             }
3043             else if (cptr[1] == '*' && cptr[2] == '>')
3044             {                   /* "no per-symbol or per-type" default destructor */
3045                 cptr += 3;
3046                 if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
3047                 {
3048                     static char typed_default[] = "<*>";
3049                     bp = make_bucket("typed default");
3050                     bp->tag = typed_default;
3051                     default_destructor[TYPED_DEFAULT] = bp;
3052                 }
3053                 if (bp->destructor != NULL)
3054                     destructor_redeclared_warning(&a);
3055                 else
3056                 {
3057                     /* postpone re-processing destructor $$s until end of grammar spec */
3058                     bp->destructor = TMALLOC(char, strlen(code_text) + 1);
3059                     NO_SPACE(bp->destructor);
3060                     strcpy(bp->destructor, code_text);
3061                 }
3062             }
3063             else
3064             {                   /* "semantic type" default destructor */
3065                 char *tag = get_tag();
3066                 bp = lookup_type_destructor(tag);
3067                 if (bp->destructor != NULL)
3068                     destructor_redeclared_warning(&a);
3069                 else
3070                     /* replace "$$" with "(*val).tag" in destructor code */
3071                     bp->destructor = process_destructor_XX(code_text, tag);
3072             }
3073         }
3074         else if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
3075         {                       /* "symbol" destructor */
3076             bp = get_name();
3077             if (bp->destructor != NULL)
3078                 destructor_redeclared_warning(&a);
3079             else
3080             {
3081                 /* postpone re-processing destructor $$s until end of grammar spec */
3082                 bp->destructor = TMALLOC(char, strlen(code_text) + 1);
3083                 NO_SPACE(bp->destructor);
3084                 strcpy(bp->destructor, code_text);
3085             }
3086         }
3087         else
3088             break;
3089     }
3090     free(a.a_line);
3091     free(code_text);
3092 }
3093
3094 static char *
3095 process_destructor_XX(char *code, char *tag)
3096 {
3097     int c;
3098     int quote;
3099     int depth;
3100     struct mstring *new_code = msnew();
3101     char *codeptr = code;
3102
3103     depth = 0;
3104   loop:                 /* step thru code */
3105     c = *codeptr;
3106     if (c == '$' && codeptr[1] == '$')
3107     {
3108         codeptr += 2;
3109         if (tag == NULL)
3110             msprintf(new_code, "(*val)");
3111         else
3112             msprintf(new_code, "(*val).%s", tag);
3113         goto loop;
3114     }
3115     if (IS_NAME1(c))
3116     {
3117         do
3118         {
3119             mputc(new_code, c);
3120             c = *++codeptr;
3121         }
3122         while (IS_NAME2(c));
3123         goto loop;
3124     }
3125     ++codeptr;
3126     mputc(new_code, c);
3127     switch (c)
3128     {
3129     case L_CURL:
3130         ++depth;
3131         goto loop;
3132
3133     case R_CURL:
3134         if (--depth > 0)
3135             goto loop;
3136         return msdone(new_code);
3137
3138     case '\'':
3139     case '"':
3140         quote = c;
3141         for (;;)
3142         {
3143             c = *codeptr++;
3144             mputc(new_code, c);
3145             if (c == quote)
3146                 goto loop;
3147             if (c == '\\')
3148             {
3149                 c = *codeptr++;
3150                 mputc(new_code, c);
3151             }
3152         }
3153
3154     case '/':
3155         c = *codeptr;
3156         if (c == '*')
3157         {
3158             mputc(new_code, c);
3159             ++codeptr;
3160             for (;;)
3161             {
3162                 c = *codeptr++;
3163                 mputc(new_code, c);
3164                 if (c == '*' && *codeptr == '/')
3165                 {
3166                     mputc(new_code, '/');
3167                     ++codeptr;
3168                     goto loop;
3169                 }
3170             }
3171         }
3172         goto loop;
3173
3174     default:
3175         goto loop;
3176     }
3177 }
3178 #endif /* defined(YYBTYACC) */
3179
3180 static int
3181 mark_symbol(void)
3182 {
3183     int c;
3184     bucket *bp = NULL;
3185
3186     c = cptr[1];
3187     if (c == '%' || c == '\\')
3188     {
3189         cptr += 2;
3190         return (1);
3191     }
3192
3193     if (c == '=')
3194         cptr += 2;
3195     else if ((c == 'p' || c == 'P') &&
3196              ((c = cptr[2]) == 'r' || c == 'R') &&
3197              ((c = cptr[3]) == 'e' || c == 'E') &&
3198              ((c = cptr[4]) == 'c' || c == 'C') &&
3199              ((c = cptr[5], !IS_IDENT(c))))
3200         cptr += 5;
3201     else
3202         syntax_error(lineno, line, cptr);
3203
3204     c = nextc();
3205     if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
3206         bp = get_name();
3207     else if (c == '\'' || c == '"')
3208         bp = get_literal();
3209     else
3210     {
3211         syntax_error(lineno, line, cptr);
3212         /*NOTREACHED */
3213     }
3214
3215     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
3216         prec_redeclared();
3217
3218     rprec[nrules] = bp->prec;
3219     rassoc[nrules] = bp->assoc;
3220     return (0);
3221 }
3222
3223 static void
3224 read_grammar(void)
3225 {
3226     int c;
3227
3228     initialize_grammar();
3229     advance_to_start();
3230
3231     for (;;)
3232     {
3233         c = nextc();
3234         if (c == EOF)
3235             break;
3236         if (isalpha(UCH(c))
3237             || c == '_'
3238             || c == '.'
3239             || c == '$'
3240             || c == '\''
3241             || c == '"')
3242             add_symbol();
3243 #if defined(YYBTYACC)
3244         else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC))
3245 #else
3246         else if (c == L_CURL || c == '=')
3247 #endif
3248             copy_action();
3249         else if (c == '|')
3250         {
3251             end_rule();
3252             start_rule(plhs[nrules - 1], 0);
3253             ++cptr;
3254         }
3255         else if (c == '%')
3256         {
3257             if (mark_symbol())
3258                 break;
3259         }
3260         else
3261             syntax_error(lineno, line, cptr);
3262     }
3263     end_rule();
3264 #if defined(YYBTYACC)
3265     if (goal->args > 0)
3266         start_requires_args(goal->name);
3267 #endif
3268 }
3269
3270 static void
3271 free_tags(void)
3272 {
3273     int i;
3274
3275     if (tag_table == 0)
3276         return;
3277
3278     for (i = 0; i < ntags; ++i)
3279     {
3280         assert(tag_table[i]);
3281         FREE(tag_table[i]);
3282     }
3283     FREE(tag_table);
3284 }
3285
3286 static void
3287 pack_names(void)
3288 {
3289     bucket *bp;
3290     char *p, *s, *t;
3291
3292     name_pool_size = 13;        /* 13 == sizeof("$end") + sizeof("$accept") */
3293     for (bp = first_symbol; bp; bp = bp->next)
3294         name_pool_size += strlen(bp->name) + 1;
3295
3296     name_pool = TMALLOC(char, name_pool_size);
3297     NO_SPACE(name_pool);
3298
3299     strcpy(name_pool, "$accept");
3300     strcpy(name_pool + 8, "$end");
3301     t = name_pool + 13;
3302     for (bp = first_symbol; bp; bp = bp->next)
3303     {
3304         p = t;
3305         s = bp->name;
3306         while ((*t++ = *s++) != 0)
3307             continue;
3308         FREE(bp->name);
3309         bp->name = p;
3310     }
3311 }
3312
3313 static void
3314 check_symbols(void)
3315 {
3316     bucket *bp;
3317
3318     if (goal->class == UNKNOWN)
3319         undefined_goal(goal->name);
3320
3321     for (bp = first_symbol; bp; bp = bp->next)
3322     {
3323         if (bp->class == UNKNOWN)
3324         {
3325             undefined_symbol_warning(bp->name);
3326             bp->class = TERM;
3327         }
3328     }
3329 }
3330
3331 static void
3332 protect_string(char *src, char **des)
3333 {
3334     unsigned len;
3335     char *s;
3336     char *d;
3337
3338     *des = src;
3339     if (src)
3340     {
3341         len = 1;
3342         s = src;
3343         while (*s)
3344         {
3345             if ('\\' == *s || '"' == *s)
3346                 len++;
3347             s++;
3348             len++;
3349         }
3350
3351         *des = d = TMALLOC(char, len);
3352         NO_SPACE(d);
3353
3354         s = src;
3355         while (*s)
3356         {
3357             if ('\\' == *s || '"' == *s)
3358                 *d++ = '\\';
3359             *d++ = *s++;
3360         }
3361         *d = '\0';
3362     }
3363 }
3364
3365 static void
3366 pack_symbols(void)
3367 {
3368     bucket *bp;
3369     bucket **v;
3370     Value_t i, j, k, n;
3371 #if defined(YYBTYACC)
3372     Value_t max_tok_pval;
3373 #endif
3374
3375     nsyms = 2;
3376     ntokens = 1;
3377     for (bp = first_symbol; bp; bp = bp->next)
3378     {
3379         ++nsyms;
3380         if (bp->class == TERM)
3381             ++ntokens;
3382     }
3383     start_symbol = (Value_t)ntokens;
3384     nvars = (Value_t)(nsyms - ntokens);
3385
3386     symbol_name = TMALLOC(char *, nsyms);
3387     NO_SPACE(symbol_name);
3388
3389     symbol_value = TMALLOC(Value_t, nsyms);
3390     NO_SPACE(symbol_value);
3391
3392     symbol_prec = TMALLOC(Value_t, nsyms);
3393     NO_SPACE(symbol_prec);
3394
3395     symbol_assoc = TMALLOC(char, nsyms);
3396     NO_SPACE(symbol_assoc);
3397
3398 #if defined(YYBTYACC)
3399     symbol_pval = TMALLOC(Value_t, nsyms);
3400     NO_SPACE(symbol_pval);
3401
3402     if (destructor)
3403     {
3404         symbol_destructor = CALLOC(sizeof(char *), nsyms);
3405         NO_SPACE(symbol_destructor);
3406
3407         symbol_type_tag = CALLOC(sizeof(char *), nsyms);
3408         NO_SPACE(symbol_type_tag);
3409     }
3410 #endif
3411
3412     v = TMALLOC(bucket *, nsyms);
3413     NO_SPACE(v);
3414
3415     v[0] = 0;
3416     v[start_symbol] = 0;
3417
3418     i = 1;
3419     j = (Value_t)(start_symbol + 1);
3420     for (bp = first_symbol; bp; bp = bp->next)
3421     {
3422         if (bp->class == TERM)
3423             v[i++] = bp;
3424         else
3425             v[j++] = bp;
3426     }
3427     assert(i == ntokens && j == nsyms);
3428
3429     for (i = 1; i < ntokens; ++i)
3430         v[i]->index = i;
3431
3432     goal->index = (Index_t)(start_symbol + 1);
3433     k = (Value_t)(start_symbol + 2);
3434     while (++i < nsyms)
3435         if (v[i] != goal)
3436         {
3437             v[i]->index = k;
3438             ++k;
3439         }
3440
3441     goal->value = 0;
3442     k = 1;
3443     for (i = (Value_t)(start_symbol + 1); i < nsyms; ++i)
3444     {
3445         if (v[i] != goal)
3446         {
3447             v[i]->value = k;
3448             ++k;
3449         }
3450     }
3451
3452     k = 0;
3453     for (i = 1; i < ntokens; ++i)
3454     {
3455         n = v[i]->value;
3456         if (n > 256)
3457         {
3458             for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
3459                 symbol_value[j] = symbol_value[j - 1];
3460             symbol_value[j] = n;
3461         }
3462     }
3463
3464     assert(v[1] != 0);
3465
3466     if (v[1]->value == UNDEFINED)
3467         v[1]->value = 256;
3468
3469     j = 0;
3470     n = 257;
3471     for (i = 2; i < ntokens; ++i)
3472     {
3473         if (v[i]->value == UNDEFINED)
3474         {
3475             while (j < k && n == symbol_value[j])
3476             {
3477                 while (++j < k && n == symbol_value[j])
3478                     continue;
3479                 ++n;
3480             }
3481             v[i]->value = n;
3482             ++n;
3483         }
3484     }
3485
3486     symbol_name[0] = name_pool + 8;
3487     symbol_value[0] = 0;
3488     symbol_prec[0] = 0;
3489     symbol_assoc[0] = TOKEN;
3490 #if defined(YYBTYACC)
3491     symbol_pval[0] = 0;
3492     max_tok_pval = 0;
3493 #endif
3494     for (i = 1; i < ntokens; ++i)
3495     {
3496         symbol_name[i] = v[i]->name;
3497         symbol_value[i] = v[i]->value;
3498         symbol_prec[i] = v[i]->prec;
3499         symbol_assoc[i] = v[i]->assoc;
3500 #if defined(YYBTYACC)
3501         symbol_pval[i] = v[i]->value;
3502         if (symbol_pval[i] > max_tok_pval)
3503             max_tok_pval = symbol_pval[i];
3504         if (destructor)
3505         {
3506             symbol_destructor[i] = v[i]->destructor;
3507             symbol_type_tag[i] = v[i]->tag;
3508         }
3509 #endif
3510     }
3511     symbol_name[start_symbol] = name_pool;
3512     symbol_value[start_symbol] = -1;
3513     symbol_prec[start_symbol] = 0;
3514     symbol_assoc[start_symbol] = TOKEN;
3515 #if defined(YYBTYACC)
3516     symbol_pval[start_symbol] = (Value_t)(max_tok_pval + 1);
3517 #endif
3518     for (++i; i < nsyms; ++i)
3519     {
3520         k = v[i]->index;
3521         symbol_name[k] = v[i]->name;
3522         symbol_value[k] = v[i]->value;
3523         symbol_prec[k] = v[i]->prec;
3524         symbol_assoc[k] = v[i]->assoc;
3525 #if defined(YYBTYACC)
3526         symbol_pval[k] = (Value_t)((max_tok_pval + 1) + v[i]->value + 1);
3527         if (destructor)
3528         {
3529             symbol_destructor[k] = v[i]->destructor;
3530             symbol_type_tag[k] = v[i]->tag;
3531         }
3532 #endif
3533     }
3534
3535     if (gflag)
3536     {
3537         symbol_pname = TMALLOC(char *, nsyms);
3538         NO_SPACE(symbol_pname);
3539
3540         for (i = 0; i < nsyms; ++i)
3541             protect_string(symbol_name[i], &(symbol_pname[i]));
3542     }
3543
3544     FREE(v);
3545 }
3546
3547 static void
3548 pack_grammar(void)
3549 {
3550     int i;
3551     Value_t j;
3552     Assoc_t assoc;
3553     Value_t prec2;
3554
3555     ritem = TMALLOC(Value_t, nitems);
3556     NO_SPACE(ritem);
3557
3558     rlhs = TMALLOC(Value_t, nrules);
3559     NO_SPACE(rlhs);
3560
3561     rrhs = TMALLOC(Value_t, nrules + 1);
3562     NO_SPACE(rrhs);
3563
3564     rprec = TREALLOC(Value_t, rprec, nrules);
3565     NO_SPACE(rprec);
3566
3567     rassoc = TREALLOC(Assoc_t, rassoc, nrules);
3568     NO_SPACE(rassoc);
3569
3570     ritem[0] = -1;
3571     ritem[1] = goal->index;
3572     ritem[2] = 0;
3573     ritem[3] = -2;
3574     rlhs[0] = 0;
3575     rlhs[1] = 0;
3576     rlhs[2] = start_symbol;
3577     rrhs[0] = 0;
3578     rrhs[1] = 0;
3579     rrhs[2] = 1;
3580
3581     j = 4;
3582     for (i = 3; i < nrules; ++i)
3583     {
3584 #if defined(YYBTYACC)
3585         if (plhs[i]->args > 0)
3586         {
3587             if (plhs[i]->argnames)
3588             {
3589                 FREE(plhs[i]->argnames);
3590                 plhs[i]->argnames = NULL;
3591             }
3592             if (plhs[i]->argtags)
3593             {
3594                 FREE(plhs[i]->argtags);
3595                 plhs[i]->argtags = NULL;
3596             }
3597         }
3598 #endif /* defined(YYBTYACC) */
3599         rlhs[i] = plhs[i]->index;
3600         rrhs[i] = j;
3601         assoc = TOKEN;
3602         prec2 = 0;
3603         while (pitem[j])
3604         {
3605             ritem[j] = pitem[j]->index;
3606             if (pitem[j]->class == TERM)
3607             {
3608                 prec2 = pitem[j]->prec;
3609                 assoc = pitem[j]->assoc;
3610             }
3611             ++j;
3612         }
3613         ritem[j] = (Value_t)-i;
3614         ++j;
3615         if (rprec[i] == UNDEFINED)
3616         {
3617             rprec[i] = prec2;
3618             rassoc[i] = assoc;
3619         }
3620     }
3621     rrhs[i] = j;
3622
3623     FREE(plhs);
3624     FREE(pitem);
3625 #if defined(YYBTYACC)
3626     clean_arg_cache();
3627 #endif
3628 }
3629
3630 static void
3631 print_grammar(void)
3632 {
3633     int i, k;
3634     size_t j, spacing = 0;
3635     FILE *f = verbose_file;
3636
3637     if (!vflag)
3638         return;
3639
3640     k = 1;
3641     for (i = 2; i < nrules; ++i)
3642     {
3643         if (rlhs[i] != rlhs[i - 1])
3644         {
3645             if (i != 2)
3646                 fprintf(f, "\n");
3647             fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
3648             spacing = strlen(symbol_name[rlhs[i]]) + 1;
3649         }
3650         else
3651         {
3652             fprintf(f, "%4d  ", i - 2);
3653             j = spacing;
3654             while (j-- != 0)
3655                 putc(' ', f);
3656             putc('|', f);
3657         }
3658
3659         while (ritem[k] >= 0)
3660         {
3661             fprintf(f, " %s", symbol_name[ritem[k]]);
3662             ++k;
3663         }
3664         ++k;
3665         putc('\n', f);
3666     }
3667 }
3668
3669 #if defined(YYBTYACC)
3670 static void
3671 finalize_destructors(void)
3672 {
3673     int i;
3674     bucket *bp;
3675     char *tag;
3676
3677     for (i = 2; i < nsyms; ++i)
3678     {
3679         tag = symbol_type_tag[i];
3680         if (symbol_destructor[i] == NULL)
3681         {
3682             if (tag == NULL)
3683             {                   /* use <> destructor, if there is one */
3684                 if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3685                 {
3686                     symbol_destructor[i] = TMALLOC(char,
3687                                                    strlen(bp->destructor) + 1);
3688                     NO_SPACE(symbol_destructor[i]);
3689                     strcpy(symbol_destructor[i], bp->destructor);
3690                 }
3691             }
3692             else
3693             {                   /* use type destructor for this tag, if there is one */
3694                 bp = lookup_type_destructor(tag);
3695                 if (bp->destructor != NULL)
3696                 {
3697                     symbol_destructor[i] = TMALLOC(char,
3698                                                    strlen(bp->destructor) + 1);
3699                     NO_SPACE(symbol_destructor[i]);
3700                     strcpy(symbol_destructor[i], bp->destructor);
3701                 }
3702                 else
3703                 {               /* use <*> destructor, if there is one */
3704                     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3705                         /* replace "$$" with "(*val).tag" in destructor code */
3706                         symbol_destructor[i]
3707                             = process_destructor_XX(bp->destructor, tag);
3708                 }
3709             }
3710         }
3711         else
3712         {                       /* replace "$$" with "(*val)[.tag]" in destructor code */
3713             symbol_destructor[i]
3714                 = process_destructor_XX(symbol_destructor[i], tag);
3715         }
3716     }
3717     /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
3718     DO_FREE(symbol_type_tag);   /* no longer needed */
3719     if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3720     {
3721         FREE(bp->name);
3722         /* 'bp->tag' is a static value, don't free */
3723         FREE(bp->destructor);
3724         FREE(bp);
3725     }
3726     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3727     {
3728         FREE(bp->name);
3729         /* 'bp->tag' is a static value, don't free */
3730         FREE(bp->destructor);
3731         FREE(bp);
3732     }
3733     if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
3734     {
3735         bucket *p;
3736         for (; bp; bp = p)
3737         {
3738             p = bp->link;
3739             FREE(bp->name);
3740             /* 'bp->tag' freed by 'free_tags()' */
3741             FREE(bp->destructor);
3742             FREE(bp);
3743         }
3744     }
3745 }
3746 #endif /* defined(YYBTYACC) */
3747
3748 void
3749 reader(void)
3750 {
3751     write_section(code_file, banner);
3752     create_symbol_table();
3753     read_declarations();
3754     read_grammar();
3755     free_symbol_table();
3756     pack_names();
3757     check_symbols();
3758     pack_symbols();
3759     pack_grammar();
3760     free_symbols();
3761     print_grammar();
3762 #if defined(YYBTYACC)
3763     if (destructor)
3764         finalize_destructors();
3765 #endif
3766     free_tags();
3767 }
3768
3769 #ifdef NO_LEAKS
3770 static param *
3771 free_declarations(param *list)
3772 {
3773     while (list != 0)
3774     {
3775         param *next = list->next;
3776         free(list->type);
3777         free(list->name);
3778         free(list->type2);
3779         free(list);
3780         list = next;
3781     }
3782     return list;
3783 }
3784
3785 void
3786 reader_leaks(void)
3787 {
3788     lex_param = free_declarations(lex_param);
3789     parse_param = free_declarations(parse_param);
3790
3791     DO_FREE(line);
3792     DO_FREE(rrhs);
3793     DO_FREE(rlhs);
3794     DO_FREE(rprec);
3795     DO_FREE(ritem);
3796     DO_FREE(rassoc);
3797     DO_FREE(cache);
3798     DO_FREE(name_pool);
3799     DO_FREE(symbol_name);
3800     DO_FREE(symbol_prec);
3801     DO_FREE(symbol_assoc);
3802     DO_FREE(symbol_value);
3803 #if defined(YYBTYACC)
3804     DO_FREE(symbol_pval);
3805     DO_FREE(symbol_destructor);
3806     DO_FREE(symbol_type_tag);
3807 #endif
3808 }
3809 #endif