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