www.pudn.com > BAWK_NEW.zip > BAWKDO.C


/* 
 * Bawk C actions interpreter 
 */ 
#include  
#include "bawk.h" 
 
dopattern( pat ) 
char *pat; 
{ 
	Where = PATTERN; 
	Actptr = pat; 
	getoken(); 
	expression(); 
	return popint(); 
} 
 
doaction( act ) 
char *act; 
{ 
	Where = ACTION; 
	Actptr = act; 
	getoken(); 
	while ( Token!=T_EOF ) 
		statement(); 
} 
 
expression() 
{ 
	expr1(); 
 
	if ( Token==T_ASSIGN ) 
	{ 
		getoken(); 
		assignment( expression() ); 
	} 
} 
 
expr1() 
{ 
	int ival; 
 
	expr2(); 
	for ( ;; ) 
	{ 
		if ( Token==T_LIOR ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr2(); 
			pushint( popint() || ival ); 
		} 
		else 
			return; 
	} 
} 
 
expr2() 
{ 
	int ival; 
 
	expr3(); 
	for ( ;; ) 
	{ 
		if ( Token==T_LAND ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr3(); 
			pushint( popint() && ival ); 
		} 
		else 
			return; 
	} 
} 
 
expr3() 
{ 
	int ival; 
 
	expr4(); 
	for ( ;; ) 
	{ 
		if ( Token==T_IOR ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr4(); 
			pushint( popint() | ival ); 
		} 
		else 
			return; 
	} 
} 
 
 
expr4() 
{ 
	int ival; 
 
	expr5(); 
	for ( ;; ) 
	{ 
		if ( Token==T_AND ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr5(); 
			pushint( popint() & ival ); 
		} 
		else 
			return; 
	} 
} 
 
expr5() 
{ 
	int ival; 
 
	expr6(); 
	for ( ;; ) 
	{ 
		if ( Token==T_XOR ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr6(); 
			pushint( popint() ^ ival ); 
		} 
		else 
			return; 
	} 
} 
 
expr6() 
{ 
	int ival; 
 
	expr7(); 
	for ( ;; ) 
	{ 
		if ( Token==T_EQ ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr7(); 
			pushint( ival == popint() ); 
		} 
		else if ( Token==T_NE ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr7(); 
			pushint( ival != popint() ); 
		} 
		else 
			return; 
	} 
} 
 
expr7() 
{ 
	int ival; 
 
	expr8(); 
	for ( ;; ) 
	{ 
		if ( Token==T_LE ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr8(); 
			pushint( ival <= popint() ); 
		} 
		else if ( Token==T_GE ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr8(); 
			pushint( ival >= popint() ); 
		} 
		else if ( Token==T_LT ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr8(); 
			pushint( ival < popint() ); 
		} 
		else if ( Token==T_GT ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr8(); 
			pushint( ival > popint() ); 
		} 
		else 
			return; 
	} 
} 
 
expr8() 
{ 
	int ival; 
 
	expr9(); 
	for ( ;; ) 
	{ 
		if ( Token==T_SHL ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr9(); 
			pushint( ival << popint() ); 
		} 
		else if ( Token==T_SHR ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr9(); 
			pushint( ival >> popint() ); 
		} 
		else 
			return; 
	} 
} 
 
expr9() 
{ 
	int ival; 
 
	expr10(); 
	for ( ;; ) 
	{ 
		if ( Token==T_ADD ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr10(); 
			pushint( ival + popint() ); 
		} 
		else if ( Token==T_SUB ) 
		{ 
			getoken(); 
			ival = popint(); 
			expr10(); 
			pushint( ival - popint() ); 
		} 
		else 
			return; 
	} 
} 
 
expr10() 
{ 
	int ival; 
 
	primary(); 
	for ( ;; ) 
	{ 
		if ( Token==T_MUL ) 
		{ 
			getoken(); 
			ival = popint(); 
			primary(); 
			pushint( ival * popint() ); 
		} 
		else if ( Token==T_DIV ) 
		{ 
			getoken(); 
			ival = popint(); 
			primary(); 
			pushint( ival / popint() ); 
		} 
		else if ( Token==T_MOD ) 
		{ 
			getoken(); 
			ival = popint(); 
			primary(); 
			pushint( ival % popint() ); 
		} 
		else 
			return; 
	} 
} 
 
