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