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