primary() 
{ 
	int index; 
	DATUM data; 
	VARIABLE *pvar; 
 
	switch ( Token ) 
	{ 
	case T_LPAREN: 
		/* 
		 * it's a parenthesized expression 
		 */ 
		getoken(); 
		expression(); 
		if ( Token!=T_RPAREN ) 
			error( "missing ')'", ACT_ERROR ); 
		getoken(); 
		break; 
	case T_LNOT: 
		getoken(); 
		primary(); 
		pushint( ! popint() ); 
		break; 
	case T_NOT: 
		getoken(); 
		primary(); 
		pushint( ~ popint() ); 
		break; 
	case T_ADD: 
		getoken(); 
		primary(); 
		break; 
	case T_SUB: 
		getoken(); 
		primary(); 
		pushint( - popint() ); 
		break; 
	case T_INCR: 
	case T_DECR: 
		preincdec(); 
		break; 
	case T_MUL: 
		getoken(); 
		primary(); 
		/* 
		 * If item on stack is an LVALUE, do an extra level of 
		 * indirection before changing it to an LVALUE. 
		 */ 
		if ( Stackptr->lvalue ) 
			Stackptr->value.ptrptr = *Stackptr->value.ptrptr; 
		Stackptr->lvalue = 1; 
		--Stackptr->class; 
		break; 
	case T_AND: 
		getoken(); 
		primary(); 
		if ( Stackptr->lvalue ) 
			Stackptr->lvalue = 0; 
		else 
			error( "'&' operator needs an lvalue", ACT_ERROR ); 
		break; 
	case T_CONSTANT: 
		pushint( Value.ival ); 
		getoken(); 
		break; 
	case T_REGEXP: 
		/* 
		 * It's a regular expression - parse it and compile it. 
		 */ 
		if ( Where == PATTERN ) 
		{ 
			/* 
			 * We're processing a pattern right now - perform a 
			 * match of the regular expression agains input line. 
			 */ 
			unparse( Fields, Fieldcount, Linebuf, Fieldsep ); 
			pushint( match( Linebuf, Value.dptr ) ); 
		} 
		else 
			push( 1, ACTUAL, BYTE, &Value ); 
		getoken(); 
		break; 
	case T_NF: 
		pushint( Fieldcount ); 
		getoken(); 
		break; 
	case T_NR: 
		pushint( Recordcount ); 
		getoken(); 
		break; 
	case T_FS: 
		Fieldsep[1] = 0; 
		data.dptr = Fieldsep; 
		push( 0, LVALUE, BYTE, &data ); 
		getoken(); 
		break; 
	case T_RS: 
		Recordsep[1] = 0; 
		data.dptr = Recordsep; 
		push( 0, LVALUE, BYTE, &data ); 
		getoken(); 
		break; 
	case T_FILENAME: 
		data.dptr = Filename; 
		push( 1, ACTUAL, BYTE, &data ); 
		getoken(); 
		break; 
	case T_DOLLAR: 
		/* 
		 * It's a reference to one (or all) of the words in Linebuf. 
		 */ 
		getoken(); 
		primary(); 
		if ( index = popint() ) 
		{ 
			if ( index > Fieldcount ) 
				index = Fieldcount; 
			else if ( index < 1 ) 
				index = 1; 
			data.dptr = Fields[ index-1 ]; 
		} 
		else 
		{ 
			/* 
			 * Reconstitute the line buffer in case any of the 
			 * fields have been changed. 
			 */ 
			unparse( Fields, Fieldcount, Linebuf, Fieldsep ); 
			data.dptr = Linebuf; 
		} 
		/* 
		 * $'s are treated the same as string constants: 
		 */ 
		push( 1, ACTUAL, BYTE, &data ); 
		break; 
	case T_STRING: 
		push( 1, ACTUAL, BYTE, &Value ); 
		getoken(); 
		break; 
	case T_FUNCTION: 
		/* 
		 * Do a built-in function call 
		 */ 
		index = Value.ival; 
		getoken(); 
		function( index ); 
		break; 
	case T_VARIABLE: 
		pvar = Value.dptr; 
		getoken(); 
		/* 
		 * it's a plain variable. The way a variable is 
		 * represented on the stack depends on its type: 
		 *      lvalue class value.dptr 
		 * vars:  1      0   address of var 
		 * ptrs:  1      1   ptr to address of ptr 
		 * array: 0      1   address of var 
		 */ 
		if ( pvar->vclass && !pvar->vlen ) 
			/* it's a pointer */ 
			data.dptr = &pvar->vptr; 
		else 
			/* an array or simple variable */ 
			data.dptr = pvar->vptr; 
		/* 
		 * If it's an array it can't be used as an LVALUE. 
		 */ 
		push( pvar->vclass, !pvar->vlen, pvar->vsize, &data ); 
		break; 
	case T_EOF: 
		break; 
	default: 
		syntaxerror(); 
	} 
	/* 
	 * a "[" means it's an array reference 
	 */ 
	if ( Token==T_LBRACKET ) 
	{ 
		getoken(); 
		if ( ! Stackptr->class ) 
			error( "'[]' needs an array or pointer", ACT_ERROR ); 
		/* 
		 * compute the subscript 
		 */ 
		expression(); 
		if ( Token!=T_RBRACKET ) 
			error( "missing ']'", ACT_ERROR ); 
		getoken(); 
		index = popint(); 
		/* 
		 * compute the offset (subscript times two for int arrays) 
		 * and then the effective address. 
		 */ 
		index *= Stackptr->size; 
		if ( Stackptr->lvalue ) 
			/* 
			 * It's a pointer - don't forget that the stack top 
			 * item's value is the address of the pointer so we 
			 * must do another level of indirection. 
			 */ 
			Stackptr->value.dptr = *Stackptr->value.ptrptr+index; 
		else 
			/* 
			 * It's a plain array - the stack top item's value is 
			 * the address of the first element in the array. 
			 */ 
			Stackptr->value.dptr += index; 
 
		/* 
		 * The stack top item now becomes an LVALUE, but we've 
		 * reduced the indirection level. 
		 */ 
		Stackptr->lvalue = 1; 
		--Stackptr->class; 
	} 
 
	if ( Token==T_INCR || Token==T_DECR ) 
		postincdec(); 
} 
 
