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