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