home *** CD-ROM | disk | FTP | other *** search
- /*
- * Bawk C actions interpreter
- */
- #include <stdio.h>
- #include "bawk.h"
-
- static char pop_array[MAX_TOKEN + 1];
-
- void init_pop_array()
- {
- register int i;
-
- DBUG_ENTER("init_pop_array");
- for(i = 0; i <= MAX_TOKEN; i++)
- pop_array[i] = 1;
- pop_array[T_STATEMENT] = pop_array[T_IF] = pop_array[T_DECLARE] = 0;
- pop_array[T_DECLARE] = pop_array[T_ARRAY_DECLARE] = 0;
- pop_array[T_BREAK] = 0;
- DBUG_VOID_RETURN;
- }
-
- int dopattern( root )
- register EXPR_NODE *root;
- {
- DBUG_ENTER("dopattern");
- Where = PATTERN;
- walk_tree(root);
- DBUG_RETURN(popint());
- }
-
- void doaction( root )
- register EXPR_NODE *root;
- {
- DBUG_ENTER("doaction");
- Where = ACTION;
- walk_tree(root);
- DBUG_VOID_RETURN;
- }
-
- void walk_tree(root)
- register EXPR_NODE *root;
- {
- register int ival;
- DATUM data;
- register VARIABLE *pvar;
- register VARDECL *pdecl;
-
- DBUG_ENTER("walk_tree");
- if(Saw_break || !root)
- DBUG_VOID_RETURN;
- switch(root->operator) {
- case T_ASSIGN:
- walk_tree(root->left);
- walk_tree(root->right);
- assignment();
- break;
- case T_LOR:
- walk_tree(root->left);
- if(popint())
- pushint(1);
- else {
- walk_tree(root->right);
- pushint(popint() != 0);
- }
- break;
- case T_LAND:
- walk_tree(root->left);
- if(!popint())
- pushint(0);
- else {
- walk_tree(root->right);
- pushint(popint() != 0);
- }
- break;
- case T_OR:
- walk_tree(root->left);
- walk_tree(root->right);
- pushint(popint() | popint());
- break;
- case T_AND:
- walk_tree(root->left);
- walk_tree(root->right);
- pushint(popint() & popint());
- break;
- case T_XOR:
- walk_tree(root->left);
- walk_tree(root->right);
- pushint(popint() ^ popint());
- break;
- case T_EQ:
- walk_tree(root->left);
- walk_tree(root->right);
- pushint(popint() == popint());
- break;
- case T_NE:
- walk_tree(root->left);
- walk_tree(root->right);
- pushint(popint() != popint());
- break;
- case T_LE:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival <= popint());
- break;
- case T_GE:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival >= popint());
- break;
- case T_LT:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival < popint());
- break;
- case T_GT:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival > popint());
- break;
- case T_SHL:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival << popint());
- break;
- case T_SHR:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival >> popint());
- break;
- case T_ADD:
- walk_tree(root->left);
- walk_tree(root->right);
- pushint(popint() + popint());
- break;
- case T_SUB:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival - popint());
- break;
- case T_MUL:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival * popint());
- break;
- case T_DIV:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival / popint());
- break;
- case T_MOD:
- walk_tree(root->left);
- ival = popint();
- walk_tree(root->right);
- pushint(ival % popint());
- break;
- case T_LNOT:
- walk_tree(root->left);
- pushint( ! popint() );
- break;
- case T_NOT:
- walk_tree(root->left);
- pushint( ~ popint() );
- break;
- case T_INCR:
- walk_tree(root->left);
- preincdec(1);
- break;
- case T_DECR:
- walk_tree(root->left);
- preincdec(-1);
- break;
- case T_DOLLAR:
- /*
- * It's a reference to one (or all) of the words in Linebuf.
- */
- walk_tree(root->left);
- if ( ival = popint() )
- {
- if ( ival > Fieldcount )
- ival = Fieldcount;
- else if ( ival < 1 )
- ival = 1;
- data.dptr = Fields[ ival-1 ];
- }
- else
- {
- /*
- * Reconstitute the line buffer in case any of the
- * fields have been changed.
- */
- unparse( Fields, Fieldcount, Linebuf, Fieldsep );
- data.dptr = Linebuf;
- }
- /*
- * $<expr>'s are treated the same as string constants:
- */
- push( (char) 1, (char) ACTUAL, (char) BYTE, &data );
- break;
- case T_UMINUS:
- walk_tree(root->left);
- pushint( - popint() );
- break;
- case T_STAR:
- walk_tree(root->left);
- /*
- * 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 =
- (char **) *Stackptr->value.ptrptr;
- Stackptr->lvalue = 1;
- --Stackptr->class;
- break;
- case T_ADDROF:
- walk_tree(root->left);
- if ( Stackptr->lvalue )
- Stackptr->lvalue = 0;
- else
- error( "'&' operator needs an lvalue", ACT_ERROR );
- break;
- case T_CONSTANT:
- pushint(((DATUM *) (root->left))->ival);
- break;
- case T_FUNCTION:
- function(((DATUM *) (root->left))->ival, root->right);
- break;
- case T_REGEXP:
- /*
- * Perform a match of the regular expression agains input
- * line.
- */
- unparse( Fields, Fieldcount, Linebuf, Fieldsep );
- pushint( match( Linebuf, (char *) root->left ) );
- break;
- case T_REGEXP_ARG:
- /*
- * A regular expression that is to be passed as a function
- * argument.
- */
- data.dptr = (char *) root->left;
- push( (char) 1, (char) ACTUAL, (char) BYTE, &data );
- break;
- case T_STRING:
- data.dptr = (char *) root->left;
- push( (char) 1, (char) ACTUAL, (char) BYTE, &data );
- break;
- case T_NF:
- pushint( Fieldcount );
- break;
- case T_NR:
- pushint( Recordcount );
- break;
- case T_FS:
- data.dptr = Fieldsep;
- push( (char) 1, (char) ACTUAL, (char) BYTE, &data );
- break;
- case T_RS:
- data.dptr = Recordsep;
- push( (char) 1, (char) ACTUAL, (char) BYTE, &data );
- break;
- case T_FILENAME:
- data.dptr = Filename;
- push( (char) 1, (char) ACTUAL, (char) BYTE, &data );
- break;
- case T_VARIABLE:
- pvar = (VARIABLE *) root->left;
- /*
- * 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 = (char *) &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, (char) !pvar->vlen, pvar->vsize, &data );
- break;
- case T_LBRACKET:
- walk_tree(root->left);
- if ( ! Stackptr->class )
- error( "'[]' needs an array or pointer", ACT_ERROR );
- /*
- * compute the subscript
- */
- walk_tree(root->right);
- ival = popint();
- /*
- * compute the offset (subscript times WORD for int arrays)
- * and then the effective address.
- */
- ival *= 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+ival;
- 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 += ival;
-
- /*
- * The stack top item now becomes an LVALUE, but we've
- * reduced the indirection level.
- */
- Stackptr->lvalue = 1;
- --Stackptr->class;
- break;
- case T_POSTINCR:
- walk_tree(root->left);
- postincdec(1);
- break;
- case T_POSTDECR:
- walk_tree(root->left);
- postincdec(-1);
- break;
- case T_STATEMENT:
- if(root->left) {
- walk_tree(root->left);
- if(pop_array[root->left->operator])
- popint();
- }
- walk_tree(root->right);
- break;
- case T_DECLARE:
- pdecl = (VARDECL *) root->left;
- pvar = pdecl->variable;
- if(pdecl->vsize != ((pvar->vlen ? pvar->vlen : 1)*
- pvar->vsize)) {
- /*
- * The amount of storage needed for the variable has
- * changed.
- */
- free(pvar->vptr);
- pvar->vptr = get_clear_memory(pdecl->vsize);
- }
- pvar->vclass = pdecl->vclass;
- pvar->vsize = pdecl->vsize;
- pvar->vlen = 0;
- walk_tree(root->right);
- break;
- case T_ARRAY_DECLARE:
- /* Compute the dimension */
- walk_tree(root->left->right);
- ival = popint();
- pdecl = (VARDECL *) root->left->left;
- pvar = pdecl->variable;
- if((ival*pdecl->vsize) != ((pvar->vlen ? pvar->vlen : 1)*
- pvar->vsize)) {
- free(pvar->vptr);
- pvar->vptr = get_clear_memory(ival*pdecl->vsize);
- }
- pvar->vclass = pdecl->vclass;
- pvar->vsize = pdecl->vsize;
- pvar->vlen = ival;
- walk_tree(root->right);
- break;
- case T_IF:
- walk_tree(root->left->left);
- if(popint())
- walk_tree(root->left->right);
- else
- walk_tree(root->right);
- break;
- case T_WHILE:
- while( !Saw_break )
- {
- walk_tree(root->left);
- if( ! popint() )
- break;
- walk_tree(root->right);
- }
- Saw_break = 0;
- break;
- case T_BREAK:
- Saw_break = 1;
- break;
- default:
- DBUG_PRINT("walk_tree",
- ("decimal value of operator = %d",root->operator));
- error("internal error: parse tree node with unknown symbol",
- ACT_ERROR);
- }
- DBUG_VOID_RETURN;
- }
-
- void preincdec(incr)
- register int incr;
- {
- /*
- * Pre increment/decrement
- */
- DBUG_ENTER("preincdec");
- if ( Stackptr->lvalue )
- {
- if ( Stackptr->class )
- incr *= Stackptr->size;
- *Stackptr->value.ptrptr += incr;
- }
- else
- error( "pre '++' or '--' needs an lvalue", ACT_ERROR );
- DBUG_VOID_RETURN;
- }
-
-
- void postincdec(incr)
- register int incr;
- {
- /*
- * Post increment/decrement
- */
- register char **pp;
-
- DBUG_ENTER("postincdec");
- 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 = (char **) *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 = (char **) *Stackptr->value.dptr;
- else
- pp = (char **) *Stackptr->value.ptrptr;
- *Stackptr->value.ptrptr += incr;
- Stackptr->value.ptrptr = pp;
- }
- Stackptr->lvalue = 0;
- }
- else
- error( "post '++' or '--' needs an lvalue", ACT_ERROR );
- DBUG_VOID_RETURN;
- }
-