fatbase

portable OpenBSD tools
git clone git://git.2f30.org/fatbase
Log | Files | Refs

parse.y (17941B)


      1 /*	$OpenBSD: parse.y,v 1.8 2003/06/04 17:34:44 millert Exp $	*/
      2 
      3 /* parse.y - parser for flex input */
      4 
      5 %token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
      6 %token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS
      7 
      8 %token CCE_ALNUM CCE_ALPHA CCE_BLANK CCE_CNTRL CCE_DIGIT CCE_GRAPH
      9 %token CCE_LOWER CCE_PRINT CCE_PUNCT CCE_SPACE CCE_UPPER CCE_XDIGIT
     10 
     11 %{
     12 /*-
     13  * Copyright (c) 1990 The Regents of the University of California.
     14  * All rights reserved.
     15  *
     16  * This code is derived from software contributed to Berkeley by
     17  * Vern Paxson.
     18  * 
     19  * The United States Government has rights in this work pursuant
     20  * to contract no. DE-AC03-76SF00098 between the United States
     21  * Department of Energy and the University of California.
     22  *
     23  * Redistribution and use in source and binary forms, with or without
     24  * modification, are permitted provided that the following conditions
     25  * are met:
     26  *
     27  * 1. Redistributions of source code must retain the above copyright
     28  *    notice, this list of conditions and the following disclaimer.
     29  * 2. Redistributions in binary form must reproduce the above copyright
     30  *    notice, this list of conditions and the following disclaimer in the
     31  *    documentation and/or other materials provided with the distribution.
     32  *
     33  * Neither the name of the University nor the names of its contributors
     34  * may be used to endorse or promote products derived from this software
     35  * without specific prior written permission.
     36  *
     37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     38  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     39  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     40  * PURPOSE.
     41  */
     42 
     43 /* $Header: /cvs/src/usr.bin/lex/parse.y,v 1.8 2003/06/04 17:34:44 millert Exp $ */
     44 
     45 
     46 /* Some versions of bison are broken in that they use alloca() but don't
     47  * declare it properly.  The following is the patented (just kidding!)
     48  * #ifdef chud to fix the problem, courtesy of Francois Pinard.
     49  */
     50 #ifdef YYBISON
     51 /* AIX requires this to be the first thing in the file.  What a piece.  */
     52 # ifdef _AIX
     53  #pragma alloca
     54 # endif
     55 #endif
     56 
     57 #include "flexdef.h"
     58 
     59 /* The remainder of the alloca() cruft has to come after including flexdef.h,
     60  * so HAVE_ALLOCA_H is (possibly) defined.
     61  */
     62 #ifdef YYBISON
     63 # ifdef __GNUC__
     64 #  ifndef alloca
     65 #   define alloca __builtin_alloca
     66 #  endif
     67 # else
     68 #  if HAVE_ALLOCA_H
     69 #   include <alloca.h>
     70 #  else
     71 #   ifdef __hpux
     72 void *alloca ();
     73 #   else
     74 #    ifdef __TURBOC__
     75 #     include <malloc.h>
     76 #    else
     77 char *alloca ();
     78 #    endif
     79 #   endif
     80 #  endif
     81 # endif
     82 #endif
     83 
     84 /* Bletch, ^^^^ that was ugly! */
     85 
     86 
     87 int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, rulelen;
     88 int trlcontxt, xcluflg, currccl, cclsorted, varlength, variable_trail_rule;
     89 
     90 int *scon_stk;
     91 int scon_stk_ptr;
     92 
     93 static int madeany = false;  /* whether we've made the '.' character class */
     94 int previous_continued_action;	/* whether the previous rule's action was '|' */
     95 
     96 /* Expand a POSIX character class expression. */
     97 #define CCL_EXPR(func) \
     98 	{ \
     99 	int c; \
    100 	for ( c = 0; c < csize; ++c ) \
    101 		if ( isascii(c) && func(c) ) \
    102 			ccladd( currccl, c ); \
    103 	}
    104 
    105 /* While POSIX defines isblank(), it's not ANSI C. */
    106 #define IS_BLANK(c) ((c) == ' ' || (c) == '\t')
    107 
    108 /* On some over-ambitious machines, such as DEC Alpha's, the default
    109  * token type is "long" instead of "int"; this leads to problems with
    110  * declaring yylval in flexdef.h.  But so far, all the yacc's I've seen
    111  * wrap their definitions of YYSTYPE with "#ifndef YYSTYPE"'s, so the
    112  * following should ensure that the default token type is "int".
    113  */
    114 #define YYSTYPE int
    115 
    116 %}
    117 
    118 %%
    119 goal		:  initlex sect1 sect1end sect2 initforrule
    120 			{ /* add default rule */
    121 			int def_rule;
    122 
    123 			pat = cclinit();
    124 			cclnegate( pat );
    125 
    126 			def_rule = mkstate( -pat );
    127 
    128 			/* Remember the number of the default rule so we
    129 			 * don't generate "can't match" warnings for it.
    130 			 */
    131 			default_rule = num_rules;
    132 
    133 			finish_rule( def_rule, false, 0, 0 );
    134 
    135 			for ( i = 1; i <= lastsc; ++i )
    136 				scset[i] = mkbranch( scset[i], def_rule );
    137 
    138 			if ( spprdflt )
    139 				add_action(
    140 				"YY_FATAL_ERROR( \"flex scanner jammed\" )" );
    141 			else
    142 				add_action( "ECHO" );
    143 
    144 			add_action( ";\n\tYY_BREAK\n" );
    145 			}
    146 		;
    147 
    148 initlex		:
    149 			{ /* initialize for processing rules */
    150 
    151 			/* Create default DFA start condition. */
    152 			scinstal( "INITIAL", false );
    153 			}
    154 		;
    155 
    156 sect1		:  sect1 startconddecl namelist1
    157 		|  sect1 options
    158 		|
    159 		|  error
    160 			{ synerr( "unknown error processing section 1" ); }
    161 		;
    162 
    163 sect1end	:  SECTEND
    164 			{
    165 			check_options();
    166 			scon_stk = allocate_integer_array( lastsc + 1 );
    167 			scon_stk_ptr = 0;
    168 			}
    169 		;
    170 
    171 startconddecl	:  SCDECL
    172 			{ xcluflg = false; }
    173 
    174 		|  XSCDECL
    175 			{ xcluflg = true; }
    176 		;
    177 
    178 namelist1	:  namelist1 NAME
    179 			{ scinstal( nmstr, xcluflg ); }
    180 
    181 		|  NAME
    182 			{ scinstal( nmstr, xcluflg ); }
    183 
    184 		|  error
    185 			{ synerr( "bad start condition list" ); }
    186 		;
    187 
    188 options		:  OPTION_OP optionlist
    189 		;
    190 
    191 optionlist	:  optionlist option
    192 		|
    193 		;
    194 
    195 option		:  OPT_OUTFILE '=' NAME
    196 			{
    197 			outfilename = copy_string( nmstr );
    198 			did_outfilename = 1;
    199 			}
    200 		|  OPT_PREFIX '=' NAME
    201 			{ prefix = copy_string( nmstr ); }
    202 		|  OPT_YYCLASS '=' NAME
    203 			{ yyclass = copy_string( nmstr ); }
    204 		;
    205 
    206 sect2		:  sect2 scon initforrule flexrule '\n'
    207 			{ scon_stk_ptr = $2; }
    208 		|  sect2 scon '{' sect2 '}'
    209 			{ scon_stk_ptr = $2; }
    210 		|
    211 		;
    212 
    213 initforrule	:
    214 			{
    215 			/* Initialize for a parse of one rule. */
    216 			trlcontxt = variable_trail_rule = varlength = false;
    217 			trailcnt = headcnt = rulelen = 0;
    218 			current_state_type = STATE_NORMAL;
    219 			previous_continued_action = continued_action;
    220 			in_rule = true;
    221 
    222 			new_rule();
    223 			}
    224 		;
    225 
    226 flexrule	:  '^' rule
    227 			{
    228 			pat = $2;
    229 			finish_rule( pat, variable_trail_rule,
    230 				headcnt, trailcnt );
    231 
    232 			if ( scon_stk_ptr > 0 )
    233 				{
    234 				for ( i = 1; i <= scon_stk_ptr; ++i )
    235 					scbol[scon_stk[i]] =
    236 						mkbranch( scbol[scon_stk[i]],
    237 								pat );
    238 				}
    239 
    240 			else
    241 				{
    242 				/* Add to all non-exclusive start conditions,
    243 				 * including the default (0) start condition.
    244 				 */
    245 
    246 				for ( i = 1; i <= lastsc; ++i )
    247 					if ( ! scxclu[i] )
    248 						scbol[i] = mkbranch( scbol[i],
    249 									pat );
    250 				}
    251 
    252 			if ( ! bol_needed )
    253 				{
    254 				bol_needed = true;
    255 
    256 				if ( performance_report > 1 )
    257 					pinpoint_message(
    258 			"'^' operator results in sub-optimal performance" );
    259 				}
    260 			}
    261 
    262 		|  rule
    263 			{
    264 			pat = $1;
    265 			finish_rule( pat, variable_trail_rule,
    266 				headcnt, trailcnt );
    267 
    268 			if ( scon_stk_ptr > 0 )
    269 				{
    270 				for ( i = 1; i <= scon_stk_ptr; ++i )
    271 					scset[scon_stk[i]] =
    272 						mkbranch( scset[scon_stk[i]],
    273 								pat );
    274 				}
    275 
    276 			else
    277 				{
    278 				for ( i = 1; i <= lastsc; ++i )
    279 					if ( ! scxclu[i] )
    280 						scset[i] =
    281 							mkbranch( scset[i],
    282 								pat );
    283 				}
    284 			}
    285 
    286 		|  EOF_OP
    287 			{
    288 			if ( scon_stk_ptr > 0 )
    289 				build_eof_action();
    290 	
    291 			else
    292 				{
    293 				/* This EOF applies to all start conditions
    294 				 * which don't already have EOF actions.
    295 				 */
    296 				for ( i = 1; i <= lastsc; ++i )
    297 					if ( ! sceof[i] )
    298 						scon_stk[++scon_stk_ptr] = i;
    299 
    300 				if ( scon_stk_ptr == 0 )
    301 					warn(
    302 			"all start conditions already have <<EOF>> rules" );
    303 
    304 				else
    305 					build_eof_action();
    306 				}
    307 			}
    308 
    309 		|  error
    310 			{ synerr( "unrecognized rule" ); }
    311 		;
    312 
    313 scon_stk_ptr	:
    314 			{ $$ = scon_stk_ptr; }
    315 		;
    316 
    317 scon		:  '<' scon_stk_ptr namelist2 '>'
    318 			{ $$ = $2; }
    319 
    320 		|  '<' '*' '>'
    321 			{
    322 			$$ = scon_stk_ptr;
    323 
    324 			for ( i = 1; i <= lastsc; ++i )
    325 				{
    326 				int j;
    327 
    328 				for ( j = 1; j <= scon_stk_ptr; ++j )
    329 					if ( scon_stk[j] == i )
    330 						break;
    331 
    332 				if ( j > scon_stk_ptr )
    333 					scon_stk[++scon_stk_ptr] = i;
    334 				}
    335 			}
    336 
    337 		|
    338 			{ $$ = scon_stk_ptr; }
    339 		;
    340 
    341 namelist2	:  namelist2 ',' sconname
    342 
    343 		|  sconname
    344 
    345 		|  error
    346 			{ synerr( "bad start condition list" ); }
    347 		;
    348 
    349 sconname	:  NAME
    350 			{
    351 			if ( (scnum = sclookup( nmstr )) == 0 )
    352 				format_pinpoint_message(
    353 					"undeclared start condition %s",
    354 					nmstr );
    355 			else
    356 				{
    357 				for ( i = 1; i <= scon_stk_ptr; ++i )
    358 					if ( scon_stk[i] == scnum )
    359 						{
    360 						format_warn(
    361 							"<%s> specified twice",
    362 							scname[scnum] );
    363 						break;
    364 						}
    365 
    366 				if ( i > scon_stk_ptr )
    367 					scon_stk[++scon_stk_ptr] = scnum;
    368 				}
    369 			}
    370 		;
    371 
    372 rule		:  re2 re
    373 			{
    374 			if ( transchar[lastst[$2]] != SYM_EPSILON )
    375 				/* Provide final transition \now/ so it
    376 				 * will be marked as a trailing context
    377 				 * state.
    378 				 */
    379 				$2 = link_machines( $2,
    380 						mkstate( SYM_EPSILON ) );
    381 
    382 			mark_beginning_as_normal( $2 );
    383 			current_state_type = STATE_NORMAL;
    384 
    385 			if ( previous_continued_action )
    386 				{
    387 				/* We need to treat this as variable trailing
    388 				 * context so that the backup does not happen
    389 				 * in the action but before the action switch
    390 				 * statement.  If the backup happens in the
    391 				 * action, then the rules "falling into" this
    392 				 * one's action will *also* do the backup,
    393 				 * erroneously.
    394 				 */
    395 				if ( ! varlength || headcnt != 0 )
    396 					warn(
    397 		"trailing context made variable due to preceding '|' action" );
    398 
    399 				/* Mark as variable. */
    400 				varlength = true;
    401 				headcnt = 0;
    402 				}
    403 
    404 			if ( lex_compat || (varlength && headcnt == 0) )
    405 				{ /* variable trailing context rule */
    406 				/* Mark the first part of the rule as the
    407 				 * accepting "head" part of a trailing
    408 				 * context rule.
    409 				 *
    410 				 * By the way, we didn't do this at the
    411 				 * beginning of this production because back
    412 				 * then current_state_type was set up for a
    413 				 * trail rule, and add_accept() can create
    414 				 * a new state ...
    415 				 */
    416 				add_accept( $1,
    417 					num_rules | YY_TRAILING_HEAD_MASK );
    418 				variable_trail_rule = true;
    419 				}
    420 			
    421 			else
    422 				trailcnt = rulelen;
    423 
    424 			$$ = link_machines( $1, $2 );
    425 			}
    426 
    427 		|  re2 re '$'
    428 			{ synerr( "trailing context used twice" ); }
    429 
    430 		|  re '$'
    431 			{
    432 			headcnt = 0;
    433 			trailcnt = 1;
    434 			rulelen = 1;
    435 			varlength = false;
    436 
    437 			current_state_type = STATE_TRAILING_CONTEXT;
    438 
    439 			if ( trlcontxt )
    440 				{
    441 				synerr( "trailing context used twice" );
    442 				$$ = mkstate( SYM_EPSILON );
    443 				}
    444 
    445 			else if ( previous_continued_action )
    446 				{
    447 				/* See the comment in the rule for "re2 re"
    448 				 * above.
    449 				 */
    450 				warn(
    451 		"trailing context made variable due to preceding '|' action" );
    452 
    453 				varlength = true;
    454 				}
    455 
    456 			if ( lex_compat || varlength )
    457 				{
    458 				/* Again, see the comment in the rule for
    459 				 * "re2 re" above.
    460 				 */
    461 				add_accept( $1,
    462 					num_rules | YY_TRAILING_HEAD_MASK );
    463 				variable_trail_rule = true;
    464 				}
    465 
    466 			trlcontxt = true;
    467 
    468 			eps = mkstate( SYM_EPSILON );
    469 			$$ = link_machines( $1,
    470 				link_machines( eps, mkstate( '\n' ) ) );
    471 			}
    472 
    473 		|  re
    474 			{
    475 			$$ = $1;
    476 
    477 			if ( trlcontxt )
    478 				{
    479 				if ( lex_compat || (varlength && headcnt == 0) )
    480 					/* Both head and trail are
    481 					 * variable-length.
    482 					 */
    483 					variable_trail_rule = true;
    484 				else
    485 					trailcnt = rulelen;
    486 				}
    487 			}
    488 		;
    489 
    490 
    491 re		:  re '|' series
    492 			{
    493 			varlength = true;
    494 			$$ = mkor( $1, $3 );
    495 			}
    496 
    497 		|  series
    498 			{ $$ = $1; }
    499 		;
    500 
    501 
    502 re2		:  re '/'
    503 			{
    504 			/* This rule is written separately so the
    505 			 * reduction will occur before the trailing
    506 			 * series is parsed.
    507 			 */
    508 
    509 			if ( trlcontxt )
    510 				synerr( "trailing context used twice" );
    511 			else
    512 				trlcontxt = true;
    513 
    514 			if ( varlength )
    515 				/* We hope the trailing context is
    516 				 * fixed-length.
    517 				 */
    518 				varlength = false;
    519 			else
    520 				headcnt = rulelen;
    521 
    522 			rulelen = 0;
    523 
    524 			current_state_type = STATE_TRAILING_CONTEXT;
    525 			$$ = $1;
    526 			}
    527 		;
    528 
    529 series		:  series singleton
    530 			{
    531 			/* This is where concatenation of adjacent patterns
    532 			 * gets done.
    533 			 */
    534 			$$ = link_machines( $1, $2 );
    535 			}
    536 
    537 		|  singleton
    538 			{ $$ = $1; }
    539 		;
    540 
    541 singleton	:  singleton '*'
    542 			{
    543 			varlength = true;
    544 
    545 			$$ = mkclos( $1 );
    546 			}
    547 
    548 		|  singleton '+'
    549 			{
    550 			varlength = true;
    551 			$$ = mkposcl( $1 );
    552 			}
    553 
    554 		|  singleton '?'
    555 			{
    556 			varlength = true;
    557 			$$ = mkopt( $1 );
    558 			}
    559 
    560 		|  singleton '{' NUMBER ',' NUMBER '}'
    561 			{
    562 			varlength = true;
    563 
    564 			if ( $3 > $5 || $3 < 0 )
    565 				{
    566 				synerr( "bad iteration values" );
    567 				$$ = $1;
    568 				}
    569 			else
    570 				{
    571 				if ( $3 == 0 )
    572 					{
    573 					if ( $5 <= 0 )
    574 						{
    575 						synerr(
    576 						"bad iteration values" );
    577 						$$ = $1;
    578 						}
    579 					else
    580 						$$ = mkopt(
    581 							mkrep( $1, 1, $5 ) );
    582 					}
    583 				else
    584 					$$ = mkrep( $1, $3, $5 );
    585 				}
    586 			}
    587 
    588 		|  singleton '{' NUMBER ',' '}'
    589 			{
    590 			varlength = true;
    591 
    592 			if ( $3 <= 0 )
    593 				{
    594 				synerr( "iteration value must be positive" );
    595 				$$ = $1;
    596 				}
    597 
    598 			else
    599 				$$ = mkrep( $1, $3, INFINITY );
    600 			}
    601 
    602 		|  singleton '{' NUMBER '}'
    603 			{
    604 			/* The singleton could be something like "(foo)",
    605 			 * in which case we have no idea what its length
    606 			 * is, so we punt here.
    607 			 */
    608 			varlength = true;
    609 
    610 			if ( $3 <= 0 )
    611 				{
    612 				synerr( "iteration value must be positive" );
    613 				$$ = $1;
    614 				}
    615 
    616 			else
    617 				$$ = link_machines( $1,
    618 						copysingl( $1, $3 - 1 ) );
    619 			}
    620 
    621 		|  '.'
    622 			{
    623 			if ( ! madeany )
    624 				{
    625 				/* Create the '.' character class. */
    626 				anyccl = cclinit();
    627 				ccladd( anyccl, '\n' );
    628 				cclnegate( anyccl );
    629 
    630 				if ( useecs )
    631 					mkeccl( ccltbl + cclmap[anyccl],
    632 						ccllen[anyccl], nextecm,
    633 						ecgroup, csize, csize );
    634 
    635 				madeany = true;
    636 				}
    637 
    638 			++rulelen;
    639 
    640 			$$ = mkstate( -anyccl );
    641 			}
    642 
    643 		|  fullccl
    644 			{
    645 			if ( ! cclsorted )
    646 				/* Sort characters for fast searching.  We
    647 				 * use a shell sort since this list could
    648 				 * be large.
    649 				 */
    650 				cshell( ccltbl + cclmap[$1], ccllen[$1], true );
    651 
    652 			if ( useecs )
    653 				mkeccl( ccltbl + cclmap[$1], ccllen[$1],
    654 					nextecm, ecgroup, csize, csize );
    655 
    656 			++rulelen;
    657 
    658 			$$ = mkstate( -$1 );
    659 			}
    660 
    661 		|  PREVCCL
    662 			{
    663 			++rulelen;
    664 
    665 			$$ = mkstate( -$1 );
    666 			}
    667 
    668 		|  '"' string '"'
    669 			{ $$ = $2; }
    670 
    671 		|  '(' re ')'
    672 			{ $$ = $2; }
    673 
    674 		|  CHAR
    675 			{
    676 			++rulelen;
    677 
    678 			if ( caseins && $1 >= 'A' && $1 <= 'Z' )
    679 				$1 = clower( $1 );
    680 
    681 			$$ = mkstate( $1 );
    682 			}
    683 		;
    684 
    685 fullccl		:  '[' ccl ']'
    686 			{ $$ = $2; }
    687 
    688 		|  '[' '^' ccl ']'
    689 			{
    690 			cclnegate( $3 );
    691 			$$ = $3;
    692 			}
    693 		;
    694 
    695 ccl		:  ccl CHAR '-' CHAR
    696 			{
    697 			if ( caseins )
    698 				{
    699 				if ( $2 >= 'A' && $2 <= 'Z' )
    700 					$2 = clower( $2 );
    701 				if ( $4 >= 'A' && $4 <= 'Z' )
    702 					$4 = clower( $4 );
    703 				}
    704 
    705 			if ( $2 > $4 )
    706 				synerr( "negative range in character class" );
    707 
    708 			else
    709 				{
    710 				for ( i = $2; i <= $4; ++i )
    711 					ccladd( $1, i );
    712 
    713 				/* Keep track if this ccl is staying in
    714 				 * alphabetical order.
    715 				 */
    716 				cclsorted = cclsorted && ($2 > lastchar);
    717 				lastchar = $4;
    718 				}
    719 
    720 			$$ = $1;
    721 			}
    722 
    723 		|  ccl CHAR
    724 			{
    725 			if ( caseins && $2 >= 'A' && $2 <= 'Z' )
    726 				$2 = clower( $2 );
    727 
    728 			ccladd( $1, $2 );
    729 			cclsorted = cclsorted && ($2 > lastchar);
    730 			lastchar = $2;
    731 			$$ = $1;
    732 			}
    733 
    734 		|  ccl ccl_expr
    735 			{
    736 			/* Too hard to properly maintain cclsorted. */
    737 			cclsorted = false;
    738 			$$ = $1;
    739 			}
    740 
    741 		|
    742 			{
    743 			cclsorted = true;
    744 			lastchar = 0;
    745 			currccl = $$ = cclinit();
    746 			}
    747 		;
    748 
    749 ccl_expr:	   CCE_ALNUM	{ CCL_EXPR(isalnum) }
    750 		|  CCE_ALPHA	{ CCL_EXPR(isalpha) }
    751 		|  CCE_BLANK	{ CCL_EXPR(IS_BLANK) }
    752 		|  CCE_CNTRL	{ CCL_EXPR(iscntrl) }
    753 		|  CCE_DIGIT	{ CCL_EXPR(isdigit) }
    754 		|  CCE_GRAPH	{ CCL_EXPR(isgraph) }
    755 		|  CCE_LOWER	{ CCL_EXPR(islower) }
    756 		|  CCE_PRINT	{ CCL_EXPR(isprint) }
    757 		|  CCE_PUNCT	{ CCL_EXPR(ispunct) }
    758 		|  CCE_SPACE	{ CCL_EXPR(isspace) }
    759 		|  CCE_UPPER	{
    760 				if ( caseins )
    761 					CCL_EXPR(islower)
    762 				else
    763 					CCL_EXPR(isupper)
    764 				}
    765 		|  CCE_XDIGIT	{ CCL_EXPR(isxdigit) }
    766 		;
    767 		
    768 string		:  string CHAR
    769 			{
    770 			if ( caseins && $2 >= 'A' && $2 <= 'Z' )
    771 				$2 = clower( $2 );
    772 
    773 			++rulelen;
    774 
    775 			$$ = link_machines( $1, mkstate( $2 ) );
    776 			}
    777 
    778 		|
    779 			{ $$ = mkstate( SYM_EPSILON ); }
    780 		;
    781 
    782 %%
    783 
    784 
    785 /* build_eof_action - build the "<<EOF>>" action for the active start
    786  *                    conditions
    787  */
    788 
    789 void build_eof_action()
    790 	{
    791 	register int i;
    792 	char action_text[MAXLINE];
    793 
    794 	for ( i = 1; i <= scon_stk_ptr; ++i )
    795 		{
    796 		if ( sceof[scon_stk[i]] )
    797 			format_pinpoint_message(
    798 				"multiple <<EOF>> rules for start condition %s",
    799 				scname[scon_stk[i]] );
    800 
    801 		else
    802 			{
    803 			sceof[scon_stk[i]] = true;
    804 			snprintf( action_text, sizeof action_text,
    805 				"case YY_STATE_EOF(%s):\n",
    806 				scname[scon_stk[i]] );
    807 			add_action( action_text );
    808 			}
    809 		}
    810 
    811 	line_directive_out( (FILE *) 0, 1 );
    812 
    813 	/* This isn't a normal rule after all - don't count it as
    814 	 * such, so we don't have any holes in the rule numbering
    815 	 * (which make generating "rule can never match" warnings
    816 	 * more difficult.
    817 	 */
    818 	--num_rules;
    819 	++num_eof_rules;
    820 	}
    821 
    822 
    823 /* format_synerr - write out formatted syntax error */
    824 
    825 void format_synerr( msg, arg )
    826 char msg[], arg[];
    827 	{
    828 	char errmsg[MAXLINE];
    829 
    830 	(void) snprintf( errmsg, sizeof errmsg, msg, arg );
    831 	synerr( errmsg );
    832 	}
    833 
    834 
    835 /* synerr - report a syntax error */
    836 
    837 void synerr( str )
    838 char str[];
    839 	{
    840 	syntaxerror = true;
    841 	pinpoint_message( str );
    842 	}
    843 
    844 
    845 /* format_warn - write out formatted warning */
    846 
    847 void format_warn( msg, arg )
    848 char msg[], arg[];
    849 	{
    850 	char warn_msg[MAXLINE];
    851 
    852 	(void) snprintf( warn_msg, sizeof warn_msg, msg, arg );
    853 	warn( warn_msg );
    854 	}
    855 
    856 
    857 /* warn - report a warning, unless -w was given */
    858 
    859 void warn( str )
    860 char str[];
    861 	{
    862 	line_warning( str, linenum );
    863 	}
    864 
    865 /* format_pinpoint_message - write out a message formatted with one string,
    866  *			     pinpointing its location
    867  */
    868 
    869 void format_pinpoint_message( msg, arg )
    870 char msg[], arg[];
    871 	{
    872 	char errmsg[MAXLINE];
    873 
    874 	(void) snprintf( errmsg, sizeof errmsg, msg, arg );
    875 	pinpoint_message( errmsg );
    876 	}
    877 
    878 
    879 /* pinpoint_message - write out a message, pinpointing its location */
    880 
    881 void pinpoint_message( str )
    882 char str[];
    883 	{
    884 	line_pinpoint( str, linenum );
    885 	}
    886 
    887 
    888 /* line_warning - report a warning at a given line, unless -w was given */
    889 
    890 void line_warning( str, line )
    891 char str[];
    892 int line;
    893 	{
    894 	char warning[MAXLINE];
    895 
    896 	if ( ! nowarn )
    897 		{
    898 		snprintf( warning, sizeof warning, "warning, %s", str );
    899 		line_pinpoint( warning, line );
    900 		}
    901 	}
    902 
    903 
    904 /* line_pinpoint - write out a message, pinpointing it at the given line */
    905 
    906 void line_pinpoint( str, line )
    907 char str[];
    908 int line;
    909 	{
    910 	fprintf( stderr, "\"%s\", line %d: %s\n", infilename, line, str );
    911 	}
    912 
    913 
    914 /* yyerror - eat up an error message from the parser;
    915  *	     currently, messages are ignore
    916  */
    917 
    918 void yyerror( msg )
    919 char msg[];
    920 	{
    921 	}