preincdec() 
{ 
	/* 
	 * Pre increment/decrement 
	 */ 
	int incr; 
 
	incr = Token==T_INCR ? 1 : -1; 
	getoken(); 
	primary(); 
	if ( Stackptr->lvalue ) 
	{ 
		if ( Stackptr->class ) 
			incr *= Stackptr->size; 
		*Stackptr->value.ptrptr += incr; 
	} 
	else 
		error( "pre '++' or '--' needs an lvalue", ACT_ERROR ); 
} 
 
postincdec() 
{ 
	/* 
	 * Post increment/decrement 
	 */ 
	char **pp; 
	int incr; 
 
	incr = Token==T_INCR ? 1 : -1; 
	getoken(); 
	if ( Stackptr->lvalue ) 
	{ 
		if ( Stackptr->class ) 
		{ 
			/* 
			 * It's a pointer - save its old value then 
			 * increment/decrement the pointer.  This makes the 
			 * item on top of the stack look like an array, which 
			 * means it can no longer be used as an LVALUE. This 
			 * doesn't really hurt, since it doesn't make much 
			 * sense to say: 
			 *   char *cp; 
			 *   cp++ = value; 
			 */ 
			pp = *Stackptr->value.ptrptr; 
			*Stackptr->value.ptrptr += incr * Stackptr->size; 
			Stackptr->value.ptrptr = pp; 
		} 
		else 
		{ 
			/* 
			 * It's a simple variable - save its old value then 
			 * increment/decrement the variable.  This makes the 
			 * item on top of the stack look like a constant, 
			 * which means it can no longer be used as an LVALUE. 
			 * Same reasoning as above. 
			 */ 
			if ( Stackptr->size == BYTE ) 
				pp = *Stackptr->value.dptr; 
			else 
				pp = *Stackptr->value.ptrptr; 
			*Stackptr->value.ptrptr += incr; 
			Stackptr->value.ival = pp; 
		} 
		Stackptr->lvalue = 0; 
	} 
	else 
		error( "post '++' or '--' needs an lvalue", ACT_ERROR ); 
} 
 
