⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gen.c

📁 SRI international 发布的OAA框架软件
💻 C
📖 第 1 页 / 共 5 页
字号:
{
	int max_k;

	/* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead
	 * from CLL_k..LL_k
	 */
	{
		int limit;
		if ( j->ftree!=NULL ) limit = LL_k;
		else limit = CLL_k;
		max_k = genExprSets(j->fset, limit);
	}

	/* Do tests for real tuples from other productions that conflict with
	 * artificial tuples generated by compression (using sets of tokens
	 * rather than k-trees).
	 */
	if ( j->ftree != NULL )
	{
		_gen(" && !("); genExprTree(j->ftree, 1); _gen(")");
	}

	if ( ParseWithPredicates && j->predicate!=NULL )
	{
		Predicate *p = j->predicate;
		warn_about_using_gk_option();
		_gen("&&");
		j->predicate=genPredTreeMain(p, (Node *)j);     /* MR10 */
	}

	return max_k;
}

static int
#ifdef __USE_PROTOS
genExprSets( set *fset, int limit )
#else
genExprSets( fset, limit )
set *fset;
int limit;
#endif
{
	int k = 1;
	int max_k = 0;
	unsigned *e, *g, firstTime=1;

    if (set_nil(fset[1])) {
      _gen(" 0 /* MR13 empty set expression  - undefined rule ? infinite left recursion ? */ ");
      MR_BadExprSets++;
    };

	if ( GenExprSetsOpt )
	{
		while ( k <= limit && !set_nil(fset[k]) )   /* MR11 */
		{
			if ( set_deg(fset[k])==1 )	/* too simple for a set? */
			{
				int e;
				_gen1("(LA(%d)==",k);
				e = set_int(fset[k]);
				if ( TokenString(e) == NULL ) _gen1("%d)", e)
				else _gen1("%s)", TokenString(e));
			}
			else
			{
				NewSet();
				FillSet( fset[k] );
				_gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<<setnum);
			}
			if ( k>max_k ) max_k = k;
			if ( k == CLL_k ) break;
			k++;
			if ( k<=limit && !set_nil(fset[k]) ) _gen(" && ");  /* MR11 */
			on1line++;
			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
		}
		return max_k;
	}

	while ( k<= limit &&  !set_nil(fset[k]) )       /* MR11 */
	{
		if ( (e=g=set_pdq(fset[k])) == NULL ) fatal_internal("genExpr: cannot allocate IF expr pdq set");
		for (; *e!=nil; e++)
		{
			if ( !firstTime ) _gen(" || ") else { _gen("("); firstTime = 0; }
			on1line++;
			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
			_gen1("LA(%d)==",k);
			if ( TokenString(*e) == NULL ) _gen1("%d", *e)
			else _gen1("%s", TokenString(*e));
		}
		free( (char *)g );
		_gen(")");
		if ( k>max_k ) max_k = k;
		if ( k == CLL_k ) break;
		k++;
		if ( k <= limit && !set_nil(fset[k]) ) { firstTime=1; _gen(" && "); }   /* MR11 */
		on1line++;
		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
	}
	return max_k;
}

/*
 * Generate code for any type of block.  If the last alternative in the block is
 * empty (not even an action) don't bother doing it.  This permits us to handle
 * optional and loop blocks as well.
 *
 * Only do this block, return after completing the block.
 * This routine is visible only to this file and cannot answer a TRANS message.
 */
