/* * Bawk C actions interpreter */ #include #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; } /* * $'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; }