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