xref: /dragonfly/contrib/byacc/reader.c (revision cecb9aae)
1 /* $Id: reader.c,v 1.36 2012/05/26 16:05:41 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 
15 static void start_rule(bucket *bp, int s_lineno);
16 
17 static char *cache;
18 static int cinc, cache_size;
19 
20 int ntags;
21 static int tagmax;
22 static char **tag_table;
23 
24 static char saw_eof;
25 char unionized;
26 char *cptr, *line;
27 static int linesize;
28 
29 static bucket *goal;
30 static Value_t prec;
31 static int gensym;
32 static char last_was_action;
33 
34 static int maxitems;
35 static bucket **pitem;
36 
37 static int maxrules;
38 static bucket **plhs;
39 
40 static size_t name_pool_size;
41 static char *name_pool;
42 
43 char line_format[] = "#line %d \"%s\"\n";
44 
45 param *lex_param;
46 param *parse_param;
47 
48 static void
49 cachec(int c)
50 {
51     assert(cinc >= 0);
52     if (cinc >= cache_size)
53     {
54 	cache_size += 256;
55 	cache = TREALLOC(char, cache, cache_size);
56 	NO_SPACE(cache);
57     }
58     cache[cinc] = (char)c;
59     ++cinc;
60 }
61 
62 static void
63 get_line(void)
64 {
65     FILE *f = input_file;
66     int c;
67     int i;
68 
69     if (saw_eof || (c = getc(f)) == EOF)
70     {
71 	if (line)
72 	{
73 	    FREE(line);
74 	    line = 0;
75 	}
76 	cptr = 0;
77 	saw_eof = 1;
78 	return;
79     }
80 
81     if (line == 0 || linesize != (LINESIZE + 1))
82     {
83 	if (line)
84 	    FREE(line);
85 	linesize = LINESIZE + 1;
86 	line = TMALLOC(char, linesize);
87 	NO_SPACE(line);
88     }
89 
90     i = 0;
91     ++lineno;
92     for (;;)
93     {
94 	line[i] = (char)c;
95 	if (c == '\n')
96 	{
97 	    cptr = line;
98 	    return;
99 	}
100 	if (++i >= linesize)
101 	{
102 	    linesize += LINESIZE;
103 	    line = TREALLOC(char, line, linesize);
104 	    NO_SPACE(line);
105 	}
106 	c = getc(f);
107 	if (c == EOF)
108 	{
109 	    line[i] = '\n';
110 	    saw_eof = 1;
111 	    cptr = line;
112 	    return;
113 	}
114     }
115 }
116 
117 static char *
118 dup_line(void)
119 {
120     char *p, *s, *t;
121 
122     if (line == 0)
123 	return (0);
124     s = line;
125     while (*s != '\n')
126 	++s;
127     p = TMALLOC(char, s - line + 1);
128     NO_SPACE(p);
129 
130     s = line;
131     t = p;
132     while ((*t++ = *s++) != '\n')
133 	continue;
134     return (p);
135 }
136 
137 static void
138 skip_comment(void)
139 {
140     char *s;
141 
142     int st_lineno = lineno;
143     char *st_line = dup_line();
144     char *st_cptr = st_line + (cptr - line);
145 
146     s = cptr + 2;
147     for (;;)
148     {
149 	if (*s == '*' && s[1] == '/')
150 	{
151 	    cptr = s + 2;
152 	    FREE(st_line);
153 	    return;
154 	}
155 	if (*s == '\n')
156 	{
157 	    get_line();
158 	    if (line == 0)
159 		unterminated_comment(st_lineno, st_line, st_cptr);
160 	    s = cptr;
161 	}
162 	else
163 	    ++s;
164     }
165 }
166 
167 static int
168 nextc(void)
169 {
170     char *s;
171 
172     if (line == 0)
173     {
174 	get_line();
175 	if (line == 0)
176 	    return (EOF);
177     }
178 
179     s = cptr;
180     for (;;)
181     {
182 	switch (*s)
183 	{
184 	case '\n':
185 	    get_line();
186 	    if (line == 0)
187 		return (EOF);
188 	    s = cptr;
189 	    break;
190 
191 	case ' ':
192 	case '\t':
193 	case '\f':
194 	case '\r':
195 	case '\v':
196 	case ',':
197 	case ';':
198 	    ++s;
199 	    break;
200 
201 	case '\\':
202 	    cptr = s;
203 	    return ('%');
204 
205 	case '/':
206 	    if (s[1] == '*')
207 	    {
208 		cptr = s;
209 		skip_comment();
210 		s = cptr;
211 		break;
212 	    }
213 	    else if (s[1] == '/')
214 	    {
215 		get_line();
216 		if (line == 0)
217 		    return (EOF);
218 		s = cptr;
219 		break;
220 	    }
221 	    /* FALLTHRU */
222 
223 	default:
224 	    cptr = s;
225 	    return (*s);
226 	}
227     }
228 }
229 
230 /*
231  * Compare keyword to cached token, treating '_' and '-' the same.  Some
232  * grammars rely upon this misfeature.
233  */
234 static int
235 matchec(const char *name)
236 {
237     const char *p = cache;
238     const char *q = name;
239     int code = 0;	/* assume mismatch */
240 
241     while (*p != '\0' && *q != '\0')
242     {
243 	char a = *p++;
244 	char b = *q++;
245 	if (a == '_')
246 	    a = '-';
247 	if (b == '_')
248 	    b = '-';
249 	if (a != b)
250 	    break;
251 	if (*p == '\0' && *q == '\0')
252 	{
253 	    code = 1;
254 	    break;
255 	}
256     }
257     return code;
258 }
259 
260 static int
261 keyword(void)
262 {
263     int c;
264     char *t_cptr = cptr;
265 
266     c = *++cptr;
267     if (isalpha(c))
268     {
269 	cinc = 0;
270 	for (;;)
271 	{
272 	    if (isalpha(c))
273 	    {
274 		if (isupper(c))
275 		    c = tolower(c);
276 		cachec(c);
277 	    }
278 	    else if (isdigit(c)
279 		     || c == '-'
280 		     || c == '_'
281 		     || c == '.'
282 		     || c == '$')
283 	    {
284 		cachec(c);
285 	    }
286 	    else
287 	    {
288 		break;
289 	    }
290 	    c = *++cptr;
291 	}
292 	cachec(NUL);
293 
294 	if (matchec("token") || matchec("term"))
295 	    return (TOKEN);
296 	if (matchec("type"))
297 	    return (TYPE);
298 	if (matchec("left"))
299 	    return (LEFT);
300 	if (matchec("right"))
301 	    return (RIGHT);
302 	if (matchec("nonassoc") || matchec("binary"))
303 	    return (NONASSOC);
304 	if (matchec("start"))
305 	    return (START);
306 	if (matchec("union"))
307 	    return (UNION);
308 	if (matchec("ident"))
309 	    return (IDENT);
310 	if (matchec("expect"))
311 	    return (EXPECT);
312 	if (matchec("expect-rr"))
313 	    return (EXPECT_RR);
314 	if (matchec("pure-parser"))
315 	    return (PURE_PARSER);
316 	if (matchec("parse-param"))
317 	    return (PARSE_PARAM);
318 	if (matchec("lex-param"))
319 	    return (LEX_PARAM);
320 	if (matchec("yacc"))
321 	    return (POSIX_YACC);
322     }
323     else
324     {
325 	++cptr;
326 	if (c == L_CURL)
327 	    return (TEXT);
328 	if (c == '%' || c == '\\')
329 	    return (MARK);
330 	if (c == '<')
331 	    return (LEFT);
332 	if (c == '>')
333 	    return (RIGHT);
334 	if (c == '0')
335 	    return (TOKEN);
336 	if (c == '2')
337 	    return (NONASSOC);
338     }
339     syntax_error(lineno, line, t_cptr);
340     /*NOTREACHED */
341 }
342 
343 static void
344 copy_ident(void)
345 {
346     int c;
347     FILE *f = output_file;
348 
349     c = nextc();
350     if (c == EOF)
351 	unexpected_EOF();
352     if (c != '"')
353 	syntax_error(lineno, line, cptr);
354     ++outline;
355     fprintf(f, "#ident \"");
356     for (;;)
357     {
358 	c = *++cptr;
359 	if (c == '\n')
360 	{
361 	    fprintf(f, "\"\n");
362 	    return;
363 	}
364 	putc(c, f);
365 	if (c == '"')
366 	{
367 	    putc('\n', f);
368 	    ++cptr;
369 	    return;
370 	}
371     }
372 }
373 
374 static void
375 copy_text(void)
376 {
377     int c;
378     int quote;
379     FILE *f = text_file;
380     int need_newline = 0;
381     int t_lineno = lineno;
382     char *t_line = dup_line();
383     char *t_cptr = t_line + (cptr - line - 2);
384 
385     if (*cptr == '\n')
386     {
387 	get_line();
388 	if (line == 0)
389 	    unterminated_text(t_lineno, t_line, t_cptr);
390     }
391     if (!lflag)
392 	fprintf(f, line_format, lineno, input_file_name);
393 
394   loop:
395     c = *cptr++;
396     switch (c)
397     {
398     case '\n':
399       next_line:
400 	putc('\n', f);
401 	need_newline = 0;
402 	get_line();
403 	if (line)
404 	    goto loop;
405 	unterminated_text(t_lineno, t_line, t_cptr);
406 
407     case '\'':
408     case '"':
409 	{
410 	    int s_lineno = lineno;
411 	    char *s_line = dup_line();
412 	    char *s_cptr = s_line + (cptr - line - 1);
413 
414 	    quote = c;
415 	    putc(c, f);
416 	    for (;;)
417 	    {
418 		c = *cptr++;
419 		putc(c, f);
420 		if (c == quote)
421 		{
422 		    need_newline = 1;
423 		    FREE(s_line);
424 		    goto loop;
425 		}
426 		if (c == '\n')
427 		    unterminated_string(s_lineno, s_line, s_cptr);
428 		if (c == '\\')
429 		{
430 		    c = *cptr++;
431 		    putc(c, f);
432 		    if (c == '\n')
433 		    {
434 			get_line();
435 			if (line == 0)
436 			    unterminated_string(s_lineno, s_line, s_cptr);
437 		    }
438 		}
439 	    }
440 	}
441 
442     case '/':
443 	putc(c, f);
444 	need_newline = 1;
445 	c = *cptr;
446 	if (c == '/')
447 	{
448 	    putc('*', f);
449 	    while ((c = *++cptr) != '\n')
450 	    {
451 		if (c == '*' && cptr[1] == '/')
452 		    fprintf(f, "* ");
453 		else
454 		    putc(c, f);
455 	    }
456 	    fprintf(f, "*/");
457 	    goto next_line;
458 	}
459 	if (c == '*')
460 	{
461 	    int c_lineno = lineno;
462 	    char *c_line = dup_line();
463 	    char *c_cptr = c_line + (cptr - line - 1);
464 
465 	    putc('*', f);
466 	    ++cptr;
467 	    for (;;)
468 	    {
469 		c = *cptr++;
470 		putc(c, f);
471 		if (c == '*' && *cptr == '/')
472 		{
473 		    putc('/', f);
474 		    ++cptr;
475 		    FREE(c_line);
476 		    goto loop;
477 		}
478 		if (c == '\n')
479 		{
480 		    get_line();
481 		    if (line == 0)
482 			unterminated_comment(c_lineno, c_line, c_cptr);
483 		}
484 	    }
485 	}
486 	need_newline = 1;
487 	goto loop;
488 
489     case '%':
490     case '\\':
491 	if (*cptr == R_CURL)
492 	{
493 	    if (need_newline)
494 		putc('\n', f);
495 	    ++cptr;
496 	    FREE(t_line);
497 	    return;
498 	}
499 	/* FALLTHRU */
500 
501     default:
502 	putc(c, f);
503 	need_newline = 1;
504 	goto loop;
505     }
506 }
507 
508 static void
509 puts_both(const char *s)
510 {
511     fputs(s, text_file);
512     if (dflag)
513 	fputs(s, union_file);
514 }
515 
516 static void
517 putc_both(int c)
518 {
519     putc(c, text_file);
520     if (dflag)
521 	putc(c, union_file);
522 }
523 
524 static void
525 copy_union(void)
526 {
527     int c;
528     int quote;
529     int depth;
530     int u_lineno = lineno;
531     char *u_line = dup_line();
532     char *u_cptr = u_line + (cptr - line - 6);
533 
534     if (unionized)
535 	over_unionized(cptr - 6);
536     unionized = 1;
537 
538     if (!lflag)
539 	fprintf(text_file, line_format, lineno, input_file_name);
540 
541     puts_both("#ifdef YYSTYPE\n");
542     puts_both("#undef  YYSTYPE_IS_DECLARED\n");
543     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
544     puts_both("#endif\n");
545     puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
546     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
547     puts_both("typedef union");
548 
549     depth = 0;
550   loop:
551     c = *cptr++;
552     putc_both(c);
553     switch (c)
554     {
555     case '\n':
556       next_line:
557 	get_line();
558 	if (line == 0)
559 	    unterminated_union(u_lineno, u_line, u_cptr);
560 	goto loop;
561 
562     case L_CURL:
563 	++depth;
564 	goto loop;
565 
566     case R_CURL:
567 	if (--depth == 0)
568 	{
569 	    puts_both(" YYSTYPE;\n");
570 	    puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
571 	    FREE(u_line);
572 	    return;
573 	}
574 	goto loop;
575 
576     case '\'':
577     case '"':
578 	{
579 	    int s_lineno = lineno;
580 	    char *s_line = dup_line();
581 	    char *s_cptr = s_line + (cptr - line - 1);
582 
583 	    quote = c;
584 	    for (;;)
585 	    {
586 		c = *cptr++;
587 		putc_both(c);
588 		if (c == quote)
589 		{
590 		    FREE(s_line);
591 		    goto loop;
592 		}
593 		if (c == '\n')
594 		    unterminated_string(s_lineno, s_line, s_cptr);
595 		if (c == '\\')
596 		{
597 		    c = *cptr++;
598 		    putc_both(c);
599 		    if (c == '\n')
600 		    {
601 			get_line();
602 			if (line == 0)
603 			    unterminated_string(s_lineno, s_line, s_cptr);
604 		    }
605 		}
606 	    }
607 	}
608 
609     case '/':
610 	c = *cptr;
611 	if (c == '/')
612 	{
613 	    putc_both('*');
614 	    while ((c = *++cptr) != '\n')
615 	    {
616 		if (c == '*' && cptr[1] == '/')
617 		{
618 		    puts_both("* ");
619 		}
620 		else
621 		{
622 		    putc_both(c);
623 		}
624 	    }
625 	    puts_both("*/\n");
626 	    goto next_line;
627 	}
628 	if (c == '*')
629 	{
630 	    int c_lineno = lineno;
631 	    char *c_line = dup_line();
632 	    char *c_cptr = c_line + (cptr - line - 1);
633 
634 	    putc_both('*');
635 	    ++cptr;
636 	    for (;;)
637 	    {
638 		c = *cptr++;
639 		putc_both(c);
640 		if (c == '*' && *cptr == '/')
641 		{
642 		    putc_both('/');
643 		    ++cptr;
644 		    FREE(c_line);
645 		    goto loop;
646 		}
647 		if (c == '\n')
648 		{
649 		    get_line();
650 		    if (line == 0)
651 			unterminated_comment(c_lineno, c_line, c_cptr);
652 		}
653 	    }
654 	}
655 	goto loop;
656 
657     default:
658 	goto loop;
659     }
660 }
661 
662 /*
663  * Keep a linked list of parameters
664  */
665 static void
666 copy_param(int k)
667 {
668     char *buf;
669     int c;
670     param *head, *p;
671     int i;
672     int name, type2;
673 
674     c = nextc();
675     if (c == EOF)
676 	unexpected_EOF();
677     if (c != '{')
678 	goto out;
679     cptr++;
680 
681     c = nextc();
682     if (c == EOF)
683 	unexpected_EOF();
684     if (c == '}')
685 	goto out;
686 
687     buf = TMALLOC(char, linesize);
688     NO_SPACE(buf);
689 
690     for (i = 0; (c = *cptr++) != '}'; i++)
691     {
692 	if (c == '\0')
693 	    missing_brace();
694 	if (c == EOF)
695 	    unexpected_EOF();
696 	buf[i] = (char)c;
697     }
698 
699     if (i == 0)
700 	goto out;
701 
702     buf[i--] = '\0';
703     while (i >= 0 && isspace(UCH(buf[i])))
704 	buf[i--] = '\0';
705 
706     if (buf[i] == ']')
707     {
708 	int level = 1;
709 	while (i >= 0 && level > 0 && buf[i] != '[')
710 	{
711 	    if (buf[i] == ']')
712 		++level;
713 	    else if (buf[i] == '[')
714 		--level;
715 	    i--;
716 	}
717 	if (i <= 0)
718 	    unexpected_EOF();
719 	type2 = i--;
720     }
721     else
722     {
723 	type2 = i + 1;
724     }
725 
726     while (i >= 0 && (isalnum(UCH(buf[i])) ||
727 		      UCH(buf[i]) == '_'))
728 	i--;
729 
730     if (!isspace(UCH(buf[i])) && buf[i] != '*')
731 	goto out;
732 
733     name = i + 1;
734 
735     p = TMALLOC(param, 1);
736     NO_SPACE(p);
737 
738     p->type2 = strdup(buf + type2);
739     NO_SPACE(p->type2);
740 
741     buf[type2] = '\0';
742 
743     p->name = strdup(buf + name);
744     NO_SPACE(p->name);
745 
746     buf[name] = '\0';
747     p->type = buf;
748 
749     if (k == LEX_PARAM)
750 	head = lex_param;
751     else
752 	head = parse_param;
753 
754     if (head != NULL)
755     {
756 	while (head->next)
757 	    head = head->next;
758 	head->next = p;
759     }
760     else
761     {
762 	if (k == LEX_PARAM)
763 	    lex_param = p;
764 	else
765 	    parse_param = p;
766     }
767     p->next = NULL;
768     return;
769 
770   out:
771     syntax_error(lineno, line, cptr);
772 }
773 
774 static int
775 hexval(int c)
776 {
777     if (c >= '0' && c <= '9')
778 	return (c - '0');
779     if (c >= 'A' && c <= 'F')
780 	return (c - 'A' + 10);
781     if (c >= 'a' && c <= 'f')
782 	return (c - 'a' + 10);
783     return (-1);
784 }
785 
786 static bucket *
787 get_literal(void)
788 {
789     int c, quote;
790     int i;
791     int n;
792     char *s;
793     bucket *bp;
794     int s_lineno = lineno;
795     char *s_line = dup_line();
796     char *s_cptr = s_line + (cptr - line);
797 
798     quote = *cptr++;
799     cinc = 0;
800     for (;;)
801     {
802 	c = *cptr++;
803 	if (c == quote)
804 	    break;
805 	if (c == '\n')
806 	    unterminated_string(s_lineno, s_line, s_cptr);
807 	if (c == '\\')
808 	{
809 	    char *c_cptr = cptr - 1;
810 
811 	    c = *cptr++;
812 	    switch (c)
813 	    {
814 	    case '\n':
815 		get_line();
816 		if (line == 0)
817 		    unterminated_string(s_lineno, s_line, s_cptr);
818 		continue;
819 
820 	    case '0':
821 	    case '1':
822 	    case '2':
823 	    case '3':
824 	    case '4':
825 	    case '5':
826 	    case '6':
827 	    case '7':
828 		n = c - '0';
829 		c = *cptr;
830 		if (IS_OCTAL(c))
831 		{
832 		    n = (n << 3) + (c - '0');
833 		    c = *++cptr;
834 		    if (IS_OCTAL(c))
835 		    {
836 			n = (n << 3) + (c - '0');
837 			++cptr;
838 		    }
839 		}
840 		if (n > MAXCHAR)
841 		    illegal_character(c_cptr);
842 		c = n;
843 		break;
844 
845 	    case 'x':
846 		c = *cptr++;
847 		n = hexval(c);
848 		if (n < 0 || n >= 16)
849 		    illegal_character(c_cptr);
850 		for (;;)
851 		{
852 		    c = *cptr;
853 		    i = hexval(c);
854 		    if (i < 0 || i >= 16)
855 			break;
856 		    ++cptr;
857 		    n = (n << 4) + i;
858 		    if (n > MAXCHAR)
859 			illegal_character(c_cptr);
860 		}
861 		c = n;
862 		break;
863 
864 	    case 'a':
865 		c = 7;
866 		break;
867 	    case 'b':
868 		c = '\b';
869 		break;
870 	    case 'f':
871 		c = '\f';
872 		break;
873 	    case 'n':
874 		c = '\n';
875 		break;
876 	    case 'r':
877 		c = '\r';
878 		break;
879 	    case 't':
880 		c = '\t';
881 		break;
882 	    case 'v':
883 		c = '\v';
884 		break;
885 	    }
886 	}
887 	cachec(c);
888     }
889     FREE(s_line);
890 
891     n = cinc;
892     s = TMALLOC(char, n);
893     NO_SPACE(s);
894 
895     for (i = 0; i < n; ++i)
896 	s[i] = cache[i];
897 
898     cinc = 0;
899     if (n == 1)
900 	cachec('\'');
901     else
902 	cachec('"');
903 
904     for (i = 0; i < n; ++i)
905     {
906 	c = UCH(s[i]);
907 	if (c == '\\' || c == cache[0])
908 	{
909 	    cachec('\\');
910 	    cachec(c);
911 	}
912 	else if (isprint(c))
913 	    cachec(c);
914 	else
915 	{
916 	    cachec('\\');
917 	    switch (c)
918 	    {
919 	    case 7:
920 		cachec('a');
921 		break;
922 	    case '\b':
923 		cachec('b');
924 		break;
925 	    case '\f':
926 		cachec('f');
927 		break;
928 	    case '\n':
929 		cachec('n');
930 		break;
931 	    case '\r':
932 		cachec('r');
933 		break;
934 	    case '\t':
935 		cachec('t');
936 		break;
937 	    case '\v':
938 		cachec('v');
939 		break;
940 	    default:
941 		cachec(((c >> 6) & 7) + '0');
942 		cachec(((c >> 3) & 7) + '0');
943 		cachec((c & 7) + '0');
944 		break;
945 	    }
946 	}
947     }
948 
949     if (n == 1)
950 	cachec('\'');
951     else
952 	cachec('"');
953 
954     cachec(NUL);
955     bp = lookup(cache);
956     bp->class = TERM;
957     if (n == 1 && bp->value == UNDEFINED)
958 	bp->value = UCH(*s);
959     FREE(s);
960 
961     return (bp);
962 }
963 
964 static int
965 is_reserved(char *name)
966 {
967     char *s;
968 
969     if (strcmp(name, ".") == 0 ||
970 	strcmp(name, "$accept") == 0 ||
971 	strcmp(name, "$end") == 0)
972 	return (1);
973 
974     if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
975     {
976 	s = name + 3;
977 	while (isdigit(UCH(*s)))
978 	    ++s;
979 	if (*s == NUL)
980 	    return (1);
981     }
982 
983     return (0);
984 }
985 
986 static bucket *
987 get_name(void)
988 {
989     int c;
990 
991     cinc = 0;
992     for (c = *cptr; IS_IDENT(c); c = *++cptr)
993 	cachec(c);
994     cachec(NUL);
995 
996     if (is_reserved(cache))
997 	used_reserved(cache);
998 
999     return (lookup(cache));
1000 }
1001 
1002 static Value_t
1003 get_number(void)
1004 {
1005     int c;
1006     Value_t n;
1007 
1008     n = 0;
1009     for (c = *cptr; isdigit(c); c = *++cptr)
1010 	n = (Value_t) (10 * n + (c - '0'));
1011 
1012     return (n);
1013 }
1014 
1015 static char *
1016 get_tag(void)
1017 {
1018     int c;
1019     int i;
1020     char *s;
1021     int t_lineno = lineno;
1022     char *t_line = dup_line();
1023     char *t_cptr = t_line + (cptr - line);
1024 
1025     ++cptr;
1026     c = nextc();
1027     if (c == EOF)
1028 	unexpected_EOF();
1029     if (!isalpha(c) && c != '_' && c != '$')
1030 	illegal_tag(t_lineno, t_line, t_cptr);
1031 
1032     cinc = 0;
1033     do
1034     {
1035 	cachec(c);
1036 	c = *++cptr;
1037     }
1038     while (IS_IDENT(c));
1039     cachec(NUL);
1040 
1041     c = nextc();
1042     if (c == EOF)
1043 	unexpected_EOF();
1044     if (c != '>')
1045 	illegal_tag(t_lineno, t_line, t_cptr);
1046     ++cptr;
1047 
1048     for (i = 0; i < ntags; ++i)
1049     {
1050 	if (strcmp(cache, tag_table[i]) == 0)
1051 	{
1052 	    FREE(t_line);
1053 	    return (tag_table[i]);
1054 	}
1055     }
1056 
1057     if (ntags >= tagmax)
1058     {
1059 	tagmax += 16;
1060 	tag_table =
1061 	    (tag_table
1062 	     ? TREALLOC(char *, tag_table, tagmax)
1063 	     : TMALLOC(char *, tagmax));
1064 	NO_SPACE(tag_table);
1065     }
1066 
1067     s = TMALLOC(char, cinc);
1068     NO_SPACE(s);
1069 
1070     strcpy(s, cache);
1071     tag_table[ntags] = s;
1072     ++ntags;
1073     FREE(t_line);
1074     return (s);
1075 }
1076 
1077 static void
1078 declare_tokens(int assoc)
1079 {
1080     int c;
1081     bucket *bp;
1082     Value_t value;
1083     char *tag = 0;
1084 
1085     if (assoc != TOKEN)
1086 	++prec;
1087 
1088     c = nextc();
1089     if (c == EOF)
1090 	unexpected_EOF();
1091     if (c == '<')
1092     {
1093 	tag = get_tag();
1094 	c = nextc();
1095 	if (c == EOF)
1096 	    unexpected_EOF();
1097     }
1098 
1099     for (;;)
1100     {
1101 	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1102 	    bp = get_name();
1103 	else if (c == '\'' || c == '"')
1104 	    bp = get_literal();
1105 	else
1106 	    return;
1107 
1108 	if (bp == goal)
1109 	    tokenized_start(bp->name);
1110 	bp->class = TERM;
1111 
1112 	if (tag)
1113 	{
1114 	    if (bp->tag && tag != bp->tag)
1115 		retyped_warning(bp->name);
1116 	    bp->tag = tag;
1117 	}
1118 
1119 	if (assoc != TOKEN)
1120 	{
1121 	    if (bp->prec && prec != bp->prec)
1122 		reprec_warning(bp->name);
1123 	    bp->assoc = (Assoc_t) assoc;
1124 	    bp->prec = prec;
1125 	}
1126 
1127 	c = nextc();
1128 	if (c == EOF)
1129 	    unexpected_EOF();
1130 
1131 	if (isdigit(c))
1132 	{
1133 	    value = get_number();
1134 	    if (bp->value != UNDEFINED && value != bp->value)
1135 		revalued_warning(bp->name);
1136 	    bp->value = value;
1137 	    c = nextc();
1138 	    if (c == EOF)
1139 		unexpected_EOF();
1140 	}
1141     }
1142 }
1143 
1144 /*
1145  * %expect requires special handling
1146  * as it really isn't part of the yacc
1147  * grammar only a flag for yacc proper.
1148  */
1149 static void
1150 declare_expect(int assoc)
1151 {
1152     int c;
1153 
1154     if (assoc != EXPECT && assoc != EXPECT_RR)
1155 	++prec;
1156 
1157     /*
1158      * Stay away from nextc - doesn't
1159      * detect EOL and will read to EOF.
1160      */
1161     c = *++cptr;
1162     if (c == EOF)
1163 	unexpected_EOF();
1164 
1165     for (;;)
1166     {
1167 	if (isdigit(c))
1168 	{
1169 	    if (assoc == EXPECT)
1170 		SRexpect = get_number();
1171 	    else
1172 		RRexpect = get_number();
1173 	    break;
1174 	}
1175 	/*
1176 	 * Looking for number before EOL.
1177 	 * Spaces, tabs, and numbers are ok,
1178 	 * words, punc., etc. are syntax errors.
1179 	 */
1180 	else if (c == '\n' || isalpha(c) || !isspace(c))
1181 	{
1182 	    syntax_error(lineno, line, cptr);
1183 	}
1184 	else
1185 	{
1186 	    c = *++cptr;
1187 	    if (c == EOF)
1188 		unexpected_EOF();
1189 	}
1190     }
1191 }
1192 
1193 static void
1194 declare_types(void)
1195 {
1196     int c;
1197     bucket *bp;
1198     char *tag;
1199 
1200     c = nextc();
1201     if (c == EOF)
1202 	unexpected_EOF();
1203     if (c != '<')
1204 	syntax_error(lineno, line, cptr);
1205     tag = get_tag();
1206 
1207     for (;;)
1208     {
1209 	c = nextc();
1210 	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1211 	    bp = get_name();
1212 	else if (c == '\'' || c == '"')
1213 	    bp = get_literal();
1214 	else
1215 	    return;
1216 
1217 	if (bp->tag && tag != bp->tag)
1218 	    retyped_warning(bp->name);
1219 	bp->tag = tag;
1220     }
1221 }
1222 
1223 static void
1224 declare_start(void)
1225 {
1226     int c;
1227     bucket *bp;
1228 
1229     c = nextc();
1230     if (c == EOF)
1231 	unexpected_EOF();
1232     if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1233 	syntax_error(lineno, line, cptr);
1234     bp = get_name();
1235     if (bp->class == TERM)
1236 	terminal_start(bp->name);
1237     if (goal && goal != bp)
1238 	restarted_warning();
1239     goal = bp;
1240 }
1241 
1242 static void
1243 read_declarations(void)
1244 {
1245     int c, k;
1246 
1247     cache_size = 256;
1248     cache = TMALLOC(char, cache_size);
1249     NO_SPACE(cache);
1250 
1251     for (;;)
1252     {
1253 	c = nextc();
1254 	if (c == EOF)
1255 	    unexpected_EOF();
1256 	if (c != '%')
1257 	    syntax_error(lineno, line, cptr);
1258 	switch (k = keyword())
1259 	{
1260 	case MARK:
1261 	    return;
1262 
1263 	case IDENT:
1264 	    copy_ident();
1265 	    break;
1266 
1267 	case TEXT:
1268 	    copy_text();
1269 	    break;
1270 
1271 	case UNION:
1272 	    copy_union();
1273 	    break;
1274 
1275 	case TOKEN:
1276 	case LEFT:
1277 	case RIGHT:
1278 	case NONASSOC:
1279 	    declare_tokens(k);
1280 	    break;
1281 
1282 	case EXPECT:
1283 	case EXPECT_RR:
1284 	    declare_expect(k);
1285 	    break;
1286 
1287 	case TYPE:
1288 	    declare_types();
1289 	    break;
1290 
1291 	case START:
1292 	    declare_start();
1293 	    break;
1294 
1295 	case PURE_PARSER:
1296 	    pure_parser = 1;
1297 	    break;
1298 
1299 	case PARSE_PARAM:
1300 	case LEX_PARAM:
1301 	    copy_param(k);
1302 	    break;
1303 
1304 	case POSIX_YACC:
1305 	    /* noop for bison compatibility. byacc is already designed to be posix
1306 	     * yacc compatible. */
1307 	    break;
1308 	}
1309     }
1310 }
1311 
1312 static void
1313 initialize_grammar(void)
1314 {
1315     nitems = 4;
1316     maxitems = 300;
1317 
1318     pitem = TMALLOC(bucket *, maxitems);
1319     NO_SPACE(pitem);
1320 
1321     pitem[0] = 0;
1322     pitem[1] = 0;
1323     pitem[2] = 0;
1324     pitem[3] = 0;
1325 
1326     nrules = 3;
1327     maxrules = 100;
1328 
1329     plhs = TMALLOC(bucket *, maxrules);
1330     NO_SPACE(plhs);
1331 
1332     plhs[0] = 0;
1333     plhs[1] = 0;
1334     plhs[2] = 0;
1335 
1336     rprec = TMALLOC(Value_t, maxrules);
1337     NO_SPACE(rprec);
1338 
1339     rprec[0] = 0;
1340     rprec[1] = 0;
1341     rprec[2] = 0;
1342 
1343     rassoc = TMALLOC(Assoc_t, maxrules);
1344     NO_SPACE(rassoc);
1345 
1346     rassoc[0] = TOKEN;
1347     rassoc[1] = TOKEN;
1348     rassoc[2] = TOKEN;
1349 }
1350 
1351 static void
1352 expand_items(void)
1353 {
1354     maxitems += 300;
1355     pitem = TREALLOC(bucket *, pitem, maxitems);
1356     NO_SPACE(pitem);
1357 }
1358 
1359 static void
1360 expand_rules(void)
1361 {
1362     maxrules += 100;
1363 
1364     plhs = TREALLOC(bucket *, plhs, maxrules);
1365     NO_SPACE(plhs);
1366 
1367     rprec = TREALLOC(Value_t, rprec, maxrules);
1368     NO_SPACE(rprec);
1369 
1370     rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
1371     NO_SPACE(rassoc);
1372 }
1373 
1374 static void
1375 advance_to_start(void)
1376 {
1377     int c;
1378     bucket *bp;
1379     char *s_cptr;
1380     int s_lineno;
1381 
1382     for (;;)
1383     {
1384 	c = nextc();
1385 	if (c != '%')
1386 	    break;
1387 	s_cptr = cptr;
1388 	switch (keyword())
1389 	{
1390 	case MARK:
1391 	    no_grammar();
1392 
1393 	case TEXT:
1394 	    copy_text();
1395 	    break;
1396 
1397 	case START:
1398 	    declare_start();
1399 	    break;
1400 
1401 	default:
1402 	    syntax_error(lineno, line, s_cptr);
1403 	}
1404     }
1405 
1406     c = nextc();
1407     if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1408 	syntax_error(lineno, line, cptr);
1409     bp = get_name();
1410     if (goal == 0)
1411     {
1412 	if (bp->class == TERM)
1413 	    terminal_start(bp->name);
1414 	goal = bp;
1415     }
1416 
1417     s_lineno = lineno;
1418     c = nextc();
1419     if (c == EOF)
1420 	unexpected_EOF();
1421     if (c != ':')
1422 	syntax_error(lineno, line, cptr);
1423     start_rule(bp, s_lineno);
1424     ++cptr;
1425 }
1426 
1427 static void
1428 start_rule(bucket *bp, int s_lineno)
1429 {
1430     if (bp->class == TERM)
1431 	terminal_lhs(s_lineno);
1432     bp->class = NONTERM;
1433     if (nrules >= maxrules)
1434 	expand_rules();
1435     plhs[nrules] = bp;
1436     rprec[nrules] = UNDEFINED;
1437     rassoc[nrules] = TOKEN;
1438 }
1439 
1440 static void
1441 end_rule(void)
1442 {
1443     int i;
1444 
1445     if (!last_was_action && plhs[nrules]->tag)
1446     {
1447 	if (pitem[nitems - 1])
1448 	{
1449 	    for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1450 		continue;
1451 	    if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1452 		default_action_warning();
1453 	}
1454 	else
1455 	{
1456 	    default_action_warning();
1457 	}
1458     }
1459 
1460     last_was_action = 0;
1461     if (nitems >= maxitems)
1462 	expand_items();
1463     pitem[nitems] = 0;
1464     ++nitems;
1465     ++nrules;
1466 }
1467 
1468 static void
1469 insert_empty_rule(void)
1470 {
1471     bucket *bp, **bpp;
1472 
1473     assert(cache);
1474     sprintf(cache, "$$%d", ++gensym);
1475     bp = make_bucket(cache);
1476     last_symbol->next = bp;
1477     last_symbol = bp;
1478     bp->tag = plhs[nrules]->tag;
1479     bp->class = NONTERM;
1480 
1481     if ((nitems += 2) > maxitems)
1482 	expand_items();
1483     bpp = pitem + nitems - 1;
1484     *bpp-- = bp;
1485     while ((bpp[0] = bpp[-1]) != 0)
1486 	--bpp;
1487 
1488     if (++nrules >= maxrules)
1489 	expand_rules();
1490     plhs[nrules] = plhs[nrules - 1];
1491     plhs[nrules - 1] = bp;
1492     rprec[nrules] = rprec[nrules - 1];
1493     rprec[nrules - 1] = 0;
1494     rassoc[nrules] = rassoc[nrules - 1];
1495     rassoc[nrules - 1] = TOKEN;
1496 }
1497 
1498 static void
1499 add_symbol(void)
1500 {
1501     int c;
1502     bucket *bp;
1503     int s_lineno = lineno;
1504 
1505     c = *cptr;
1506     if (c == '\'' || c == '"')
1507 	bp = get_literal();
1508     else
1509 	bp = get_name();
1510 
1511     c = nextc();
1512     if (c == ':')
1513     {
1514 	end_rule();
1515 	start_rule(bp, s_lineno);
1516 	++cptr;
1517 	return;
1518     }
1519 
1520     if (last_was_action)
1521 	insert_empty_rule();
1522     last_was_action = 0;
1523 
1524     if (++nitems > maxitems)
1525 	expand_items();
1526     pitem[nitems - 1] = bp;
1527 }
1528 
1529 static char *
1530 after_blanks(char *s)
1531 {
1532     while (*s != '\0' && isspace(UCH(*s)))
1533 	++s;
1534     return s;
1535 }
1536 
1537 static void
1538 copy_action(void)
1539 {
1540     int c;
1541     int i, n;
1542     int depth;
1543     int quote;
1544     char *tag;
1545     FILE *f = action_file;
1546     int a_lineno = lineno;
1547     char *a_line = dup_line();
1548     char *a_cptr = a_line + (cptr - line);
1549 
1550     if (last_was_action)
1551 	insert_empty_rule();
1552     last_was_action = 1;
1553 
1554     fprintf(f, "case %d:\n", nrules - 2);
1555     if (!lflag)
1556 	fprintf(f, line_format, lineno, input_file_name);
1557     if (*cptr == '=')
1558 	++cptr;
1559 
1560     /* avoid putting curly-braces in first column, to ease editing */
1561     if (*after_blanks(cptr) == L_CURL)
1562     {
1563 	putc('\t', f);
1564 	cptr = after_blanks(cptr);
1565     }
1566 
1567     n = 0;
1568     for (i = nitems - 1; pitem[i]; --i)
1569 	++n;
1570 
1571     depth = 0;
1572   loop:
1573     c = *cptr;
1574     if (c == '$')
1575     {
1576 	if (cptr[1] == '<')
1577 	{
1578 	    int d_lineno = lineno;
1579 	    char *d_line = dup_line();
1580 	    char *d_cptr = d_line + (cptr - line);
1581 
1582 	    ++cptr;
1583 	    tag = get_tag();
1584 	    c = *cptr;
1585 	    if (c == '$')
1586 	    {
1587 		fprintf(f, "yyval.%s", tag);
1588 		++cptr;
1589 		FREE(d_line);
1590 		goto loop;
1591 	    }
1592 	    else if (isdigit(c))
1593 	    {
1594 		i = get_number();
1595 		if (i > n)
1596 		    dollar_warning(d_lineno, i);
1597 		fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1598 		FREE(d_line);
1599 		goto loop;
1600 	    }
1601 	    else if (c == '-' && isdigit(UCH(cptr[1])))
1602 	    {
1603 		++cptr;
1604 		i = -get_number() - n;
1605 		fprintf(f, "yystack.l_mark[%d].%s", i, tag);
1606 		FREE(d_line);
1607 		goto loop;
1608 	    }
1609 	    else
1610 		dollar_error(d_lineno, d_line, d_cptr);
1611 	}
1612 	else if (cptr[1] == '$')
1613 	{
1614 	    if (ntags)
1615 	    {
1616 		tag = plhs[nrules]->tag;
1617 		if (tag == 0)
1618 		    untyped_lhs();
1619 		fprintf(f, "yyval.%s", tag);
1620 	    }
1621 	    else
1622 		fprintf(f, "yyval");
1623 	    cptr += 2;
1624 	    goto loop;
1625 	}
1626 	else if (isdigit(UCH(cptr[1])))
1627 	{
1628 	    ++cptr;
1629 	    i = get_number();
1630 	    if (ntags)
1631 	    {
1632 		if (i <= 0 || i > n)
1633 		    unknown_rhs(i);
1634 		tag = pitem[nitems + i - n - 1]->tag;
1635 		if (tag == 0)
1636 		    untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1637 		fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1638 	    }
1639 	    else
1640 	    {
1641 		if (i > n)
1642 		    dollar_warning(lineno, i);
1643 		fprintf(f, "yystack.l_mark[%d]", i - n);
1644 	    }
1645 	    goto loop;
1646 	}
1647 	else if (cptr[1] == '-')
1648 	{
1649 	    cptr += 2;
1650 	    i = get_number();
1651 	    if (ntags)
1652 		unknown_rhs(-i);
1653 	    fprintf(f, "yystack.l_mark[%d]", -i - n);
1654 	    goto loop;
1655 	}
1656     }
1657     if (isalpha(c) || c == '_' || c == '$')
1658     {
1659 	do
1660 	{
1661 	    putc(c, f);
1662 	    c = *++cptr;
1663 	}
1664 	while (isalnum(c) || c == '_' || c == '$');
1665 	goto loop;
1666     }
1667     putc(c, f);
1668     ++cptr;
1669     switch (c)
1670     {
1671     case '\n':
1672       next_line:
1673 	get_line();
1674 	if (line)
1675 	    goto loop;
1676 	unterminated_action(a_lineno, a_line, a_cptr);
1677 
1678     case ';':
1679 	if (depth > 0)
1680 	    goto loop;
1681 	fprintf(f, "\nbreak;\n");
1682 	free(a_line);
1683 	return;
1684 
1685     case L_CURL:
1686 	++depth;
1687 	goto loop;
1688 
1689     case R_CURL:
1690 	if (--depth > 0)
1691 	    goto loop;
1692 	fprintf(f, "\nbreak;\n");
1693 	free(a_line);
1694 	return;
1695 
1696     case '\'':
1697     case '"':
1698 	{
1699 	    int s_lineno = lineno;
1700 	    char *s_line = dup_line();
1701 	    char *s_cptr = s_line + (cptr - line - 1);
1702 
1703 	    quote = c;
1704 	    for (;;)
1705 	    {
1706 		c = *cptr++;
1707 		putc(c, f);
1708 		if (c == quote)
1709 		{
1710 		    FREE(s_line);
1711 		    goto loop;
1712 		}
1713 		if (c == '\n')
1714 		    unterminated_string(s_lineno, s_line, s_cptr);
1715 		if (c == '\\')
1716 		{
1717 		    c = *cptr++;
1718 		    putc(c, f);
1719 		    if (c == '\n')
1720 		    {
1721 			get_line();
1722 			if (line == 0)
1723 			    unterminated_string(s_lineno, s_line, s_cptr);
1724 		    }
1725 		}
1726 	    }
1727 	}
1728 
1729     case '/':
1730 	c = *cptr;
1731 	if (c == '/')
1732 	{
1733 	    putc('*', f);
1734 	    while ((c = *++cptr) != '\n')
1735 	    {
1736 		if (c == '*' && cptr[1] == '/')
1737 		    fprintf(f, "* ");
1738 		else
1739 		    putc(c, f);
1740 	    }
1741 	    fprintf(f, "*/\n");
1742 	    goto next_line;
1743 	}
1744 	if (c == '*')
1745 	{
1746 	    int c_lineno = lineno;
1747 	    char *c_line = dup_line();
1748 	    char *c_cptr = c_line + (cptr - line - 1);
1749 
1750 	    putc('*', f);
1751 	    ++cptr;
1752 	    for (;;)
1753 	    {
1754 		c = *cptr++;
1755 		putc(c, f);
1756 		if (c == '*' && *cptr == '/')
1757 		{
1758 		    putc('/', f);
1759 		    ++cptr;
1760 		    FREE(c_line);
1761 		    goto loop;
1762 		}
1763 		if (c == '\n')
1764 		{
1765 		    get_line();
1766 		    if (line == 0)
1767 			unterminated_comment(c_lineno, c_line, c_cptr);
1768 		}
1769 	    }
1770 	}
1771 	goto loop;
1772 
1773     default:
1774 	goto loop;
1775     }
1776 }
1777 
1778 static int
1779 mark_symbol(void)
1780 {
1781     int c;
1782     bucket *bp = NULL;
1783 
1784     c = cptr[1];
1785     if (c == '%' || c == '\\')
1786     {
1787 	cptr += 2;
1788 	return (1);
1789     }
1790 
1791     if (c == '=')
1792 	cptr += 2;
1793     else if ((c == 'p' || c == 'P') &&
1794 	     ((c = cptr[2]) == 'r' || c == 'R') &&
1795 	     ((c = cptr[3]) == 'e' || c == 'E') &&
1796 	     ((c = cptr[4]) == 'c' || c == 'C') &&
1797 	     ((c = cptr[5], !IS_IDENT(c))))
1798 	cptr += 5;
1799     else
1800 	syntax_error(lineno, line, cptr);
1801 
1802     c = nextc();
1803     if (isalpha(c) || c == '_' || c == '.' || c == '$')
1804 	bp = get_name();
1805     else if (c == '\'' || c == '"')
1806 	bp = get_literal();
1807     else
1808     {
1809 	syntax_error(lineno, line, cptr);
1810 	/*NOTREACHED */
1811     }
1812 
1813     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1814 	prec_redeclared();
1815 
1816     rprec[nrules] = bp->prec;
1817     rassoc[nrules] = bp->assoc;
1818     return (0);
1819 }
1820 
1821 static void
1822 read_grammar(void)
1823 {
1824     int c;
1825 
1826     initialize_grammar();
1827     advance_to_start();
1828 
1829     for (;;)
1830     {
1831 	c = nextc();
1832 	if (c == EOF)
1833 	    break;
1834 	if (isalpha(c)
1835 	    || c == '_'
1836 	    || c == '.'
1837 	    || c == '$'
1838 	    || c == '\''
1839 	    || c == '"')
1840 	    add_symbol();
1841 	else if (c == L_CURL || c == '=')
1842 	    copy_action();
1843 	else if (c == '|')
1844 	{
1845 	    end_rule();
1846 	    start_rule(plhs[nrules - 1], 0);
1847 	    ++cptr;
1848 	}
1849 	else if (c == '%')
1850 	{
1851 	    if (mark_symbol())
1852 		break;
1853 	}
1854 	else
1855 	    syntax_error(lineno, line, cptr);
1856     }
1857     end_rule();
1858 }
1859 
1860 static void
1861 free_tags(void)
1862 {
1863     int i;
1864 
1865     if (tag_table == 0)
1866 	return;
1867 
1868     for (i = 0; i < ntags; ++i)
1869     {
1870 	assert(tag_table[i]);
1871 	FREE(tag_table[i]);
1872     }
1873     FREE(tag_table);
1874 }
1875 
1876 static void
1877 pack_names(void)
1878 {
1879     bucket *bp;
1880     char *p, *s, *t;
1881 
1882     name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
1883     for (bp = first_symbol; bp; bp = bp->next)
1884 	name_pool_size += strlen(bp->name) + 1;
1885 
1886     name_pool = TMALLOC(char, name_pool_size);
1887     NO_SPACE(name_pool);
1888 
1889     strcpy(name_pool, "$accept");
1890     strcpy(name_pool + 8, "$end");
1891     t = name_pool + 13;
1892     for (bp = first_symbol; bp; bp = bp->next)
1893     {
1894 	p = t;
1895 	s = bp->name;
1896 	while ((*t++ = *s++) != 0)
1897 	    continue;
1898 	FREE(bp->name);
1899 	bp->name = p;
1900     }
1901 }
1902 
1903 static void
1904 check_symbols(void)
1905 {
1906     bucket *bp;
1907 
1908     if (goal->class == UNKNOWN)
1909 	undefined_goal(goal->name);
1910 
1911     for (bp = first_symbol; bp; bp = bp->next)
1912     {
1913 	if (bp->class == UNKNOWN)
1914 	{
1915 	    undefined_symbol_warning(bp->name);
1916 	    bp->class = TERM;
1917 	}
1918     }
1919 }
1920 
1921 static void
1922 protect_string(char *src, char **des)
1923 {
1924     unsigned len;
1925     char *s;
1926     char *d;
1927 
1928     *des = src;
1929     if (src)
1930     {
1931 	len = 1;
1932 	s = src;
1933 	while (*s)
1934 	{
1935 	    if ('\\' == *s || '"' == *s)
1936 		len++;
1937 	    s++;
1938 	    len++;
1939 	}
1940 
1941 	*des = d = TMALLOC(char, len);
1942 	NO_SPACE(d);
1943 
1944 	s = src;
1945 	while (*s)
1946 	{
1947 	    if ('\\' == *s || '"' == *s)
1948 		*d++ = '\\';
1949 	    *d++ = *s++;
1950 	}
1951 	*d = '\0';
1952     }
1953 }
1954 
1955 static void
1956 pack_symbols(void)
1957 {
1958     bucket *bp;
1959     bucket **v;
1960     Value_t i, j, k, n;
1961 
1962     nsyms = 2;
1963     ntokens = 1;
1964     for (bp = first_symbol; bp; bp = bp->next)
1965     {
1966 	++nsyms;
1967 	if (bp->class == TERM)
1968 	    ++ntokens;
1969     }
1970     start_symbol = (Value_t) ntokens;
1971     nvars = nsyms - ntokens;
1972 
1973     symbol_name = TMALLOC(char *, nsyms);
1974     NO_SPACE(symbol_name);
1975 
1976     symbol_value = TMALLOC(Value_t, nsyms);
1977     NO_SPACE(symbol_value);
1978 
1979     symbol_prec = TMALLOC(short, nsyms);
1980     NO_SPACE(symbol_prec);
1981 
1982     symbol_assoc = TMALLOC(char, nsyms);
1983     NO_SPACE(symbol_assoc);
1984 
1985     v = TMALLOC(bucket *, nsyms);
1986     NO_SPACE(v);
1987 
1988     v[0] = 0;
1989     v[start_symbol] = 0;
1990 
1991     i = 1;
1992     j = (Value_t) (start_symbol + 1);
1993     for (bp = first_symbol; bp; bp = bp->next)
1994     {
1995 	if (bp->class == TERM)
1996 	    v[i++] = bp;
1997 	else
1998 	    v[j++] = bp;
1999     }
2000     assert(i == ntokens && j == nsyms);
2001 
2002     for (i = 1; i < ntokens; ++i)
2003 	v[i]->index = i;
2004 
2005     goal->index = (Index_t) (start_symbol + 1);
2006     k = (Value_t) (start_symbol + 2);
2007     while (++i < nsyms)
2008 	if (v[i] != goal)
2009 	{
2010 	    v[i]->index = k;
2011 	    ++k;
2012 	}
2013 
2014     goal->value = 0;
2015     k = 1;
2016     for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2017     {
2018 	if (v[i] != goal)
2019 	{
2020 	    v[i]->value = k;
2021 	    ++k;
2022 	}
2023     }
2024 
2025     k = 0;
2026     for (i = 1; i < ntokens; ++i)
2027     {
2028 	n = v[i]->value;
2029 	if (n > 256)
2030 	{
2031 	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2032 		symbol_value[j] = symbol_value[j - 1];
2033 	    symbol_value[j] = n;
2034 	}
2035     }
2036 
2037     assert(v[1] != 0);
2038 
2039     if (v[1]->value == UNDEFINED)
2040 	v[1]->value = 256;
2041 
2042     j = 0;
2043     n = 257;
2044     for (i = 2; i < ntokens; ++i)
2045     {
2046 	if (v[i]->value == UNDEFINED)
2047 	{
2048 	    while (j < k && n == symbol_value[j])
2049 	    {
2050 		while (++j < k && n == symbol_value[j])
2051 		    continue;
2052 		++n;
2053 	    }
2054 	    v[i]->value = n;
2055 	    ++n;
2056 	}
2057     }
2058 
2059     symbol_name[0] = name_pool + 8;
2060     symbol_value[0] = 0;
2061     symbol_prec[0] = 0;
2062     symbol_assoc[0] = TOKEN;
2063     for (i = 1; i < ntokens; ++i)
2064     {
2065 	symbol_name[i] = v[i]->name;
2066 	symbol_value[i] = v[i]->value;
2067 	symbol_prec[i] = v[i]->prec;
2068 	symbol_assoc[i] = v[i]->assoc;
2069     }
2070     symbol_name[start_symbol] = name_pool;
2071     symbol_value[start_symbol] = -1;
2072     symbol_prec[start_symbol] = 0;
2073     symbol_assoc[start_symbol] = TOKEN;
2074     for (++i; i < nsyms; ++i)
2075     {
2076 	k = v[i]->index;
2077 	symbol_name[k] = v[i]->name;
2078 	symbol_value[k] = v[i]->value;
2079 	symbol_prec[k] = v[i]->prec;
2080 	symbol_assoc[k] = v[i]->assoc;
2081     }
2082 
2083     if (gflag)
2084     {
2085 	symbol_pname = TMALLOC(char *, nsyms);
2086 	NO_SPACE(symbol_pname);
2087 
2088 	for (i = 0; i < nsyms; ++i)
2089 	    protect_string(symbol_name[i], &(symbol_pname[i]));
2090     }
2091 
2092     FREE(v);
2093 }
2094 
2095 static void
2096 pack_grammar(void)
2097 {
2098     int i;
2099     Value_t j;
2100     Assoc_t assoc;
2101     Value_t prec2;
2102 
2103     ritem = TMALLOC(Value_t, nitems);
2104     NO_SPACE(ritem);
2105 
2106     rlhs = TMALLOC(Value_t, nrules);
2107     NO_SPACE(rlhs);
2108 
2109     rrhs = TMALLOC(Value_t, nrules + 1);
2110     NO_SPACE(rrhs);
2111 
2112     rprec = TREALLOC(Value_t, rprec, nrules);
2113     NO_SPACE(rprec);
2114 
2115     rassoc = TREALLOC(Assoc_t, rassoc, nrules);
2116     NO_SPACE(rassoc);
2117 
2118     ritem[0] = -1;
2119     ritem[1] = goal->index;
2120     ritem[2] = 0;
2121     ritem[3] = -2;
2122     rlhs[0] = 0;
2123     rlhs[1] = 0;
2124     rlhs[2] = start_symbol;
2125     rrhs[0] = 0;
2126     rrhs[1] = 0;
2127     rrhs[2] = 1;
2128 
2129     j = 4;
2130     for (i = 3; i < nrules; ++i)
2131     {
2132 	rlhs[i] = plhs[i]->index;
2133 	rrhs[i] = j;
2134 	assoc = TOKEN;
2135 	prec2 = 0;
2136 	while (pitem[j])
2137 	{
2138 	    ritem[j] = pitem[j]->index;
2139 	    if (pitem[j]->class == TERM)
2140 	    {
2141 		prec2 = pitem[j]->prec;
2142 		assoc = pitem[j]->assoc;
2143 	    }
2144 	    ++j;
2145 	}
2146 	ritem[j] = (Value_t) - i;
2147 	++j;
2148 	if (rprec[i] == UNDEFINED)
2149 	{
2150 	    rprec[i] = prec2;
2151 	    rassoc[i] = assoc;
2152 	}
2153     }
2154     rrhs[i] = j;
2155 
2156     FREE(plhs);
2157     FREE(pitem);
2158 }
2159 
2160 static void
2161 print_grammar(void)
2162 {
2163     int i, k;
2164     size_t j, spacing = 0;
2165     FILE *f = verbose_file;
2166 
2167     if (!vflag)
2168 	return;
2169 
2170     k = 1;
2171     for (i = 2; i < nrules; ++i)
2172     {
2173 	if (rlhs[i] != rlhs[i - 1])
2174 	{
2175 	    if (i != 2)
2176 		fprintf(f, "\n");
2177 	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
2178 	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
2179 	}
2180 	else
2181 	{
2182 	    fprintf(f, "%4d  ", i - 2);
2183 	    j = spacing;
2184 	    while (j-- != 0)
2185 		putc(' ', f);
2186 	    putc('|', f);
2187 	}
2188 
2189 	while (ritem[k] >= 0)
2190 	{
2191 	    fprintf(f, " %s", symbol_name[ritem[k]]);
2192 	    ++k;
2193 	}
2194 	++k;
2195 	putc('\n', f);
2196     }
2197 }
2198 
2199 void
2200 reader(void)
2201 {
2202     write_section(code_file, banner);
2203     create_symbol_table();
2204     read_declarations();
2205     read_grammar();
2206     free_symbol_table();
2207     free_tags();
2208     pack_names();
2209     check_symbols();
2210     pack_symbols();
2211     pack_grammar();
2212     free_symbols();
2213     print_grammar();
2214 }
2215 
2216 #ifdef NO_LEAKS
2217 static param *
2218 free_declarations(param * list)
2219 {
2220     while (list != 0)
2221     {
2222 	param *next = list->next;
2223 	free(list->type);
2224 	free(list->name);
2225 	free(list->type2);
2226 	free(list);
2227 	list = next;
2228     }
2229     return list;
2230 }
2231 
2232 void
2233 reader_leaks(void)
2234 {
2235     lex_param = free_declarations(lex_param);
2236     parse_param = free_declarations(parse_param);
2237 
2238     DO_FREE(line);
2239     DO_FREE(rrhs);
2240     DO_FREE(rlhs);
2241     DO_FREE(rprec);
2242     DO_FREE(ritem);
2243     DO_FREE(rassoc);
2244     DO_FREE(cache);
2245     DO_FREE(name_pool);
2246     DO_FREE(symbol_name);
2247     DO_FREE(symbol_prec);
2248     DO_FREE(symbol_assoc);
2249     DO_FREE(symbol_value);
2250 }
2251 #endif
2252