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