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