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