]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/byacc/reader.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / byacc / reader.c
1 /* $Id: reader.c,v 1.58 2014/10/06 22:15:08 tom Exp $ */
2
3 #include "defs.h"
4
5 /*  The line size must be a positive integer.  One hundred was chosen   */
6 /*  because few lines in Yacc input grammars exceed 100 characters.     */
7 /*  Note that if a line exceeds LINESIZE characters, the line buffer    */
8 /*  will be expanded to accomodate it.                                  */
9
10 #define LINESIZE 100
11
12 #define L_CURL  '{'
13 #define R_CURL  '}'
14 #define L_PAREN '('
15 #define R_PAREN ')'
16 #define L_BRAC  '['
17 #define R_BRAC  ']'
18
19 /* the maximum number of arguments (inherited attributes) to a non-terminal */
20 /* this is a hard limit, but seems more than adequate */
21 #define MAXARGS 20
22
23 static void start_rule(bucket *bp, int s_lineno);
24 #if defined(YYBTYACC)
25 static void copy_destructor(void);
26 static char *process_destructor_XX(char *code, char *tag);
27 #endif
28
29 static char *cache;
30 static int cinc, cache_size;
31
32 int ntags;
33 static int tagmax, havetags;
34 static char **tag_table;
35
36 static char saw_eof;
37 char unionized;
38 char *cptr, *line;
39 static int linesize;
40
41 static bucket *goal;
42 static Value_t prec;
43 static int gensym;
44 static char last_was_action;
45
46 static int maxitems;
47 static bucket **pitem;
48
49 static int maxrules;
50 static bucket **plhs;
51
52 static size_t name_pool_size;
53 static char *name_pool;
54
55 char line_format[] = "#line %d \"%s\"\n";
56
57 param *lex_param;
58 param *parse_param;
59
60 #if defined(YYBTYACC)
61 int destructor = 0;     /* =1 if at least one %destructor */
62
63 static bucket *default_destructor[3] =
64 {0, 0, 0};
65
66 #define UNTYPED_DEFAULT 0
67 #define TYPED_DEFAULT   1
68 #define TYPE_SPECIFIED  2
69
70 static bucket *
71 lookup_type_destructor(char *tag)
72 {
73     const char fmt[] = "%.*s destructor";
74     char name[1024] = "\0";
75     bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED];
76
77     while ((bp = *bpp) != NULL)
78     {
79         if (bp->tag == tag)
80             return (bp);
81         bpp = &bp->link;
82     }
83
84     sprintf(name, fmt, (int)(sizeof(name) - sizeof(fmt)), tag);
85     *bpp = bp = make_bucket(name);
86     bp->tag = tag;
87
88     return (bp);
89 }
90 #endif /* defined(YYBTYACC) */
91
92 static void
93 cachec(int c)
94 {
95     assert(cinc >= 0);
96     if (cinc >= cache_size)
97     {
98         cache_size += 256;
99         cache = TREALLOC(char, cache, cache_size);
100         NO_SPACE(cache);
101     }
102     cache[cinc] = (char)c;
103     ++cinc;
104 }
105
106 static void
107 get_line(void)
108 {
109     FILE *f = input_file;
110     int c;
111     int i;
112
113     if (saw_eof || (c = getc(f)) == EOF)
114     {
115         if (line)
116         {
117             FREE(line);
118             line = 0;
119         }
120         cptr = 0;
121         saw_eof = 1;
122         return;
123     }
124
125     if (line == 0 || linesize != (LINESIZE + 1))
126     {
127         if (line)
128             FREE(line);
129         linesize = LINESIZE + 1;
130         line = TMALLOC(char, linesize);
131         NO_SPACE(line);
132     }
133
134     i = 0;
135     ++lineno;
136     for (;;)
137     {
138         line[i++] = (char)c;
139         if (c == '\n')
140             break;
141         if ((i + 3) >= linesize)
142         {
143             linesize += LINESIZE;
144             line = TREALLOC(char, line, linesize);
145             NO_SPACE(line);
146         }
147         c = getc(f);
148         if (c == EOF)
149         {
150             line[i++] = '\n';
151             saw_eof = 1;
152             break;
153         }
154     }
155     line[i] = '\0';
156     cptr = line;
157     return;
158 }
159
160 static char *
161 dup_line(void)
162 {
163     char *p, *s, *t;
164
165     if (line == 0)
166         return (0);
167     s = line;
168     while (*s != '\n')
169         ++s;
170     p = TMALLOC(char, s - line + 1);
171     NO_SPACE(p);
172
173     s = line;
174     t = p;
175     while ((*t++ = *s++) != '\n')
176         continue;
177     return (p);
178 }
179
180 static void
181 skip_comment(void)
182 {
183     char *s;
184
185     int st_lineno = lineno;
186     char *st_line = dup_line();
187     char *st_cptr = st_line + (cptr - line);
188
189     s = cptr + 2;
190     for (;;)
191     {
192         if (*s == '*' && s[1] == '/')
193         {
194             cptr = s + 2;
195             FREE(st_line);
196             return;
197         }
198         if (*s == '\n')
199         {
200             get_line();
201             if (line == 0)
202                 unterminated_comment(st_lineno, st_line, st_cptr);
203             s = cptr;
204         }
205         else
206             ++s;
207     }
208 }
209
210 static int
211 next_inline(void)
212 {
213     char *s;
214
215     if (line == 0)
216     {
217         get_line();
218         if (line == 0)
219             return (EOF);
220     }
221
222     s = cptr;
223     for (;;)
224     {
225         switch (*s)
226         {
227         case '/':
228             if (s[1] == '*')
229             {
230                 cptr = s;
231                 skip_comment();
232                 s = cptr;
233                 break;
234             }
235             else if (s[1] == '/')
236             {
237                 get_line();
238                 if (line == 0)
239                     return (EOF);
240                 s = cptr;
241                 break;
242             }
243             /* FALLTHRU */
244
245         default:
246             cptr = s;
247             return (*s);
248         }
249     }
250 }
251
252 static int
253 nextc(void)
254 {
255     int ch;
256     int finish = 0;
257
258     do
259     {
260         switch (ch = next_inline())
261         {
262         case '\n':
263             get_line();
264             break;
265         case ' ':
266         case '\t':
267         case '\f':
268         case '\r':
269         case '\v':
270         case ',':
271         case ';':
272             ++cptr;
273             break;
274         case '\\':
275             ch = '%';
276             /* FALLTHRU */
277         default:
278             finish = 1;
279             break;
280         }
281     }
282     while (!finish);
283
284     return ch;
285 }
286 /* *INDENT-OFF* */
287 static struct keyword
288 {
289     char name[13];
290     int token;
291 }
292 keywords[] = {
293     { "binary",      NONASSOC },
294 #if defined(YYBTYACC)
295     { "destructor",  DESTRUCTOR },
296 #endif
297     { "expect",      EXPECT },
298     { "expect-rr",   EXPECT_RR },
299     { "ident",       IDENT }, 
300     { "left",        LEFT },
301     { "lex-param",   LEX_PARAM },
302 #if defined(YYBTYACC)
303     { "locations",   LOCATIONS },
304 #endif
305     { "nonassoc",    NONASSOC },
306     { "parse-param", PARSE_PARAM },
307     { "pure-parser", PURE_PARSER },
308     { "right",       RIGHT }, 
309     { "start",       START },
310     { "term",        TOKEN }, 
311     { "token",       TOKEN }, 
312     { "token-table", TOKEN_TABLE }, 
313     { "type",        TYPE },
314     { "union",       UNION },
315     { "yacc",        POSIX_YACC },
316 };
317 /* *INDENT-ON* */
318
319 static int
320 compare_keys(const void *a, const void *b)
321 {
322     const struct keyword *p = (const struct keyword *)a;
323     const struct keyword *q = (const struct keyword *)b;
324     return strcmp(p->name, q->name);
325 }
326
327 static int
328 keyword(void)
329 {
330     int c;
331     char *t_cptr = cptr;
332     struct keyword *key;
333
334     c = *++cptr;
335     if (isalpha(c))
336     {
337         cinc = 0;
338         for (;;)
339         {
340             if (isalpha(c))
341             {
342                 if (isupper(c))
343                     c = tolower(c);
344                 cachec(c);
345             }
346             else if (isdigit(c)
347                      || c == '-'
348                      || c == '.'
349                      || c == '$')
350             {
351                 cachec(c);
352             }
353             else if (c == '_')
354             {
355                 /* treat keywords spelled with '_' as if it were '-' */
356                 cachec('-');
357             }
358             else
359             {
360                 break;
361             }
362             c = *++cptr;
363         }
364         cachec(NUL);
365
366         if ((key = bsearch(cache, keywords,
367                            sizeof(keywords) / sizeof(*key),
368                            sizeof(*key), compare_keys)))
369             return key->token;
370     }
371     else
372     {
373         ++cptr;
374         if (c == L_CURL)
375             return (TEXT);
376         if (c == '%' || c == '\\')
377             return (MARK);
378         if (c == '<')
379             return (LEFT);
380         if (c == '>')
381             return (RIGHT);
382         if (c == '0')
383             return (TOKEN);
384         if (c == '2')
385             return (NONASSOC);
386     }
387     syntax_error(lineno, line, t_cptr);
388     return (-1);
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     i = 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 = 256;
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     sprintf(cache, "$$%d", ++gensym);
2086     bp = make_bucket(cache);
2087     last_symbol->next = bp;
2088     last_symbol = bp;
2089     bp->tag = plhs[nrules]->tag;
2090     bp->class = ACTION;
2091 #if defined(YYBTYACC)
2092     bp->args = 0;
2093 #endif
2094
2095     nitems = (Value_t) (nitems + 2);
2096     if (nitems > maxitems)
2097         expand_items();
2098     bpp = pitem + nitems - 1;
2099     *bpp-- = bp;
2100     while ((bpp[0] = bpp[-1]) != 0)
2101         --bpp;
2102
2103     if (++nrules >= maxrules)
2104         expand_rules();
2105     plhs[nrules] = plhs[nrules - 1];
2106     plhs[nrules - 1] = bp;
2107     rprec[nrules] = rprec[nrules - 1];
2108     rprec[nrules - 1] = 0;
2109     rassoc[nrules] = rassoc[nrules - 1];
2110     rassoc[nrules - 1] = TOKEN;
2111 }
2112
2113 #if defined(YYBTYACC)
2114 static char *
2115 insert_arg_rule(char *arg, char *tag)
2116 {
2117     int line_number = rescan_lineno;
2118     char *code = compile_arg(&arg, tag);
2119     int rule = lookup_arg_cache(code);
2120     FILE *f = action_file;
2121
2122     if (rule < 0)
2123     {
2124         rule = nrules;
2125         insert_arg_cache(code, rule);
2126         fprintf(f, "case %d:\n", rule - 2);
2127         if (!lflag)
2128             fprintf(f, line_format, line_number, input_file_name);
2129         fprintf(f, "%s;\n", code);
2130         fprintf(f, "break;\n");
2131         insert_empty_rule();
2132         plhs[rule]->tag = tag;
2133         plhs[rule]->class = ARGUMENT;
2134     }
2135     else
2136     {
2137         if (++nitems > maxitems)
2138             expand_items();
2139         pitem[nitems - 1] = plhs[rule];
2140         free(code);
2141     }
2142     return arg + 1;
2143 }
2144 #endif
2145
2146 static void
2147 add_symbol(void)
2148 {
2149     int c;
2150     bucket *bp;
2151     int s_lineno = lineno;
2152 #if defined(YYBTYACC)
2153     char *args = NULL;
2154     int argslen = 0;
2155 #endif
2156
2157     c = *cptr;
2158     if (c == '\'' || c == '"')
2159         bp = get_literal();
2160     else
2161         bp = get_name();
2162
2163     c = nextc();
2164     rescan_lineno = lineno;     /* line# for possible inherited args rescan */
2165 #if defined(YYBTYACC)
2166     if (c == L_PAREN)
2167     {
2168         ++cptr;
2169         args = copy_args(&argslen);
2170         NO_SPACE(args);
2171         c = nextc();
2172     }
2173 #endif
2174     if (c == ':')
2175     {
2176         end_rule();
2177         start_rule(bp, s_lineno);
2178 #if defined(YYBTYACC)
2179         parse_arginfo(bp, args, argslen);
2180 #endif
2181         ++cptr;
2182         return;
2183     }
2184
2185     if (last_was_action)
2186         insert_empty_rule();
2187     last_was_action = 0;
2188
2189 #if defined(YYBTYACC)
2190     if (bp->args < 0)
2191         bp->args = argslen;
2192     if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
2193     {
2194         int i;
2195         if (plhs[nrules]->args != bp->args)
2196             wrong_number_args_warning("default ", bp->name);
2197         for (i = bp->args - 1; i >= 0; i--)
2198             if (plhs[nrules]->argtags[i] != bp->argtags[i])
2199                 wrong_type_for_arg_warning(i + 1, bp->name);
2200     }
2201     else if (bp->args != argslen)
2202         wrong_number_args_warning("", bp->name);
2203     if (bp->args > 0 && argslen > 0)
2204     {
2205         char *ap;
2206         int i;
2207         for (ap = args, i = 0; i < argslen; i++)
2208             ap = insert_arg_rule(ap, bp->argtags[i]);
2209         free(args);
2210     }
2211 #endif /* defined(YYBTYACC) */
2212
2213     if (++nitems > maxitems)
2214         expand_items();
2215     pitem[nitems - 1] = bp;
2216 }
2217
2218 static void
2219 copy_action(void)
2220 {
2221     int c;
2222     int i, j, n;
2223     int depth;
2224 #if defined(YYBTYACC)
2225     int trialaction = 0;
2226     int haveyyval = 0;
2227 #endif
2228     char *tag;
2229     FILE *f = action_file;
2230     int a_lineno = lineno;
2231     char *a_line = dup_line();
2232     char *a_cptr = a_line + (cptr - line);
2233     Value_t *offsets = NULL, maxoffset;
2234     bucket **rhs;
2235
2236     if (last_was_action)
2237         insert_empty_rule();
2238     last_was_action = 1;
2239
2240     fprintf(f, "case %d:\n", nrules - 2);
2241 #if defined(YYBTYACC)
2242     if (backtrack)
2243     {
2244         if (*cptr != L_BRAC)
2245             fprintf(f, "  if (!yytrial)\n");
2246         else
2247             trialaction = 1;
2248     }
2249 #endif
2250     if (!lflag)
2251         fprintf(f, line_format, lineno, input_file_name);
2252     if (*cptr == '=')
2253         ++cptr;
2254
2255     /* avoid putting curly-braces in first column, to ease editing */
2256     if (*after_blanks(cptr) == L_CURL)
2257     {
2258         putc('\t', f);
2259         cptr = after_blanks(cptr);
2260     }
2261
2262     maxoffset = 0;
2263     n = 0;
2264     for (i = nitems - 1; pitem[i]; --i)
2265     {
2266         ++n;
2267         if (pitem[i]->class != ARGUMENT)
2268             maxoffset++;
2269     }
2270     if (maxoffset > 0)
2271     {
2272         offsets = TMALLOC(Value_t, maxoffset + 1);
2273         NO_SPACE(offsets);
2274
2275         for (j = 0, i++; i < nitems; i++)
2276         {
2277             if (pitem[i]->class != ARGUMENT)
2278             {
2279                 offsets[++j] = (Value_t) (i - nitems + 1);
2280             }
2281         }
2282     }
2283     rhs = pitem + nitems - 1;
2284
2285     depth = 0;
2286   loop:
2287     c = *cptr;
2288     if (c == '$')
2289     {
2290         if (cptr[1] == '<')
2291         {
2292             int d_lineno = lineno;
2293             char *d_line = dup_line();
2294             char *d_cptr = d_line + (cptr - line);
2295
2296             ++cptr;
2297             tag = get_tag();
2298             c = *cptr;
2299             if (c == '$')
2300             {
2301                 fprintf(f, "yyval.%s", tag);
2302                 ++cptr;
2303                 FREE(d_line);
2304                 goto loop;
2305             }
2306             else if (isdigit(c))
2307             {
2308                 i = get_number();
2309                 if (i == 0)
2310                     fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
2311                 else if (i > maxoffset)
2312                 {
2313                     dollar_warning(d_lineno, i);
2314                     fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag);
2315                 }
2316                 else if (offsets)
2317                     fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2318                 FREE(d_line);
2319                 goto loop;
2320             }
2321             else if (c == '-' && isdigit(UCH(cptr[1])))
2322             {
2323                 ++cptr;
2324                 i = -get_number() - n;
2325                 fprintf(f, "yystack.l_mark[%d].%s", i, tag);
2326                 FREE(d_line);
2327                 goto loop;
2328             }
2329 #if defined(YYBTYACC)
2330             else if (isalpha(c) || c == '_')
2331             {
2332                 char *arg = scan_id();
2333                 for (i = plhs[nrules]->args - 1; i >= 0; i--)
2334                     if (arg == plhs[nrules]->argnames[i])
2335                         break;
2336                 if (i < 0)
2337                     unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
2338                 fprintf(f, "yystack.l_mark[%d].%s", i - plhs[nrules]->args +
2339                         1 - n, tag);
2340                 FREE(d_line);
2341                 goto loop;
2342             }
2343 #endif
2344             else
2345                 dollar_error(d_lineno, d_line, d_cptr);
2346         }
2347         else if (cptr[1] == '$')
2348         {
2349             if (havetags)
2350             {
2351                 tag = plhs[nrules]->tag;
2352                 if (tag == 0)
2353                     untyped_lhs();
2354                 fprintf(f, "yyval.%s", tag);
2355             }
2356             else
2357                 fprintf(f, "yyval");
2358             cptr += 2;
2359 #if defined(YYBTYACC)
2360             haveyyval = 1;
2361 #endif
2362             goto loop;
2363         }
2364         else if (isdigit(UCH(cptr[1])))
2365         {
2366             ++cptr;
2367             i = get_number();
2368             if (havetags && offsets)
2369             {
2370                 if (i <= 0 || i > maxoffset)
2371                     unknown_rhs(i);
2372                 tag = rhs[offsets[i]]->tag;
2373                 if (tag == 0)
2374                     untyped_rhs(i, rhs[offsets[i]]->name);
2375                 fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2376             }
2377             else
2378             {
2379                 if (i == 0)
2380                     fprintf(f, "yystack.l_mark[%d]", -n);
2381                 else if (i > maxoffset)
2382                 {
2383                     dollar_warning(lineno, i);
2384                     fprintf(f, "yystack.l_mark[%d]", i - maxoffset);
2385                 }
2386                 else if (offsets)
2387                     fprintf(f, "yystack.l_mark[%d]", offsets[i]);
2388             }
2389             goto loop;
2390         }
2391         else if (cptr[1] == '-')
2392         {
2393             cptr += 2;
2394             i = get_number();
2395             if (havetags)
2396                 unknown_rhs(-i);
2397             fprintf(f, "yystack.l_mark[%d]", -i - n);
2398             goto loop;
2399         }
2400 #if defined(YYBTYACC)
2401         else if (isalpha(cptr[1]) || cptr[1] == '_')
2402         {
2403             char *arg;
2404             ++cptr;
2405             arg = scan_id();
2406             for (i = plhs[nrules]->args - 1; i >= 0; i--)
2407                 if (arg == plhs[nrules]->argnames[i])
2408                     break;
2409             if (i < 0)
2410                 unknown_arg_warning(lineno, "$", arg, line, cptr);
2411             tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]);
2412             fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n);
2413             if (tag)
2414                 fprintf(f, ".%s", tag);
2415             else if (havetags)
2416                 untyped_arg_warning(lineno, "$", arg);
2417             goto loop;
2418         }
2419 #endif
2420     }
2421 #if defined(YYBTYACC)
2422     if (c == '@')
2423     {
2424         if (!locations)
2425         {
2426             int l_lineno = lineno;
2427             char *l_line = dup_line();
2428             char *l_cptr = l_line + (cptr - line);
2429             syntax_error(l_lineno, l_line, l_cptr);
2430         }
2431         if (cptr[1] == '$')
2432         {
2433             fprintf(f, "yyloc");
2434             cptr += 2;
2435             goto loop;
2436         }
2437         else if (isdigit(UCH(cptr[1])))
2438         {
2439             ++cptr;
2440             i = get_number();
2441             if (i == 0)
2442                 fprintf(f, "yystack.p_mark[%d]", -n);
2443             else if (i > maxoffset)
2444             {
2445                 at_warning(lineno, i);
2446                 fprintf(f, "yystack.p_mark[%d]", i - maxoffset);
2447             }
2448             else if (offsets)
2449                 fprintf(f, "yystack.p_mark[%d]", offsets[i]);
2450             goto loop;
2451         }
2452     }
2453 #endif
2454     if (isalpha(c) || c == '_' || c == '$')
2455     {
2456         do
2457         {
2458             putc(c, f);
2459             c = *++cptr;
2460         }
2461         while (isalnum(c) || c == '_' || c == '$');
2462         goto loop;
2463     }
2464     ++cptr;
2465 #if defined(YYBTYACC)
2466     if (backtrack)
2467     {
2468         if (trialaction && c == L_BRAC && depth == 0)
2469         {
2470             ++depth;
2471             putc(L_CURL, f);
2472             goto loop;
2473         }
2474         if (trialaction && c == R_BRAC && depth == 1)
2475         {
2476             --depth;
2477             putc(R_CURL, f);
2478             c = nextc();
2479             if (c == L_BRAC && !haveyyval)
2480             {
2481                 goto loop;
2482             }
2483             if (c == L_CURL && !haveyyval)
2484             {
2485                 fprintf(f, "  if (!yytrial)\n");
2486                 if (!lflag)
2487                     fprintf(f, line_format, lineno, input_file_name);
2488                 trialaction = 0;
2489                 goto loop;
2490             }
2491             fprintf(f, "\nbreak;\n");
2492             FREE(a_line);
2493             if (maxoffset > 0)
2494                 FREE(offsets);
2495             return;
2496         }
2497     }
2498 #endif
2499     putc(c, f);
2500     switch (c)
2501     {
2502     case '\n':
2503         get_line();
2504         if (line)
2505             goto loop;
2506         unterminated_action(a_lineno, a_line, a_cptr);
2507
2508     case ';':
2509         if (depth > 0)
2510             goto loop;
2511         fprintf(f, "\nbreak;\n");
2512         free(a_line);
2513         if (maxoffset > 0)
2514             FREE(offsets);
2515         return;
2516
2517 #if defined(YYBTYACC)
2518     case L_BRAC:
2519         if (backtrack)
2520             ++depth;
2521         goto loop;
2522
2523     case R_BRAC:
2524         if (backtrack)
2525             --depth;
2526         goto loop;
2527 #endif
2528
2529     case L_CURL:
2530         ++depth;
2531         goto loop;
2532
2533     case R_CURL:
2534         if (--depth > 0)
2535             goto loop;
2536 #if defined(YYBTYACC)
2537         if (backtrack)
2538         {
2539             c = nextc();
2540             if (c == L_BRAC && !haveyyval)
2541             {
2542                 trialaction = 1;
2543                 goto loop;
2544             }
2545             if (c == L_CURL && !haveyyval)
2546             {
2547                 fprintf(f, "  if (!yytrial)\n");
2548                 if (!lflag)
2549                     fprintf(f, line_format, lineno, input_file_name);
2550                 goto loop;
2551             }
2552         }
2553 #endif
2554         fprintf(f, "\nbreak;\n");
2555         free(a_line);
2556         if (maxoffset > 0)
2557             FREE(offsets);
2558         return;
2559
2560     case '\'':
2561     case '"':
2562         {
2563             char *s = copy_string(c);
2564             fputs(s, f);
2565             free(s);
2566         }
2567         goto loop;
2568
2569     case '/':
2570         {
2571             char *s = copy_comment();
2572             fputs(s, f);
2573             free(s);
2574         }
2575         goto loop;
2576
2577     default:
2578         goto loop;
2579     }
2580 }
2581
2582 #if defined(YYBTYACC)
2583 static void
2584 copy_destructor(void)
2585 {
2586     int c;
2587     int depth;
2588     char *tag;
2589     bucket *bp;
2590     struct mstring *destructor_text = msnew();
2591     char *code_text;
2592     int a_lineno;
2593     char *a_line;
2594     char *a_cptr;
2595
2596     if (!lflag)
2597         msprintf(destructor_text, line_format, lineno, input_file_name);
2598
2599     cptr = after_blanks(cptr);
2600     if (*cptr == L_CURL)
2601         /* avoid putting curly-braces in first column, to ease editing */
2602         mputc(destructor_text, '\t');
2603     else
2604         syntax_error(lineno, line, cptr);
2605
2606     a_lineno = lineno;
2607     a_line = dup_line();
2608     a_cptr = a_line + (cptr - line);
2609
2610     depth = 0;
2611   loop:
2612     c = *cptr;
2613     if (c == '$')
2614     {
2615         if (cptr[1] == '<')
2616         {
2617             int d_lineno = lineno;
2618             char *d_line = dup_line();
2619             char *d_cptr = d_line + (cptr - line);
2620
2621             ++cptr;
2622             tag = get_tag();
2623             c = *cptr;
2624             if (c == '$')
2625             {
2626                 msprintf(destructor_text, "(*val).%s", tag);
2627                 ++cptr;
2628                 FREE(d_line);
2629                 goto loop;
2630             }
2631             else
2632                 dollar_error(d_lineno, d_line, d_cptr);
2633         }
2634         else if (cptr[1] == '$')
2635         {
2636             /* process '$$' later; replacement is context dependent */
2637             msprintf(destructor_text, "$$");
2638             cptr += 2;
2639             goto loop;
2640         }
2641     }
2642     if (c == '@' && cptr[1] == '$')
2643     {
2644         if (!locations)
2645         {
2646             int l_lineno = lineno;
2647             char *l_line = dup_line();
2648             char *l_cptr = l_line + (cptr - line);
2649             syntax_error(l_lineno, l_line, l_cptr);
2650         }
2651         msprintf(destructor_text, "(*loc)");
2652         cptr += 2;
2653         goto loop;
2654     }
2655     if (isalpha(c) || c == '_' || c == '$')
2656     {
2657         do
2658         {
2659             mputc(destructor_text, c);
2660             c = *++cptr;
2661         }
2662         while (isalnum(c) || c == '_' || c == '$');
2663         goto loop;
2664     }
2665     ++cptr;
2666     mputc(destructor_text, c);
2667     switch (c)
2668     {
2669     case '\n':
2670         get_line();
2671         if (line)
2672             goto loop;
2673         unterminated_action(a_lineno, a_line, a_cptr);
2674
2675     case L_CURL:
2676         ++depth;
2677         goto loop;
2678
2679     case R_CURL:
2680         if (--depth > 0)
2681             goto loop;
2682         goto process_symbols;
2683
2684     case '\'':
2685     case '"':
2686         {
2687             char *s = copy_string(c);
2688             msprintf(destructor_text, "%s", s);
2689             free(s);
2690         }
2691         goto loop;
2692
2693     case '/':
2694         {
2695             char *s = copy_comment();
2696             msprintf(destructor_text, "%s", s);
2697             free(s);
2698         }
2699         goto loop;
2700
2701     default:
2702         goto loop;
2703     }
2704   process_symbols:
2705     code_text = msdone(destructor_text);
2706     for (;;)
2707     {
2708         c = nextc();
2709         if (c == EOF)
2710             unexpected_EOF();
2711         if (c == '<')
2712         {
2713             if (cptr[1] == '>')
2714             {                   /* "no semantic type" default destructor */
2715                 cptr += 2;
2716                 if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
2717                 {
2718                     static char untyped_default[] = "<>";
2719                     bp = make_bucket("untyped default");
2720                     bp->tag = untyped_default;
2721                     default_destructor[UNTYPED_DEFAULT] = bp;
2722                 }
2723                 if (bp->destructor != NULL)
2724                     destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2725                 else
2726                     /* replace "$$" with "(*val)" in destructor code */
2727                     bp->destructor = process_destructor_XX(code_text, NULL);
2728             }
2729             else if (cptr[1] == '*' && cptr[2] == '>')
2730             {                   /* "no per-symbol or per-type" default destructor */
2731                 cptr += 3;
2732                 if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
2733                 {
2734                     static char typed_default[] = "<*>";
2735                     bp = make_bucket("typed default");
2736                     bp->tag = typed_default;
2737                     default_destructor[TYPED_DEFAULT] = bp;
2738                 }
2739                 if (bp->destructor != NULL)
2740                     destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2741                 else
2742                 {
2743                     /* postpone re-processing destructor $$s until end of grammar spec */
2744                     bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2745                     NO_SPACE(bp->destructor);
2746                     strcpy(bp->destructor, code_text);
2747                 }
2748             }
2749             else
2750             {                   /* "semantic type" default destructor */
2751                 tag = get_tag();
2752                 bp = lookup_type_destructor(tag);
2753                 if (bp->destructor != NULL)
2754                     destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2755                 else
2756                     /* replace "$$" with "(*val).tag" in destructor code */
2757                     bp->destructor = process_destructor_XX(code_text, tag);
2758             }
2759         }
2760         else if (isalpha(c) || c == '_' || c == '.' || c == '$')
2761         {                       /* "symbol" destructor */
2762             bp = get_name();
2763             if (bp->destructor != NULL)
2764                 destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2765             else
2766             {
2767                 /* postpone re-processing destructor $$s until end of grammar spec */
2768                 bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2769                 NO_SPACE(bp->destructor);
2770                 strcpy(bp->destructor, code_text);
2771             }
2772         }
2773         else
2774             break;
2775     }
2776     free(a_line);
2777     free(code_text);
2778 }
2779
2780 static char *
2781 process_destructor_XX(char *code, char *tag)
2782 {
2783     int c;
2784     int quote;
2785     int depth;
2786     struct mstring *new_code = msnew();
2787     char *codeptr = code;
2788
2789     depth = 0;
2790   loop:                 /* step thru code */
2791     c = *codeptr;
2792     if (c == '$' && codeptr[1] == '$')
2793     {
2794         codeptr += 2;
2795         if (tag == NULL)
2796             msprintf(new_code, "(*val)");
2797         else
2798             msprintf(new_code, "(*val).%s", tag);
2799         goto loop;
2800     }
2801     if (isalpha(c) || c == '_' || c == '$')
2802     {
2803         do
2804         {
2805             mputc(new_code, c);
2806             c = *++codeptr;
2807         }
2808         while (isalnum(c) || c == '_' || c == '$');
2809         goto loop;
2810     }
2811     ++codeptr;
2812     mputc(new_code, c);
2813     switch (c)
2814     {
2815     case L_CURL:
2816         ++depth;
2817         goto loop;
2818
2819     case R_CURL:
2820         if (--depth > 0)
2821             goto loop;
2822         return msdone(new_code);
2823
2824     case '\'':
2825     case '"':
2826         quote = c;
2827         for (;;)
2828         {
2829             c = *codeptr++;
2830             mputc(new_code, c);
2831             if (c == quote)
2832                 goto loop;
2833             if (c == '\\')
2834             {
2835                 c = *codeptr++;
2836                 mputc(new_code, c);
2837             }
2838         }
2839
2840     case '/':
2841         c = *codeptr;
2842         if (c == '*')
2843         {
2844             mputc(new_code, c);
2845             ++codeptr;
2846             for (;;)
2847             {
2848                 c = *codeptr++;
2849                 mputc(new_code, c);
2850                 if (c == '*' && *codeptr == '/')
2851                 {
2852                     mputc(new_code, '/');
2853                     ++codeptr;
2854                     goto loop;
2855                 }
2856             }
2857         }
2858         goto loop;
2859
2860     default:
2861         goto loop;
2862     }
2863 }
2864 #endif /* defined(YYBTYACC) */
2865
2866 static int
2867 mark_symbol(void)
2868 {
2869     int c;
2870     bucket *bp = NULL;
2871
2872     c = cptr[1];
2873     if (c == '%' || c == '\\')
2874     {
2875         cptr += 2;
2876         return (1);
2877     }
2878
2879     if (c == '=')
2880         cptr += 2;
2881     else if ((c == 'p' || c == 'P') &&
2882              ((c = cptr[2]) == 'r' || c == 'R') &&
2883              ((c = cptr[3]) == 'e' || c == 'E') &&
2884              ((c = cptr[4]) == 'c' || c == 'C') &&
2885              ((c = cptr[5], !IS_IDENT(c))))
2886         cptr += 5;
2887     else
2888         syntax_error(lineno, line, cptr);
2889
2890     c = nextc();
2891     if (isalpha(c) || c == '_' || c == '.' || c == '$')
2892         bp = get_name();
2893     else if (c == '\'' || c == '"')
2894         bp = get_literal();
2895     else
2896     {
2897         syntax_error(lineno, line, cptr);
2898     }
2899
2900     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
2901         prec_redeclared();
2902
2903     rprec[nrules] = bp->prec;
2904     rassoc[nrules] = bp->assoc;
2905     return (0);
2906 }
2907
2908 static void
2909 read_grammar(void)
2910 {
2911     int c;
2912
2913     initialize_grammar();
2914     advance_to_start();
2915
2916     for (;;)
2917     {
2918         c = nextc();
2919         if (c == EOF)
2920             break;
2921         if (isalpha(c)
2922             || c == '_'
2923             || c == '.'
2924             || c == '$'
2925             || c == '\''
2926             || c == '"')
2927             add_symbol();
2928 #if defined(YYBTYACC)
2929         else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC))
2930 #else
2931         else if (c == L_CURL || c == '=')
2932 #endif
2933             copy_action();
2934         else if (c == '|')
2935         {
2936             end_rule();
2937             start_rule(plhs[nrules - 1], 0);
2938             ++cptr;
2939         }
2940         else if (c == '%')
2941         {
2942             if (mark_symbol())
2943                 break;
2944         }
2945         else
2946             syntax_error(lineno, line, cptr);
2947     }
2948     end_rule();
2949 #if defined(YYBTYACC)
2950     if (goal->args > 0)
2951         start_requires_args(goal->name);
2952 #endif
2953 }
2954
2955 static void
2956 free_tags(void)
2957 {
2958     int i;
2959
2960     if (tag_table == 0)
2961         return;
2962
2963     for (i = 0; i < ntags; ++i)
2964     {
2965         assert(tag_table[i]);
2966         FREE(tag_table[i]);
2967     }
2968     FREE(tag_table);
2969 }
2970
2971 static void
2972 pack_names(void)
2973 {
2974     bucket *bp;
2975     char *p, *s, *t;
2976
2977     name_pool_size = 13;        /* 13 == sizeof("$end") + sizeof("$accept") */
2978     for (bp = first_symbol; bp; bp = bp->next)
2979         name_pool_size += strlen(bp->name) + 1;
2980
2981     name_pool = TMALLOC(char, name_pool_size);
2982     NO_SPACE(name_pool);
2983
2984     strcpy(name_pool, "$accept");
2985     strcpy(name_pool + 8, "$end");
2986     t = name_pool + 13;
2987     for (bp = first_symbol; bp; bp = bp->next)
2988     {
2989         p = t;
2990         s = bp->name;
2991         while ((*t++ = *s++) != 0)
2992             continue;
2993         FREE(bp->name);
2994         bp->name = p;
2995     }
2996 }
2997
2998 static void
2999 check_symbols(void)
3000 {
3001     bucket *bp;
3002
3003     if (goal->class == UNKNOWN)
3004         undefined_goal(goal->name);
3005
3006     for (bp = first_symbol; bp; bp = bp->next)
3007     {
3008         if (bp->class == UNKNOWN)
3009         {
3010             undefined_symbol_warning(bp->name);
3011             bp->class = TERM;
3012         }
3013     }
3014 }
3015
3016 static void
3017 protect_string(char *src, char **des)
3018 {
3019     unsigned len;
3020     char *s;
3021     char *d;
3022
3023     *des = src;
3024     if (src)
3025     {
3026         len = 1;
3027         s = src;
3028         while (*s)
3029         {
3030             if ('\\' == *s || '"' == *s)
3031                 len++;
3032             s++;
3033             len++;
3034         }
3035
3036         *des = d = TMALLOC(char, len);
3037         NO_SPACE(d);
3038
3039         s = src;
3040         while (*s)
3041         {
3042             if ('\\' == *s || '"' == *s)
3043                 *d++ = '\\';
3044             *d++ = *s++;
3045         }
3046         *d = '\0';
3047     }
3048 }
3049
3050 static void
3051 pack_symbols(void)
3052 {
3053     bucket *bp;
3054     bucket **v;
3055     Value_t i, j, k, n;
3056 #if defined(YYBTYACC)
3057     Value_t max_tok_pval;
3058 #endif
3059
3060     nsyms = 2;
3061     ntokens = 1;
3062     for (bp = first_symbol; bp; bp = bp->next)
3063     {
3064         ++nsyms;
3065         if (bp->class == TERM)
3066             ++ntokens;
3067     }
3068     start_symbol = (Value_t) ntokens;
3069     nvars = (Value_t) (nsyms - ntokens);
3070
3071     symbol_name = TMALLOC(char *, nsyms);
3072     NO_SPACE(symbol_name);
3073
3074     symbol_value = TMALLOC(Value_t, nsyms);
3075     NO_SPACE(symbol_value);
3076
3077     symbol_prec = TMALLOC(Value_t, nsyms);
3078     NO_SPACE(symbol_prec);
3079
3080     symbol_assoc = TMALLOC(char, nsyms);
3081     NO_SPACE(symbol_assoc);
3082
3083 #if defined(YYBTYACC)
3084     symbol_pval = TMALLOC(Value_t, nsyms);
3085     NO_SPACE(symbol_pval);
3086
3087     if (destructor)
3088     {
3089         symbol_destructor = CALLOC(sizeof(char *), nsyms);
3090         NO_SPACE(symbol_destructor);
3091
3092         symbol_type_tag = CALLOC(sizeof(char *), nsyms);
3093         NO_SPACE(symbol_type_tag);
3094     }
3095 #endif
3096
3097     v = TMALLOC(bucket *, nsyms);
3098     NO_SPACE(v);
3099
3100     v[0] = 0;
3101     v[start_symbol] = 0;
3102
3103     i = 1;
3104     j = (Value_t) (start_symbol + 1);
3105     for (bp = first_symbol; bp; bp = bp->next)
3106     {
3107         if (bp->class == TERM)
3108             v[i++] = bp;
3109         else
3110             v[j++] = bp;
3111     }
3112     assert(i == ntokens && j == nsyms);
3113
3114     for (i = 1; i < ntokens; ++i)
3115         v[i]->index = i;
3116
3117     goal->index = (Index_t) (start_symbol + 1);
3118     k = (Value_t) (start_symbol + 2);
3119     while (++i < nsyms)
3120         if (v[i] != goal)
3121         {
3122             v[i]->index = k;
3123             ++k;
3124         }
3125
3126     goal->value = 0;
3127     k = 1;
3128     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
3129     {
3130         if (v[i] != goal)
3131         {
3132             v[i]->value = k;
3133             ++k;
3134         }
3135     }
3136
3137     k = 0;
3138     for (i = 1; i < ntokens; ++i)
3139     {
3140         n = v[i]->value;
3141         if (n > 256)
3142         {
3143             for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
3144                 symbol_value[j] = symbol_value[j - 1];
3145             symbol_value[j] = n;
3146         }
3147     }
3148
3149     assert(v[1] != 0);
3150
3151     if (v[1]->value == UNDEFINED)
3152         v[1]->value = 256;
3153
3154     j = 0;
3155     n = 257;
3156     for (i = 2; i < ntokens; ++i)
3157     {
3158         if (v[i]->value == UNDEFINED)
3159         {
3160             while (j < k && n == symbol_value[j])
3161             {
3162                 while (++j < k && n == symbol_value[j])
3163                     continue;
3164                 ++n;
3165             }
3166             v[i]->value = n;
3167             ++n;
3168         }
3169     }
3170
3171     symbol_name[0] = name_pool + 8;
3172     symbol_value[0] = 0;
3173     symbol_prec[0] = 0;
3174     symbol_assoc[0] = TOKEN;
3175 #if defined(YYBTYACC)
3176     symbol_pval[0] = 0;
3177     max_tok_pval = 0;
3178 #endif
3179     for (i = 1; i < ntokens; ++i)
3180     {
3181         symbol_name[i] = v[i]->name;
3182         symbol_value[i] = v[i]->value;
3183         symbol_prec[i] = v[i]->prec;
3184         symbol_assoc[i] = v[i]->assoc;
3185 #if defined(YYBTYACC)
3186         symbol_pval[i] = v[i]->value;
3187         if (symbol_pval[i] > max_tok_pval)
3188             max_tok_pval = symbol_pval[i];
3189         if (destructor)
3190         {
3191             symbol_destructor[i] = v[i]->destructor;
3192             symbol_type_tag[i] = v[i]->tag;
3193         }
3194 #endif
3195     }
3196     symbol_name[start_symbol] = name_pool;
3197     symbol_value[start_symbol] = -1;
3198     symbol_prec[start_symbol] = 0;
3199     symbol_assoc[start_symbol] = TOKEN;
3200 #if defined(YYBTYACC)
3201     symbol_pval[start_symbol] = (Value_t) (max_tok_pval + 1);
3202 #endif
3203     for (++i; i < nsyms; ++i)
3204     {
3205         k = v[i]->index;
3206         symbol_name[k] = v[i]->name;
3207         symbol_value[k] = v[i]->value;
3208         symbol_prec[k] = v[i]->prec;
3209         symbol_assoc[k] = v[i]->assoc;
3210 #if defined(YYBTYACC)
3211         symbol_pval[k] = (Value_t) ((max_tok_pval + 1) + v[i]->value + 1);
3212         if (destructor)
3213         {
3214             symbol_destructor[k] = v[i]->destructor;
3215             symbol_type_tag[k] = v[i]->tag;
3216         }
3217 #endif
3218     }
3219
3220     if (gflag)
3221     {
3222         symbol_pname = TMALLOC(char *, nsyms);
3223         NO_SPACE(symbol_pname);
3224
3225         for (i = 0; i < nsyms; ++i)
3226             protect_string(symbol_name[i], &(symbol_pname[i]));
3227     }
3228
3229     FREE(v);
3230 }
3231
3232 static void
3233 pack_grammar(void)
3234 {
3235     int i;
3236     Value_t j;
3237     Assoc_t assoc;
3238     Value_t prec2;
3239
3240     ritem = TMALLOC(Value_t, nitems);
3241     NO_SPACE(ritem);
3242
3243     rlhs = TMALLOC(Value_t, nrules);
3244     NO_SPACE(rlhs);
3245
3246     rrhs = TMALLOC(Value_t, nrules + 1);
3247     NO_SPACE(rrhs);
3248
3249     rprec = TREALLOC(Value_t, rprec, nrules);
3250     NO_SPACE(rprec);
3251
3252     rassoc = TREALLOC(Assoc_t, rassoc, nrules);
3253     NO_SPACE(rassoc);
3254
3255     ritem[0] = -1;
3256     ritem[1] = goal->index;
3257     ritem[2] = 0;
3258     ritem[3] = -2;
3259     rlhs[0] = 0;
3260     rlhs[1] = 0;
3261     rlhs[2] = start_symbol;
3262     rrhs[0] = 0;
3263     rrhs[1] = 0;
3264     rrhs[2] = 1;
3265
3266     j = 4;
3267     for (i = 3; i < nrules; ++i)
3268     {
3269 #if defined(YYBTYACC)
3270         if (plhs[i]->args > 0)
3271         {
3272             if (plhs[i]->argnames)
3273             {
3274                 FREE(plhs[i]->argnames);
3275                 plhs[i]->argnames = NULL;
3276             }
3277             if (plhs[i]->argtags)
3278             {
3279                 FREE(plhs[i]->argtags);
3280                 plhs[i]->argtags = NULL;
3281             }
3282         }
3283 #endif /* defined(YYBTYACC) */
3284         rlhs[i] = plhs[i]->index;
3285         rrhs[i] = j;
3286         assoc = TOKEN;
3287         prec2 = 0;
3288         while (pitem[j])
3289         {
3290             ritem[j] = pitem[j]->index;
3291             if (pitem[j]->class == TERM)
3292             {
3293                 prec2 = pitem[j]->prec;
3294                 assoc = pitem[j]->assoc;
3295             }
3296             ++j;
3297         }
3298         ritem[j] = (Value_t) - i;
3299         ++j;
3300         if (rprec[i] == UNDEFINED)
3301         {
3302             rprec[i] = prec2;
3303             rassoc[i] = assoc;
3304         }
3305     }
3306     rrhs[i] = j;
3307
3308     FREE(plhs);
3309     FREE(pitem);
3310 #if defined(YYBTYACC)
3311     clean_arg_cache();
3312 #endif
3313 }
3314
3315 static void
3316 print_grammar(void)
3317 {
3318     int i, k;
3319     size_t j, spacing = 0;
3320     FILE *f = verbose_file;
3321
3322     if (!vflag)
3323         return;
3324
3325     k = 1;
3326     for (i = 2; i < nrules; ++i)
3327     {
3328         if (rlhs[i] != rlhs[i - 1])
3329         {
3330             if (i != 2)
3331                 fprintf(f, "\n");
3332             fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
3333             spacing = strlen(symbol_name[rlhs[i]]) + 1;
3334         }
3335         else
3336         {
3337             fprintf(f, "%4d  ", i - 2);
3338             j = spacing;
3339             while (j-- != 0)
3340                 putc(' ', f);
3341             putc('|', f);
3342         }
3343
3344         while (ritem[k] >= 0)
3345         {
3346             fprintf(f, " %s", symbol_name[ritem[k]]);
3347             ++k;
3348         }
3349         ++k;
3350         putc('\n', f);
3351     }
3352 }
3353
3354 #if defined(YYBTYACC)
3355 static void
3356 finalize_destructors(void)
3357 {
3358     int i;
3359     bucket *bp;
3360     char *tag;
3361
3362     for (i = 2; i < nsyms; ++i)
3363     {
3364         tag = symbol_type_tag[i];
3365         if (symbol_destructor[i] == NULL)
3366         {
3367             if (tag == NULL)
3368             {                   /* use <> destructor, if there is one */
3369                 if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3370                 {
3371                     symbol_destructor[i] = TMALLOC(char,
3372                                                    strlen(bp->destructor) + 1);
3373                     NO_SPACE(symbol_destructor[i]);
3374                     strcpy(symbol_destructor[i], bp->destructor);
3375                 }
3376             }
3377             else
3378             {                   /* use type destructor for this tag, if there is one */
3379                 bp = lookup_type_destructor(tag);
3380                 if (bp->destructor != NULL)
3381                 {
3382                     symbol_destructor[i] = TMALLOC(char,
3383                                                    strlen(bp->destructor) + 1);
3384                     NO_SPACE(symbol_destructor[i]);
3385                     strcpy(symbol_destructor[i], bp->destructor);
3386                 }
3387                 else
3388                 {               /* use <*> destructor, if there is one */
3389                     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3390                         /* replace "$$" with "(*val).tag" in destructor code */
3391                         symbol_destructor[i]
3392                             = process_destructor_XX(bp->destructor, tag);
3393                 }
3394             }
3395         }
3396         else
3397         {                       /* replace "$$" with "(*val)[.tag]" in destructor code */
3398             symbol_destructor[i]
3399                 = process_destructor_XX(symbol_destructor[i], tag);
3400         }
3401     }
3402     /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
3403     DO_FREE(symbol_type_tag);   /* no longer needed */
3404     if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3405     {
3406         FREE(bp->name);
3407         /* 'bp->tag' is a static value, don't free */
3408         FREE(bp->destructor);
3409         FREE(bp);
3410     }
3411     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3412     {
3413         FREE(bp->name);
3414         /* 'bp->tag' is a static value, don't free */
3415         FREE(bp->destructor);
3416         FREE(bp);
3417     }
3418     if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
3419     {
3420         bucket *p;
3421         for (; bp; bp = p)
3422         {
3423             p = bp->link;
3424             FREE(bp->name);
3425             /* 'bp->tag' freed by 'free_tags()' */
3426             FREE(bp->destructor);
3427             FREE(bp);
3428         }
3429     }
3430 }
3431 #endif /* defined(YYBTYACC) */
3432
3433 void
3434 reader(void)
3435 {
3436     write_section(code_file, banner);
3437     create_symbol_table();
3438     read_declarations();
3439     read_grammar();
3440     free_symbol_table();
3441     pack_names();
3442     check_symbols();
3443     pack_symbols();
3444     pack_grammar();
3445     free_symbols();
3446     print_grammar();
3447 #if defined(YYBTYACC)
3448     if (destructor)
3449         finalize_destructors();
3450 #endif
3451     free_tags();
3452 }
3453
3454 #ifdef NO_LEAKS
3455 static param *
3456 free_declarations(param * list)
3457 {
3458     while (list != 0)
3459     {
3460         param *next = list->next;
3461         free(list->type);
3462         free(list->name);
3463         free(list->type2);
3464         free(list);
3465         list = next;
3466     }
3467     return list;
3468 }
3469
3470 void
3471 reader_leaks(void)
3472 {
3473     lex_param = free_declarations(lex_param);
3474     parse_param = free_declarations(parse_param);
3475
3476     DO_FREE(line);
3477     DO_FREE(rrhs);
3478     DO_FREE(rlhs);
3479     DO_FREE(rprec);
3480     DO_FREE(ritem);
3481     DO_FREE(rassoc);
3482     DO_FREE(cache);
3483     DO_FREE(name_pool);
3484     DO_FREE(symbol_name);
3485     DO_FREE(symbol_prec);
3486     DO_FREE(symbol_assoc);
3487     DO_FREE(symbol_value);
3488 #if defined(YYBTYACC)
3489     DO_FREE(symbol_pval);
3490     DO_FREE(symbol_destructor);
3491     DO_FREE(symbol_type_tag);
3492 #endif
3493 }
3494 #endif