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