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