static set
#ifdef __USE_PROTOS
genBlk( Junction *q, int jtype, int *max_k, int *need_right_curly, int * lastAltEmpty /* MR23 */)
#else
genBlk( q, jtype, max_k, need_right_curly, lastAltEmpty /* MR23 */)
Junction *q;
int jtype;
int *max_k;
int *need_right_curly;
int *lastAltEmpty; /* MR23 */
#endif
{
	set f;
	Junction *alt;
	int a_guess_in_block = 0;
	require(q!=NULL,				"genBlk: invalid node");
	require(q->ntype == nJunction,	"genBlk: not junction");
	*need_right_curly=0;
	*lastAltEmpty = 0;		/* MR23 */
	if ( q->p2 == NULL )	/* only one alternative?  Then don't need if */
	{	
		if (first_item_is_guess_block((Junction *)q->p1)!=NULL )
		{
            if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) {
  			  warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line);
            };
   	   	    gen("zzGUESS\n");	/* guess anyway to make output code consistent */
/* MR10 disable */  /**** gen("if ( !zzrv )\n"); ****/
/* MR10 */          gen("if ( !zzrv ) {\n"); tabs++; (*need_right_curly)++;
        };
		TRANS(q->p1);
		return empty;		/* no decision to be made-->no error set */
	}

	f = First(q, 1, jtype, max_k);
	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
	{
		if ( alt->p2 == NULL )					/* chk for empty alt */
		{	
			Node *p = alt->p1;
			if ( p->ntype == nJunction )
			{
				/* we have empty alt */
/* MR23
   There is a conflict between giving good error information for non-exceptions
   and making life easy for those using parser exception handling.  Consider:

         r: { A } b;
		 b: B;
		 
		   with input "C"

   Before MR21 the error message would be "expecting B - found C".  After MR21
   the error message would be "expcect A, B - found C".  This was good, but it
   caused problems for those using parser exceptions because the reference to
   B was generated inside the {...} where B really wasn't part of the block.

   In MR23 this has been changed for the case where exceptions are in use to
   not generate the extra check in the tail of the {A} block.
*/


/* MR23 */	if (isEmptyAlt( ((Junction *)p)->p1, (Node *)q->end)) {
/* MR23 */      *lastAltEmpty = 1;
/* MR23 */		if (FoundException) {
/* MR23 */			/* code to restore state if a prev alt didn't follow guess */
/* MR23 */			if ( a_guess_in_block && jtype != aPlusBlk) {
/* MR23 */				gen("if ( !zzrv ) zzGUESS_DONE; /* MR28 */\n");
/* MR23 */			}
/* MR23 */			break;
/* MR23 */		};
/* MR28 */      if (jtype == aPlusBlk) {
/* MR28 */          break;
/* MR28 */      }
/* MR23 */	}
		}
	} /* end of for loop on alt */

/* MR10 */        if (alt->p2 == NULL &&
/* MR10 */               ( q->jtype == aSubBlk || q->jtype == RuleBlk) ) {
/* MR10 */          if (first_item_is_guess_block(alt)) {
/* MR10 */               warnFL("(...)? as last alternative of block is unnecessary",
/* MR10 */                                FileStr[alt->file],alt->line);
/* MR10 */          };
/* MR10 */        };

		if ( alt != q ) gen("else ")
		else
		{
			if ( DemandLookahead ) {
				if ( !GenCC ) {gen1("LOOK(%d);\n", *max_k);}
				else gen1("look(%d);\n", *max_k);
			}
		}

		if ( alt!=q )
		{
			_gen("{\n");
			tabs++;
			(*need_right_curly)++;
			/* code to restore state if a prev alt didn't follow guess */
			if ( a_guess_in_block )
				gen("if ( !zzrv ) zzGUESS_DONE;\n");
		}
		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL )
		{
			a_guess_in_block = 1;
			gen("zzGUESS\n");
		}
		gen("if ( ");
		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) _gen("!zzrv && ");
		genExpr(alt);
		_gen(" ) ");
		_gen("{\n");
		tabs++;
		TRANS(alt->p1);
		--tabs;
		gen("}\n");
/* MR10 */        if (alt->p2 == NULL) {
/* MR10 */          if (first_item_is_guess_block(alt)) {
/* MR10 */            gen("/* MR10 */ else {\n");
/* MR10 */            tabs++;
/* MR10 */  		  (*need_right_curly)++;
/* MR10 */  		  /* code to restore state if a prev alt didn't follow guess */
/* MR10 */            gen("/* MR10 */ if ( !zzrv ) zzGUESS_DONE;\n");
/* MR10 */            gen("/* MR10 */ if (0) {}     /* last alternative of block is guess block */\n");
/* MR10 */          };
/* MR10 */        };
	}
	return f;
}

static int
#ifdef __USE_PROTOS
has_guess_block_as_first_item( Junction *q )
#else
has_guess_block_as_first_item( q )
Junction *q;
#endif
{
	Junction *alt;

	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
	{
		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) return 1;
	}
	return 0;
}

static int
#ifdef __USE_PROTOS
has_guess_block_as_last_item( Junction *q )
#else
has_guess_block_as_last_item( q )
Junction *q;
#endif
{
	Junction *alt;

    if (q == NULL) return 0;
	for (alt=q; alt->p2 != NULL && !( (Junction *) alt->p2)->ignore; alt= (Junction *) alt->p2 ) {};
    return first_item_is_guess_block( (Junction *) alt->p1) != NULL;
}

/* MR30 See description of first_item_is_guess_block for background */

Junction *
#ifdef __USE_PROTOS
first_item_is_guess_block_extra(Junction *q )
#else
first_item_is_guess_block_extra(q)
Junction *q;
#endif
{
	while ( q!=NULL &&
            (  ( q->ntype==nAction ) ||
               ( q->ntype==nJunction &&
                    (q->jtype==Generic || q->jtype == aLoopBlk) 
               )
            )
          )
	{
		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
		else q = (Junction *) ((ActionNode *)q)->next;
	}

	if ( q==NULL ) return NULL;
	if ( q->ntype!=nJunction ) return NULL;
	if ( q->jtype!=aSubBlk ) return NULL;
	if ( !q->guess ) return NULL;

	return q;
}

/* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node
 * of (...)?;  This function ignores actions and predicates.
 */

Junction *
#ifdef __USE_PROTOS
first_item_is_guess_block( Junction *q )
#else
first_item_is_guess_block( q )
Junction *q;
#endif
{
	Junction * qOriginal = q;	/* DEBUG */

    /* MR14  Couldn't find aSubBlock which was a guess block when it lay
             behind aLoopBlk.  The aLoopBlk only appear in conjunction with
             aLoopBegin, but the routine didn't know that.  I think.

       MR14a Added extra parentheses to clarify precedence

	   MR30  This appears to have been a mistake.  The First set was then
	         computed incorrectly for:

					r : ( (A)? B
					    | C
						)*
			 
			 The routine analysis_point was seeing the guess block when
			 it was still analyzing the loopBegin block.  As a consequence,
			 when it looked for the analysis_point it was processing the B, but
			 skipping over the C alternative altogether because it thought
			 it was looking at a guess block, not realizing there was a loop
			 block in front of the loopBegin.

             loopBegin  loopBlk  subBlk/guess  A  G  EB  G  B EB EB  EB  ER
			    |          |          |                     ^   ^
				|		   |                                |   |
                |          +-> G  C G ----------------------+   |
                |                                               |
				+--- G G G -------------------------------------+
    
			 Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu).

		MR30  This is still more complicated.  This fix caused ambiguity messages
		to be reported for "( (A B)? )* A B" but not for "( (A B)? )+".  Why is
		there a difference when these are outwardly identical ?  It is because the
		start of a (...)* block is represented by two nodes: a loopBegin block
		followed by a loopBlock whereas the start of a (...)+ block is
		represented as a single node: a plusBlock.  So if first_item_is_guess_block
		is called when the current node is a loopBegin it starts with the
		loop block rather than the the sub block which follows the loop block.
		However, we can't just skip past the loop block because some routines
		depend on the old implementation.  So, we provide a new implementation
		which does skip the loopBlock.  However, which should be called when ?
		I'm not sure, but my guess is that first_item_is_guess_block_extra (the
		new one) should only be called for the ambiguity routines.

    */

	while ( q!=NULL &&
            (  ( q->ntype==nAction ) ||
               ( q->ntype==nJunction &&
                    (q->jtype==Generic /*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/
               )
            )
          )
	{
		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
		else q = (Junction *) ((ActionNode *)q)->next;
	}

	if ( q==NULL ) return NULL;
	if ( q->ntype!=nJunction ) return NULL;
	if ( q->jtype!=aSubBlk ) return NULL;
	if ( !q->guess ) return NULL;

	return q;
}

/* MR1				                 					    */
/* MR1  10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs  */
/* MR1				                                                        */

#define STRINGIZEBUFSIZE 1024

static char stringizeBuf[STRINGIZEBUFSIZE];
char *
#ifdef __USE_PROTOS
stringize(char * s)
#else
stringize(s)
char *s;
#endif

{
  char		*p;
  char		*stop;

  p=stringizeBuf;
  stop=&stringizeBuf[1015];

  if (s != 0) {
    while (*s != 0) {
      if (p >= stop) {
	goto stringizeStop;
      } else if (*s == '\n') {
        *p++='\\';
        *p++='n';
        *p++='\\';
	*p++=*s++;
      } else if (*s == '\\') {
	*p++=*s;
	*p++=*s++;
      } else if (*s == '\"') {
        *p++='\\';
	*p++=*s++;
        while (*s != 0) {
          if (p >= stop) {
	     goto stringizeStop;
	  } else if (*s == '\n') {
	    *p++='\\';
	    *p++=*s++;
	  } else if (*s == '\\') {
	    *p++=*s++;
	    *p++=*s++;
	  } else if (*s == '\"') {
	    *p++='\\';
	    *p++=*s++;
	    break;
	  } else {
	    *p++=*s++;
          };
        };
      } else if (*s == '\'') {
	*p++=*s++;
        while (*s != 0) {
          if (p >= stop) {
	     goto stringizeStop;
	  } else if (*s == '\'') {
	    *p++=*s++;
	    break;
	  } else if (*s == '\\') {
	    *p++=*s++;
	    *p++=*s++;
	  } else if (*s == '\"') {
	    *p++='\\';
	    *p++=*s++;
	    break;
	  } else {
	    *p++=*s++;
          };
        };
      } else {
        *p++=*s++;
      };
    };
  };
  goto stringizeExit;
stringizeStop:
  *p++='.';        	
  *p++='.';        	
  *p++='.';        	
stringizeExit:
  *p=0;
  return stringizeBuf;
}

#ifdef __USE_PROTOS
int isNullAction(char *s)
#else
int isNullAction(s)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -