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