Category : C Source Code
Archive   : BAWK.ZIP
Filename : BAWKDO.C

 
Output of file : BAWKDO.C contained in archive : BAWK.ZIP
/*
* 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 );
}


  3 Responses to “Category : C Source Code
Archive   : BAWK.ZIP
Filename : BAWKDO.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/