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