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