ast@cs.vu.nl (09/23/89)
: This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'bawkdo.c' sed 's/^X//' > 'bawkdo.c' << '+ END-OF-FILE ''bawkdo.c' X/* X * Bawk C actions interpreter X */ X#include <stdio.h> X#include "bawk.h" X Xdopattern( pat ) Xchar *pat; X{ X Where = PATTERN; X Actptr = pat; X getoken(); X expression(); X return popint(); X} X Xdoaction( act ) Xchar *act; X{ X Where = ACTION; X Actptr = act; X getoken(); X while ( Token!=T_EOF ) X statement(); X} X Xexpression() X{ X expr1(); X X if ( Token==T_ASSIGN ) X { X getoken(); X assignment( expression() ); X } X} X Xexpr1() X{ X int ival; X X expr2(); X for ( ;; ) X { X if ( Token==T_LIOR ) X { X getoken(); X ival = popint(); X expr2(); X pushint( popint() || ival ); X } X else X return; X } X} X Xexpr2() X{ X int ival; X X expr3(); X for ( ;; ) X { X if ( Token==T_LAND ) X { X getoken(); X ival = popint(); X expr3(); X pushint( popint() && ival ); X } X else X return; X } X} X Xexpr3() X{ X int ival; X X expr4(); X for ( ;; ) X { X if ( Token==T_IOR ) X { X getoken(); X ival = popint(); X expr4(); X pushint( popint() | ival ); X } X else X return; X } X} X X Xexpr4() X{ X int ival; X X expr5(); X for ( ;; ) X { X if ( Token==T_AND ) X { X getoken(); X ival = popint(); X expr5(); X pushint( popint() & ival ); X } X else X return; X } X} X Xexpr5() X{ X int ival; X X expr6(); X for ( ;; ) X { X if ( Token==T_XOR ) X { X getoken(); X ival = popint(); X expr6(); X pushint( popint() ^ ival ); X } X else X return; X } X} X Xexpr6() X{ X int ival; X X expr7(); X for ( ;; ) X { X if ( Token==T_EQ ) X { X getoken(); X ival = popint(); X expr7(); X pushint( ival == popint() ); X } X else if ( Token==T_NE ) X { X getoken(); X ival = popint(); X expr7(); X pushint( ival != popint() ); X } X else X return; X } X} X Xexpr7() X{ X int ival; X X expr8(); X for ( ;; ) X { X if ( Token==T_LE ) X { X getoken(); X ival = popint(); X expr8(); X pushint( ival <= popint() ); X } X else if ( Token==T_GE ) X { X getoken(); X ival = popint(); X expr8(); X pushint( ival >= popint() ); X } X else if ( Token==T_LT ) X { X getoken(); X ival = popint(); X expr8(); X pushint( ival < popint() ); X } X else if ( Token==T_GT ) X { X getoken(); X ival = popint(); X expr8(); X pushint( ival > popint() ); X } X else X return; X } X} X Xexpr8() X{ X int ival; X X expr9(); X for ( ;; ) X { X if ( Token==T_SHL ) X { X getoken(); X ival = popint(); X expr9(); X pushint( ival << popint() ); X } X else if ( Token==T_SHR ) X { X getoken(); X ival = popint(); X expr9(); X pushint( ival >> popint() ); X } X else X return; X } X} X Xexpr9() X{ X int ival; X X expr10(); X for ( ;; ) X { X if ( Token==T_ADD ) X { X getoken(); X ival = popint(); X expr10(); X pushint( ival + popint() ); X } X else if ( Token==T_SUB ) X { X getoken(); X ival = popint(); X expr10(); X pushint( ival - popint() ); X } X else X return; X } X} X Xexpr10() X{ X int ival; X X primary(); X for ( ;; ) X { X if ( Token==T_MUL ) X { X getoken(); X ival = popint(); X primary(); X pushint( ival * popint() ); X } X else if ( Token==T_DIV ) X { X getoken(); X ival = popint(); X primary(); X pushint( ival / popint() ); X } X else if ( Token==T_MOD ) X { X getoken(); X ival = popint(); X primary(); X pushint( ival % popint() ); X } X else X return; X } X} X Xprimary() X{ X int index; X DATUM data; X VARIABLE *pvar; X X switch ( Token ) X { X case T_LPAREN: X /* X * it's a parenthesized expression X */ X getoken(); X expression(); X if ( Token!=T_RPAREN ) X error( "missing ')'", ACT_ERROR ); X getoken(); X break; X case T_LNOT: X getoken(); X primary(); X pushint( ! popint() ); X break; X case T_NOT: X getoken(); X primary(); X pushint( ~ popint() ); X break; X case T_ADD: X getoken(); X primary(); X break; X case T_SUB: X getoken(); X primary(); X pushint( - popint() ); X break; X case T_INCR: X case T_DECR: X preincdec(); X break; X case T_MUL: X getoken(); X primary(); X /* X * If item on stack is an LVALUE, do an extra level of X * indirection before changing it to an LVALUE. X */ X if ( Stackptr->lvalue ) X Stackptr->value.ptrptr = *Stackptr->value.ptrptr; X Stackptr->lvalue = 1; X --Stackptr->class; X break; X case T_AND: X getoken(); X primary(); X if ( Stackptr->lvalue ) X Stackptr->lvalue = 0; X else X error( "'&' operator needs an lvalue", ACT_ERROR ); X break; X case T_CONSTANT: X pushint( Value.ival ); X getoken(); X break; X case T_REGEXP: X /* X * It's a regular expression - parse it and compile it. X */ X if ( Where == PATTERN ) X { X /* X * We're processing a pattern right now - perform a X * match of the regular expression agains input line. X */ X unparse( Fields, Fieldcount, Linebuf, Fieldsep ); X pushint( match( Linebuf, Value.dptr ) ); X } X else X push( 1, ACTUAL, BYTE, &Value ); X getoken(); X break; X case T_NF: X pushint( Fieldcount ); X getoken(); X break; X case T_NR: X pushint( Recordcount ); X getoken(); X break; X case T_FS: X Fieldsep[1] = 0; X data.dptr = Fieldsep; X push( 0, LVALUE, BYTE, &data ); X getoken(); X break; X case T_RS: X Recordsep[1] = 0; X data.dptr = Recordsep; X push( 0, LVALUE, BYTE, &data ); X getoken(); X break; X case T_FILENAME: X data.dptr = Filename; X push( 1, ACTUAL, BYTE, &data ); X getoken(); X break; X case T_DOLLAR: X /* X * It's a reference to one (or all) of the words in Linebuf. X */ X getoken(); X primary(); X if ( index = popint() ) X { X if ( index > Fieldcount ) X index = Fieldcount; X else if ( index < 1 ) X index = 1; X data.dptr = Fields[ index-1 ]; X } X else X { X /* X * Reconstitute the line buffer in case any of the X * fields have been changed. X */ X unparse( Fields, Fieldcount, Linebuf, Fieldsep ); X data.dptr = Linebuf; X } X /* X * $<expr>'s are treated the same as string constants: X */ X push( 1, ACTUAL, BYTE, &data ); X break; X case T_STRING: X push( 1, ACTUAL, BYTE, &Value ); X getoken(); X break; X case T_FUNCTION: X /* X * Do a built-in function call X */ X index = Value.ival; X getoken(); X function( index ); X break; X case T_VARIABLE: X pvar = Value.dptr; X getoken(); X /* X * it's a plain variable. The way a variable is X * represented on the stack depends on its type: X * lvalue class value.dptr X * vars: 1 0 address of var X * ptrs: 1 1 ptr to address of ptr X * array: 0 1 address of var X */ X if ( pvar->vclass && !pvar->vlen ) X /* it's a pointer */ X data.dptr = &pvar->vptr; X else X /* an array or simple variable */ X data.dptr = pvar->vptr; X /* X * If it's an array it can't be used as an LVALUE. X */ X push( pvar->vclass, !pvar->vlen, pvar->vsize, &data ); X break; X case T_EOF: X break; X default: X syntaxerror(); X } X /* X * a "[" means it's an array reference X */ X if ( Token==T_LBRACKET ) X { X getoken(); X if ( ! Stackptr->class ) X error( "'[]' needs an array or pointer", ACT_ERROR ); X /* X * compute the subscript X */ X expression(); X if ( Token!=T_RBRACKET ) X error( "missing ']'", ACT_ERROR ); X getoken(); X index = popint(); X /* X * compute the offset (subscript times two for int arrays) X * and then the effective address. X */ X index *= Stackptr->size; X if ( Stackptr->lvalue ) X /* X * It's a pointer - don't forget that the stack top X * item's value is the address of the pointer so we X * must do another level of indirection. X */ X Stackptr->value.dptr = *Stackptr->value.ptrptr+index; X else X /* X * It's a plain array - the stack top item's value is X * the address of the first element in the array. X */ X Stackptr->value.dptr += index; X X /* X * The stack top item now becomes an LVALUE, but we've X * reduced the indirection level. X */ X Stackptr->lvalue = 1; X --Stackptr->class; X } X X if ( Token==T_INCR || Token==T_DECR ) X postincdec(); X} X Xpreincdec() X{ X /* X * Pre increment/decrement X */ X int incr; X X incr = Token==T_INCR ? 1 : -1; X getoken(); X primary(); X if ( Stackptr->lvalue ) X { X if ( Stackptr->class ) X incr *= Stackptr->size; X *Stackptr->value.ptrptr += incr; X } X else X error( "pre '++' or '--' needs an lvalue", ACT_ERROR ); X} X Xpostincdec() X{ X /* X * Post increment/decrement X */ X char **pp; X int incr; X X incr = Token==T_INCR ? 1 : -1; X getoken(); X if ( Stackptr->lvalue ) X { X if ( Stackptr->class ) X { X /* X * It's a pointer - save its old value then X * increment/decrement the pointer. This makes the X * item on top of the stack look like an array, which X * means it can no longer be used as an LVALUE. This X * doesn't really hurt, since it doesn't make much X * sense to say: X * char *cp; X * cp++ = value; X */ X pp = *Stackptr->value.ptrptr; X *Stackptr->value.ptrptr += incr * Stackptr->size; X Stackptr->value.ptrptr = pp; X } X else X { X /* X * It's a simple variable - save its old value then X * increment/decrement the variable. This makes the X * item on top of the stack look like a constant, X * which means it can no longer be used as an LVALUE. X * Same reasoning as above. X */ X if ( Stackptr->size == BYTE ) X pp = *Stackptr->value.dptr; X else X pp = *Stackptr->value.ptrptr; X *Stackptr->value.ptrptr += incr; X Stackptr->value.ival = pp; X } X Stackptr->lvalue = 0; X } X else X error( "post '++' or '--' needs an lvalue", ACT_ERROR ); X} X Xstatement() X{ X /* X * Evaluate a statement X */ X char *repeat, *body; X X switch ( Token ) X { X case T_EOF: X break; X case T_CHAR: X case T_INT: X declist(); X break; X case T_LBRACE: X /* X * parse a compound statement X */ X getoken(); X while ( !Saw_break && Token!=T_RBRACE ) X statement(); X X if ( Token==T_RBRACE ) X getoken(); X break; X case T_IF: X /* X * parse an "if-else" statement X */ X if ( getoken() != T_LPAREN ) X syntaxerror(); X getoken(); X expression(); X if ( Token!=T_RPAREN ) X syntaxerror(); X getoken(); X if ( popint() ) X { X statement(); X if ( Token==T_ELSE ) X { X getoken(); X skipstatement(); X } X } X else X { X skipstatement(); X if ( Token==T_ELSE ) X { X getoken(); X statement(); X } X } X break; X case T_WHILE: X /* X * parse a "while" statement X */ X repeat = Actptr; X for ( ;; ) X { X if ( getoken() != T_LPAREN ) X syntaxerror(); X X getoken(); X expression(); X if ( Token!=T_RPAREN ) X syntaxerror(); X X if ( popint() ) X { X body = Actptr; X getoken(); X statement(); X if ( Saw_break ) X { X Actptr = body; X Saw_break = 0; X break; X } X Actptr = repeat; X } X else X break; X } X getoken(); X skipstatement(); X break; X case T_BREAK: X /* X * parse a "break" statement X */ X getoken(); X Saw_break = 1; X break; X case T_SEMICOLON: X break; X default: X expression(); X popint(); X } X X if ( Token==T_SEMICOLON ) X getoken(); X} X Xskipstatement() X{ X /* X * Skip a statement X */ X X switch ( Token ) X { X case T_LBRACE: X /* X * skip a compound statement X */ X skip( T_LBRACE, T_RBRACE ); X break; X case T_IF: X /* X * skip an "if-else" statement X */ X getoken(); /* skip 'if' */ X skip( T_LPAREN, T_RPAREN ); X skipstatement(); X if ( Token==T_ELSE ) X { X getoken(); /* skip 'else' */ X skipstatement(); X } X break; X case T_WHILE: X /* X * skip a "while" statement X */ X getoken(); /* skip 'while' */ X skip( T_LPAREN, T_RPAREN ); X skipstatement(); X break; X default: X /* X * skip a one-liner X */ X while (Token!=T_SEMICOLON && Token!=T_RBRACE && Token!=T_EOF) X getoken(); X if ( Token==T_EOF ) X error( "unexpected end", ACT_ERROR ); X if ( Token==T_SEMICOLON ) X getoken(); X } X} X Xskip( left, right ) Xchar left, right; X{ X /* X * Skip matched left and right delimiters and everything in between X */ X int parity; X char *save, errmsg[ 80 ]; X X parity = 1; X save = Actptr; X while ( getoken() != T_EOF ) X { X if ( Token == left ) X { X save = Actptr; X ++parity; X } X else if ( Token == right ) X --parity; X if ( !parity ) X { X getoken(); X return; X } X } X Actptr = save; X X sprintf( errmsg, "mismatched '%c' and '%c'", left, right ); X error( errmsg, ACT_ERROR ); X} X Xsyntaxerror() X{ X error( "syntax error", ACT_ERROR ); X} + END-OF-FILE bawkdo.c chmod 'u=rw,g=r,o=r' 'bawkdo.c' set `wc -c 'bawkdo.c'` count=$1 case $count in 21383) :;; *) echo 'Bad character count in ''bawkdo.c' >&2 echo 'Count should be 21383' >&2 esac echo Extracting 'bawkpat.c' sed 's/^X//' > 'bawkpat.c' << '+ END-OF-FILE ''bawkpat.c' X/* X * Bawk regular expression compiler/interpreter X */ X#include <stdio.h> X#include "bawk.h" X Xre_compile( patbuf ) Xchar *patbuf; /* where to put compiled pattern */ X{ X /* X * Compile a regular expression from current input file X * into the given pattern buffer. X */ X int c, /* Current character */ X o; /* Temp */ X char *patptr, /* destination string pntr */ X *lp, /* Last pattern pointer */ X *spp, /* Save beginning of pattern */ X delim, /* pattern delimiter */ X *cclass(); /* Compile class routine */ X X patptr = patbuf; X delim = getcharacter(); X X while ( (c = getcharacter()) != -1 && c != delim ) X { X /* X * STAR, PLUS and MINUS are special. X */ X if (c == '*' || c == '+' || c == '-') { X if (patptr == patbuf || X (o=patptr[-1]) == BOL || X o == EOL || X o == STAR || X o == PLUS || X o == MINUS) X error( "illegal occurrance op", RE_ERROR ); X *patptr++ = ENDPAT; X *patptr++ = ENDPAT; X spp = patptr; /* Save pattern end */ X while (--patptr > lp) /* Move pattern down... */ X *patptr = patptr[-1]; /* one byte */ X *patptr = (c == '*') ? STAR : X (c == '-') ? MINUS : PLUS; X patptr = spp; /* Restore pattern end */ X continue; X } X /* X * All the rest. X */ X lp = patptr; /* Remember start */ X switch(c) { X X case '^': X *patptr++ = BOL; X break; X X case '$': X *patptr++ = EOL; X break; X X case '.': X *patptr++ = ANY; X break; X X case '[': X patptr = cclass( patptr ); X break; X X case ':': X if ( (c=getcharacter()) != -1 ) X { X switch( tolower( c ) ) X { X X case 'a': X *patptr++ = ALPHA; X break; X X case 'd': X *patptr++ = DIGIT; X break; X X case 'n': X *patptr++ = NALPHA; X break; X X case ' ': X *patptr++ = PUNCT; X break; X X default: X error( "unknown ':' type", RE_ERROR ); X X } X } X else X error( "no ':' type", RE_ERROR ); X break; X X case '\\': X c = getcharacter(); X X default: X *patptr++ = CHAR; X *patptr++ = c; X } X } X *patptr++ = ENDPAT; X *patptr++ = 0; /* Terminate string */ X X#ifdef DEBUG X if ( Debug>1 ) X { X for ( lp=patbuf; lp<patptr; ++lp ) X { X switch ( c = *lp ) X { X case CHAR: printf("char "); break; X case BOL: printf("bol "); break; X case EOL: printf("eol "); break; X case ANY: printf("any "); break; X case CLASS: printf("class(%d) ", *++lp); break; X case NCLASS: printf("notclass(%d) ",*++lp); break; X case STAR: printf("star "); break; X case PLUS: printf("plus "); break; X case MINUS: printf("minus "); break; X case ALPHA: printf("alpha "); break; X case DIGIT: printf("digit "); break; X case NALPHA: printf("notalpha "); break; X case PUNCT: printf("punct "); break; X case RANGE: printf("range "); break; X case ENDPAT: printf("endpat "); break; X default: printf("<%c> ", c); break; X } X } X printf( "\n" ); X } X#endif X X return patptr - patbuf; X} X Xchar * Xcclass( patbuf ) Xchar *patbuf; /* destination pattern buffer */ X{ X /* X * Compile a class (within []) X */ X char *patptr, /* destination pattern pointer */ X *cp; /* Pattern start */ X int c, /* Current character */ X o; /* Temp */ X X patptr = patbuf; X X if ( (c = getcharacter()) == -1 ) X error( "class terminates badly", RE_ERROR ); X else if ( c == '^') X { X /* X * Class exclusion, for example: [^abc] X * Swallow the "^" and set token type to class exclusion. X */ X o = NCLASS; X } X else X { X /* X * Normal class, for example: [abc] X * push back the character and set token type to class X */ X ungetcharacter( c ); X o = CLASS; X } X *patptr++ = o; X X cp = patptr; /* remember where byte count is */ X *patptr++ = 0; /* and initialize byte count */ X while ( (c = getcharacter()) != -1 && c!=']' ) X { X o = getcharacter(); /* peek at next char */ X if (c == '\\') /* Store quoted chars */ X { X if ( o == -1) /* Gotta get something */ X error( "class terminates badly", RE_ERROR ); X *patptr++ = o; X } X else if ( c=='-' && (patptr-cp)>1 && o!=']' && o != -1 ) X { X c = patptr[-1]; /* Range start */ X patptr[-1] = RANGE; /* Range signal */ X *patptr++ = c; /* Re-store start */ X *patptr++ = o; /* Store end char */ X } X else X { X *patptr++ = c; /* Store normal char */ X ungetcharacter( o ); X } X } X if (c != ']') X error( "unterminated class", RE_ERROR ); X if ( (c = (patptr - cp)) >= 256 ) X error( "class too large", RE_ERROR ); X if ( c == 0 ) X error( "empty class", RE_ERROR ); X *cp = c; /* fill in byte count */ X X return patptr; X} X Xmatch( line, pattern ) Xchar *line; /* line to match */ Xchar *pattern; /* pattern to match */ X{ X /* X * Match the current line (in Linebuf[]), return 1 if it does. X */ X char *l; /* Line pointer */ X char *pmatch(); X char *next; X int matches; X X matches = 0; X for (l = line; *l; l++) X { X if ( next = pmatch(line, l, pattern) ) X { X l = next - 1; X ++matches; X#ifdef DEBUG X if ( Debug ) X printf( "match!\n" ); X#endif X } X } X X return matches; X} X Xchar * Xpmatch(linestart, line, pattern) Xchar *linestart; /* start of line to match */ Xchar *line; /* (partial) line to match */ Xchar *pattern; /* (partial) pattern to match */ X{ X char *l; /* Current line pointer */ X char *p; /* Current pattern pointer */ X char c; /* Current character */ X char *e; /* End for STAR and PLUS match */ X int op; /* Pattern operation */ X int n; /* Class counter */ X char *are; /* Start of STAR match */ X X l = line; X X#ifdef DEBUG X if (Debug > 1) X printf("pmatch(\"%s\")\n", line); X#endif X X p = pattern; X while ((op = *p++) != ENDPAT) { X X#ifdef DEBUG X if (Debug > 1) X printf("byte[%d] = 0%o, '%c', op = 0%o\n", X l-line, *l, *l, op); X#endif X X switch(op) { X X case CHAR: X if ( *l++ != *p++) X return 0; X break; X X case BOL: X if (l != linestart) X return 0; X break; X X case EOL: X if (*l != '\0') X return 0; X break; X X case ANY: X if (*l++ == '\0') X return 0; X break; X X case DIGIT: X if ((c = *l++) < '0' || (c > '9')) X return 0; X break; X X case ALPHA: X c = tolower( *l++ ); X if (c < 'a' || c > 'z') X return 0; X break; X X case NALPHA: X c = tolower(*l++); X if (c >= 'a' && c <= 'z') X break; X else if (c < '0' || c > '9') X return 0; X break; X X case PUNCT: X c = *l++; X if (c == 0 || c > ' ') X return 0; X break; X X case CLASS: X case NCLASS: X c = *l++; X n = *p++ & 0377; X do { X if (*p == RANGE) { X p += 3; X n -= 2; X if (c >= p[-2] && c <= p[-1]) X break; X } X else if (c == *p++) X break; X } while (--n > 1); X if ((op == CLASS) == (n <= 1)) X return 0; X if (op == CLASS) X p += n - 2; X break; X X case MINUS: X e = pmatch(linestart,l,p);/* Look for a match */ X while (*p++ != ENDPAT); /* Skip over pattern */ X if (e) /* Got a match? */ X l = e; /* Yes, update string */ X break; /* Always succeeds */ X X case PLUS: /* One or more ... */ X if ((l = pmatch(linestart,l,p)) == 0) X return 0; /* Gotta have a match */ X case STAR: /* Zero or more ... */ X are = l; /* Remember line start */ X while (*l && (e = pmatch(linestart,l,p))) X l = e; /* Get longest match */ X while (*p++ != ENDPAT); /* Skip over pattern */ X while (l >= are) { /* Try to match rest */ X if (e = pmatch(linestart,l,p)) X return e; X --l; /* Nope, try earlier */ X } X return 0; /* Nothing else worked */ X X default: X fprintf( stderr, "bad op code %d\n", op ); X error( "can't happen -- match", RE_ERROR ); X } X } X return l; X} + END-OF-FILE bawkpat.c chmod 'u=rw,g=r,o=r' 'bawkpat.c' set `wc -c 'bawkpat.c'` count=$1 case $count in 13298) :;; *) echo 'Bad character count in ''bawkpat.c' >&2 echo 'Count should be 13298' >&2 esac echo Extracting 'bawksym.c' sed 's/^X//' > 'bawksym.c' << '+ END-OF-FILE ''bawksym.c' X/* X * Bawk C actions builtin functions, variable declaration, and X * stack management routines. X */ X#include <stdio.h> X#include "bawk.h" X X#define MAXARGS 10 /* max # of arguments to a builtin func */ X#define F_PRINTF 1 X#define F_GETLINE 2 X#define F_STRLEN 3 X#define F_STRCPY 4 X#define F_STRCMP 5 X#define F_TOUPPER 6 X#define F_TOLOWER 7 X#define F_MATCH 8 X#define F_NEXTFILE 9 X Xisfunction( s ) Xchar *s; X{ X /* X * Compare the string "s" to a list of builtin functions X * and return its (non-zero) token number. X * Return zero if "s" is not a function. X */ X if ( !strcmp( s, "printf" ) ) X return F_PRINTF; X if ( !strcmp( s, "getline" ) ) X return F_GETLINE; X if ( !strcmp( s, "strlen" ) ) X return F_STRLEN; X if ( !strcmp( s, "strcpy" ) ) X return F_STRCPY; X if ( !strcmp( s, "strcmp" ) ) X return F_STRCMP; X if ( !strcmp( s, "toupper" ) ) X return F_TOUPPER; X if ( !strcmp( s, "tolower" ) ) X return F_TOLOWER; X if ( !strcmp( s, "match" ) ) X return F_MATCH; X if ( !strcmp( s, "nextfile" ) ) X return F_NEXTFILE; X return 0; X} X Xiskeyword( s ) Xchar *s; X{ X /* X * Compare the string "s" to a list of keywords and return its X * (non-zero) token number. Return zero if "s" is not a keyword. X */ X if ( !strcmp( s, "char" ) ) X return T_CHAR; X if ( !strcmp( s, "int" ) ) X return T_INT; X if ( !strcmp( s, "if" ) ) X return T_IF; X if ( !strcmp( s, "else" ) ) X return T_ELSE; X if ( !strcmp( s, "while" ) ) X return T_WHILE; X if ( !strcmp( s, "break" ) ) X return T_BREAK; X X if ( !strcmp( s, "NF" ) ) X return T_NF; X if ( !strcmp( s, "NR" ) ) X return T_NR; X if ( !strcmp( s, "FS" ) ) X return T_FS; X if ( !strcmp( s, "RS" ) ) X return T_RS; X if ( !strcmp( s, "FILENAME" ) ) X return T_FILENAME; X if ( !strcmp( s, "BEGIN" ) ) X return T_BEGIN; X if ( !strcmp( s, "END" ) ) X return T_END; X return 0; X} X Xfunction( funcnum ) X{ X int argc, args[ MAXARGS ]; X char lpar; X X argc = 0; X if ( Token==T_LPAREN ) X { X lpar = 1; X getoken(); X } X else X lpar = 0; X /* X * If there are any arguments, evaluate them and copy their values X * to a local array. X */ X if ( Token!=T_RPAREN && Token!=T_EOF ) X { X for ( ;; ) X { X expression(); X if ( argc<MAXARGS ) X args[ argc++ ] = popint(); X else X popint(); X if ( Token==T_COMMA ) X getoken(); X else X break; X } X } X if ( lpar && Token!=T_RPAREN ) X error( "missing ')'", ACT_ERROR ); X else if ( Token==T_RPAREN ) X getoken(); X X switch ( funcnum ) X { X case F_PRINTF: /* just like the real printf() function */ X pushint( printf( args[0], args[1], args[2], args[3], args[4], X args[5], args[6], args[7], args[8], args[9] ) ); X break; X case F_GETLINE: X /* X * Get the next line of input from the current input file X * and parse according to the current field seperator. X * Don't forget to free up the previous line's words first... X */ X while ( Fieldcount ) X free( Fields[ --Fieldcount ] ); X pushint( getline() ); X Fieldcount = parse( Linebuf, Fields, Fieldsep ); X break; X case F_STRLEN: /* calculate length of string argument */ X pushint( strlen( args[0] ) ); X break; X case F_STRCPY: /* copy second string argument to first string */ X pushint( strcpy( args[0], args[1] ) ); X break; X case F_STRCMP: /* compare two strings */ X pushint( strcmp( args[0], args[1] ) ); X break; X case F_TOUPPER: /* convert the character argument to upper case */ X pushint( toupper( args[0] ) ); X break; X case F_TOLOWER: /* convert the character argument to lower case */ X pushint( tolower( args[0] ) ); X break; X case F_MATCH: /* match a string argument to a regular expression */ X pushint( match( args[0], args[1] ) ); X break; X case F_NEXTFILE:/* close current input file and process next file */ X pushint( endfile() ); X break; X default: /* oops! */ X error( "bad function call", ACT_ERROR ); X } X} X XVARIABLE * Xfindvar( s ) Xchar *s; X{ X /* X * Search the symbol table for a variable whose name is "s". X */ X VARIABLE *pvar; X int i; X char name[ MAXVARLEN ]; X X i = 0; X while ( i < MAXVARLEN && alphanum( *s ) ) X name[i++] = *s++; X if ( i<MAXVARLEN ) X name[i] = 0; X X for ( pvar = Vartab; pvar<Nextvar; ++pvar ) X { X if ( !strncmp( pvar->vname, name, MAXVARLEN ) ) X return pvar; X } X return NULL; X} X XVARIABLE * Xaddvar( name ) Xchar *name; X{ X /* X * Add a new variable to symbol table and assign it default X * attributes (int name;) X */ X int i; X X if ( Nextvar <= Vartab + MAXVARTABSZ ) X { X i = 0; X while ( i<MAXVARLEN && alphanum( *name ) ) X Nextvar->vname[i++] = *name++; X if ( i<MAXVARLEN ) X Nextvar->vname[i] = 0; X X Nextvar->vclass = 0; X Nextvar->vsize = WORD; X Nextvar->vlen = 0; X /* X * Allocate some new room X */ X Nextvar->vptr = getmem( WORD ); X fillmem( Nextvar->vptr, WORD, 0 ); X } X else X error( "symbol table overflow", MEM_ERROR ); X X return Nextvar++; X} X Xdeclist() X{ X /* X * Parse a "char" or "int" statement. X */ X char type; X X type = Token; X getoken(); X decl( type ); X while ( Token==T_COMMA ) X { X getoken(); X decl( type ); X } X if ( Token==T_SEMICOLON ) X getoken(); X} X XVARIABLE * Xdecl( type ) X{ X /* X * Parse an element of a "char" or "int" declaration list. X * The function stmt_compile() has already entered the variable X * into the symbol table as an integer, this routine simply changes X * the symbol's class, size or length according to the declaraction. X * WARNING: The interpreter depends on the fact that pointers are X * the same length as int's. If your machine uses long's for X * pointers either change the code or #define int long (or whatever). X */ X char class, size; X int len; X unsigned oldsize, newsize; X VARIABLE *pvar; X X if ( Token==T_MUL ) X { X /* X * it's a pointer X */ X getoken(); X pvar = decl( type ); X ++pvar->vclass; X } X else if ( Token==T_VARIABLE ) X { X /* X * Simple variable so far. The token value (in the global X * "Value" variable) is a pointer to the variable's symbol X * table entry. X */ X pvar = Value.dptr; X getoken(); X class = 0; X /* X * Compute its length X */ X if ( Token==T_LBRACKET ) X { X /* X * It's an array. X */ X getoken(); X ++class; X /* X * Compute the dimension X */ X expression(); X if ( Token!=T_RBRACKET ) X error( "missing ']'", ACT_ERROR ); X getoken(); X len = popint(); X } X else X /* X * It's a simple variable - array length is zero. X */ X len = 0; X X size = (type==T_CHAR) ? BYTE : WORD; X X newsize = (len ? len : 1) * size; X oldsize = (pvar->vlen ? pvar->vlen : 1) * pvar->vsize; X if ( newsize != oldsize ) X { X /* X * The amount of storage needed for the variable X * has changed - free up memory allocated initially X * and reallocate for new size. X */ X free( pvar->vptr ); X pvar->vptr = getmem( newsize ); X } X /* X * Now change the variable's attributes. X */ X pvar->vclass = class; X pvar->vsize = size; X pvar->vlen = len; X } X else X syntaxerror(); X X return pvar; X} X Xassignment() X{ X /* X * Perform an assignment X */ X int ival; X X ival = popint(); X /* X * make sure we've got an lvalue X */ X if ( Stackptr->lvalue ) X { X if ( Stackptr->class ) X movemem( &ival, Stackptr->value.dptr, WORD ); X else X movemem(&ival, Stackptr->value.dptr, Stackptr->size); X pop(); X pushint( ival ); X } X else X error( "'=' needs an lvalue", ACT_ERROR ); X} X Xpop() X{ X /* X * Pop the stack and return the integer value X */ X if ( Stackptr >= Stackbtm ) X return (Stackptr--)->value.ival; X return error( "stack underflow", ACT_ERROR ); X} X Xpush( pclass, plvalue, psize, pdatum ) Xchar pclass, plvalue, psize; XDATUM *pdatum; X{ X /* X * Push item parts onto the stack X */ X if ( ++Stackptr <= Stacktop ) X { X Stackptr->lvalue = plvalue; X Stackptr->size = psize; X if ( !(Stackptr->class = pclass) && !plvalue ) X Stackptr->value.ival = pdatum->ival; X else X Stackptr->value.dptr = pdatum->dptr; X } X else X error( "stack overflow", MEM_ERROR ); X} X Xpushint( intvalue ) Xint intvalue; X{ X /* X * push an integer onto the stack X */ X if ( ++Stackptr <= Stacktop ) X { X Stackptr->lvalue = X Stackptr->class = 0; X Stackptr->size = WORD; X Stackptr->value.ival = intvalue; X } X else X error( "stack overflow", MEM_ERROR ); X} X Xpopint() X{ X /* X * Resolve the item on the top of the stack and return it X */ X int intvalue; X X if ( Stackptr->lvalue ) X { X /* X * if it's a byte indirect, sign extend it X */ X if ( Stackptr->size == BYTE && !Stackptr->class ) X intvalue = *Stackptr->value.dptr; X else X { X /* X * otherwise, it's an unsigned int X */ X intvalue = *Stackptr->value.ptrptr; X } X pop(); X return intvalue; X } X else X { X /* X * else it's an ACTUAL, just pop it X */ X return pop(); X } X} + END-OF-FILE bawksym.c chmod 'u=rw,g=r,o=r' 'bawksym.c' set `wc -c 'bawksym.c'` count=$1 case $count in 12636) :;; *) echo 'Bad character count in ''bawksym.c' >&2 echo 'Count should be 12636' >&2 esac exit 0