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