statement() 
{ 
	/* 
	 * Evaluate a statement 
	 */ 
	char *repeat, *body; 
 
	switch ( Token ) 
	{ 
	case T_EOF: 
		break; 
	case T_CHAR: 
	case T_INT: 
		declist(); 
		break; 
	case T_LBRACE: 
		/* 
		 * parse a compound statement 
		 */ 
		getoken(); 
		while ( !Saw_break && Token!=T_RBRACE ) 
			statement(); 
 
		if ( Token==T_RBRACE ) 
			getoken(); 
		break; 
	case T_IF: 
		/* 
		 * parse an "if-else" statement 
		 */ 
		if ( getoken() != T_LPAREN ) 
			syntaxerror(); 
		getoken(); 
		expression(); 
		if ( Token!=T_RPAREN ) 
			syntaxerror(); 
		getoken(); 
		if ( popint() ) 
		{ 
			statement(); 
			if ( Token==T_ELSE ) 
			{ 
				getoken(); 
				skipstatement(); 
			} 
		} 
		else 
		{ 
			skipstatement(); 
			if ( Token==T_ELSE ) 
			{ 
				getoken(); 
				statement(); 
			} 
		} 
		break; 
	case T_WHILE: 
		/* 
		 * parse a "while" statement 
		 */ 
		repeat = Actptr; 
		for ( ;; ) 
		{ 
			if ( getoken() != T_LPAREN ) 
				syntaxerror(); 
 
			getoken(); 
			expression(); 
			if ( Token!=T_RPAREN ) 
				syntaxerror(); 
 
			if ( popint() ) 
			{ 
				body = Actptr; 
				getoken(); 
				statement(); 
				if ( Saw_break ) 
				{ 
					Actptr = body; 
					Saw_break = 0; 
					break; 
				} 
				Actptr = repeat; 
			} 
			else 
				break; 
		} 
		getoken(); 
		skipstatement(); 
		break; 
	case T_BREAK: 
		/* 
		 * parse a "break" statement 
		 */ 
		getoken(); 
		Saw_break = 1; 
		break; 
	case T_SEMICOLON: 
		break; 
	default: 
		expression(); 
		popint(); 
	} 
 
	if ( Token==T_SEMICOLON ) 
		getoken(); 
}	 
 
skipstatement() 
{ 
	/* 
	 * Skip a statement 
	 */ 
 
	switch ( Token ) 
	{ 
	case T_LBRACE: 
		/* 
		 * skip a compound statement 
		 */ 
		skip( T_LBRACE, T_RBRACE ); 
		break; 
	case T_IF: 
		/* 
		 * skip an "if-else" statement 
		 */ 
		getoken();	/* skip 'if' */ 
		skip( T_LPAREN, T_RPAREN ); 
		skipstatement(); 
		if ( Token==T_ELSE ) 
		{ 
			getoken();	/* skip 'else' */ 
			skipstatement(); 
		} 
		break; 
	case T_WHILE: 
		/* 
		 * skip a "while" statement 
		 */ 
		getoken();	/* skip 'while' */ 
		skip( T_LPAREN, T_RPAREN ); 
		skipstatement(); 
		break; 
	default: 
		/* 
		 * skip a one-liner 
		 */ 
		while (Token!=T_SEMICOLON && Token!=T_RBRACE && Token!=T_EOF) 
			getoken(); 
		if ( Token==T_EOF ) 
			error( "unexpected end", ACT_ERROR ); 
		if ( Token==T_SEMICOLON ) 
			getoken(); 
	} 
} 
 
skip( left, right ) 
char left, right; 
{ 
	/* 
	 * Skip matched left and right delimiters and everything in between 
	 */ 
	int parity; 
	char *save, errmsg[ 80 ]; 
 
	parity = 1; 
	save = Actptr; 
	while ( getoken() != T_EOF ) 
	{ 
		if ( Token == left ) 
		{ 
			save = Actptr; 
			++parity; 
		} 
		else if ( Token == right ) 
			--parity; 
		if ( !parity ) 
		{ 
			getoken(); 
			return; 
		} 
	} 
	Actptr = save; 
 
	sprintf( errmsg, "mismatched '%c' and '%c'", left, right ); 
	error( errmsg, ACT_ERROR ); 
} 
 
syntaxerror() 
{ 
	error( "syntax error", ACT_ERROR ); 
}