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