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