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