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