home *** CD-ROM | disk | FTP | other *** search
- /*
- * Bawk C actions interpreter
- */
- #include <stdio.h>
- #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;
- }
- /*
- * $<expr>'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 );
- }