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