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 'Makefile'
sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
X#
X# Makefile for BAWK (MINIX)
X#
X# Makefile @(#)1.1
X#
X
XOPSYS = MINIX
X
XCFLAGS = -D$(OPSYS)
X
XOBJ = bawk.s bawkact.s bawksym.s bawkpat.s bawkdo.s
X
Xbawk: $(OBJ)
X @echo Start linking BAWK
X @cc -i -o bawk $(OBJ)
X @echo BAWK done.
X
Xbawk.s: bawk.h bawk.c
X
Xbawkact.s: bawk.h bawkact.c
X
Xbawkpat.s: bawk.h bawkpat.c
X
Xbawksym.s: bawk.h bawksym.c
X
Xbawkdo.s: bawk.h bawkdo.c
X
+ END-OF-FILE Makefile
chmod 'u=rw,g=,o=' 'Makefile'
set `wc -c 'Makefile'`
count=$1
case $count in
416) :;;
*) echo 'Bad character count in ''Makefile' >&2
echo 'Count should be 416' >&2
esac
echo Extracting 'Crcs'
sed 's/^X//' > 'Crcs' << '+ END-OF-FILE ''Crcs'
X55823 416 Makefile
X32840 19175 bawk.c
X39865 6705 bawk.h
X36860 14754 bawkact.c
X32377 21383 bawkdo.c
X19136 13298 bawkpat.c
X56250 12636 bawksym.c
X18536 28213 x1
+ END-OF-FILE Crcs
chmod 'u=rw,g=r,o=r' 'Crcs'
set `wc -c 'Crcs'`
count=$1
case $count in
169) :;;
*) echo 'Bad character count in ''Crcs' >&2
echo 'Count should be 169' >&2
esac
echo Extracting 'bawk.c'
sed 's/^X//' > 'bawk.c' << '+ END-OF-FILE ''bawk.c'
X/*
X * Bawk main program
X */
X#define MAIN 1
X#include <stdio.h>
X#include "bawk.h"
X
X/*
X * Main program
X */
Xmain( argc, argv )
Xint argc;
Xchar **argv;
X{
X int gotrules, didfile, getstdin;
X
X getstdin =
X didfile =
X gotrules = 0;
X
X /*
X * Initialize global variables:
X */
X Beginact =
X Endact =
X Rules =
X Rulep =
X#ifdef DEBUG
X Debug =
X#endif
X Filename =
X Linecount =
X Saw_break = 0;
X Stackptr = Stackbtm - 1;
X Stacktop = Stackbtm + MAXSTACKSZ;
X Nextvar = Vartab;
X
X strcpy( Fieldsep, " \t" );
X strcpy( Recordsep, "\n" );
X
X /*
X * Parse command line
X */
X while ( --argc )
X {
X if ( **(++argv) == '-' )
X {
X /*
X * Process dash options.
X */
X switch ( tolower( *(++(*argv)) ) )
X {
X#ifdef DEBUG
X case 'd':
X ++Debug;
X break;
X#endif
X case 0:
X ++getstdin;
X --argv;
X goto dosomething;
X break;
X default: usage();
X }
X }
X else
X {
Xdosomething:
X if ( gotrules )
X {
X /*
X * Already read rules file - assume this is
X * is a text file for processing.
X */
X if ( ++didfile == 1 && Beginact )
X doaction( Beginact );
X if ( getstdin )
X {
X --getstdin;
X newfile( 0 );
X }
X else
X newfile( *argv );
X process();
X }
X else
X {
X /*
X * First file name argument on command line
X * is assumed to be a rules file - attempt to
X * compile it.
X */
X if ( getstdin )
X {
X --getstdin;
X newfile( 0 );
X }
X else
X newfile( *argv );
X compile();
X gotrules = 1;
X }
X }
X }
X if ( !gotrules )
X usage();
X
X if ( ! didfile )
X {
X /*
X * Didn't process any files yet - process stdin.
X */
X newfile( 0 );
X if ( Beginact )
X doaction( Beginact );
X process();
X }
X if ( Endact )
X doaction( Endact );
X}
X
X/*
X * Regular expression/action file compilation routines.
X */
Xcompile()
X{
X /*
X * Compile regular expressions and C actions into Rules struct,
X * reading from current input file "Fileptr".
X */
X int c, len;
X
X#ifdef DEBUG
X if ( Debug )
X error( "compiling...", 0 );
X#endif
X
X while ( (c = getcharacter()) != -1 )
X {
X if ( c==' ' || c=='\t' || c=='\n' )
X /* swallow whitespace */
X ;
X else if ( c=='#' )
X {
X /*
X * Swallow comments
X */
X while ( (c=getcharacter()) != -1 && c!='\n' )
X ;
X }
X else if ( c=='{' )
X {
X#ifdef DEBUG
X if ( Debug )
X error( "action", 0 );
X#endif
X /*
X * Compile (tokenize) the action string into our
X * global work buffer, then allocate some memory
X * for it and copy it over.
X */
X ungetcharacter( '{' );
X len = act_compile( Workbuf );
X
X if ( Rulep && Rulep->action )
X {
X Rulep->nextrule = getmem( sizeof( *Rulep ) );
X Rulep = Rulep->nextrule;
X fillmem( Rulep, sizeof( *Rulep ), 0 );
X }
X if ( !Rulep )
X {
X /*
X * This is the first action encountered.
X * Allocate the first Rules structure and
X * initialize it
X */
X Rules = Rulep = getmem( sizeof( *Rulep ) );
X fillmem( Rulep, sizeof( *Rulep ), 0 );
X }
X Rulep->action = getmem( len );
X movemem( Workbuf, Rulep->action, len );
X }
X else if ( c==',' )
X {
X#ifdef DEBUG
X if ( Debug )
X error( "stop pattern", 0 );
X#endif
X /*
X * It's (hopefully) the second part of a two-part
X * pattern string. Swallow the comma and start
X * compiling an action string.
X */
X if ( !Rulep || !Rulep->pattern.start )
X error( "stop pattern without a start",
X RE_ERROR );
X if ( Rulep->pattern.stop )
X error( "already have a stop pattern",
X RE_ERROR );
X len = pat_compile( Workbuf );
X Rulep->pattern.stop = getmem( len );
X movemem( Workbuf, Rulep->pattern.stop, len );
X }
X else
X {
X /*
X * Assume it's a regular expression pattern
X */
X#ifdef DEBUG
X if ( Debug )
X error( "start pattern", 0 );
X#endif
X
X ungetcharacter( c );
X len = pat_compile( Workbuf );
X
X if ( *Workbuf == T_BEGIN )
X {
X /*
X * Saw a "BEGIN" keyword - compile following
X * action into special "Beginact" buffer.
X */
X len = act_compile( Workbuf );
X Beginact = getmem( len );
X movemem( Workbuf, Beginact, len );
X continue;
X }
X if ( *Workbuf == T_END )
X {
X /*
X * Saw an "END" keyword - compile following
X * action into special "Endact" buffer.
X */
X len = act_compile( Workbuf );
X Endact = getmem( len );
X movemem( Workbuf, Endact, len );
X continue;
X }
X if ( Rulep )
X {
X /*
X * Already saw a pattern/action - link in
X * another Rules structure.
X */
X Rulep->nextrule = getmem( sizeof( *Rulep ) );
X Rulep = Rulep->nextrule;
X fillmem( Rulep, sizeof( *Rulep ), 0 );
X }
X if ( !Rulep )
X {
X /*
X * This is the first pattern encountered.
X * Allocate the first Rules structure and
X * initialize it
X */
X Rules = Rulep = getmem( sizeof( *Rulep ) );
X fillmem( Rulep, sizeof( *Rulep ), 0 );
X }
X if ( Rulep->pattern.start )
X error( "already have a start pattern",
X RE_ERROR );
X
X Rulep->pattern.start = getmem( len );
X movemem( Workbuf, Rulep->pattern.start, len );
X }
X }
X endfile();
X}
X
X/*
X * Text file main processing loop.
X */
Xprocess()
X{
X /*
X * Read a line at a time from current input file at "Fileptr",
X * then apply each rule in the Rules chain to the input line.
X */
X int i;
X
X#ifdef DEBUG
X if ( Debug )
X error( "processing...", 0 );
X#endif
X
X Recordcount = 0;
X
X while ( getline() )
X {
X /*
X * Parse the input line.
X */
X Fieldcount = parse( Linebuf, Fields, Fieldsep );
X#ifdef DEBUG
X if ( Debug>1 )
X {
X printf( "parsed %d words:\n", Fieldcount );
X for(i=0; i<Fieldcount; ++i )
X printf( "<%s>\n", Fields[i] );
X }
X#endif
X
X Rulep = Rules;
X do
X {
X if ( ! Rulep->pattern.start )
X {
X /*
X * No pattern given - perform action on
X * every input line.
X */
X doaction( Rulep->action );
X }
X else if ( Rulep->pattern.startseen )
X {
X /*
X * Start pattern already found - perform
X * action then check if line matches
X * stop pattern.
X */
X doaction( Rulep->action );
X if ( dopattern( Rulep->pattern.stop ) )
X Rulep->pattern.startseen = 0;
X }
X else if ( dopattern( Rulep->pattern.start ) )
X {
X /*
X * Matched start pattern - perform action.
X * If a stop pattern was given, set "start
X * pattern seen" flag and process every input
X * line until stop pattern found.
X */
X doaction( Rulep->action );
X if ( Rulep->pattern.stop )
X Rulep->pattern.startseen = 1;
X }
X }
X while ( Rulep = Rulep->nextrule );
X
X /*
X * Release memory allocated by parse().
X */
X while ( Fieldcount )
X free( Fields[ --Fieldcount ] );
X }
X}
X
X/*
X * Miscellaneous functions
X */
Xparse( str, wrdlst, delim )
Xchar *str;
Xchar *wrdlst[];
Xchar *delim;
X{
X /*
X * Parse the string of words in "str" into the word list at "wrdlst".
X * A "word" is a sequence of characters delimited by one or more
X * of the characters found in the string "delim".
X * Returns the number of words parsed.
X * CAUTION: the memory for the words in "wrdlst" is allocated
X * by malloc() and should eventually be returned by free()...
X */
X int wrdcnt, wrdlen;
X char wrdbuf[ MAXLINELEN ], c;
X
X wrdcnt = 0;
X while ( *str )
X {
X while ( instr( *str, delim ) )
X ++str;
X if ( !*str )
X break;
X wrdlen = 0;
X while ( (c = *str) && !instr( c, delim ) )
X {
X wrdbuf[ wrdlen++ ] = c;
X ++str;
X }
X wrdbuf[ wrdlen++ ] = 0;
X /*
X * NOTE: allocate a MAXLINELEN sized buffer for every
X * word, just in case user wants to copy a larger string
X * into a field.
X */
X wrdlst[ wrdcnt ] = getmem( MAXLINELEN );
X strcpy( wrdlst[ wrdcnt++ ], wrdbuf );
X }
X
X return wrdcnt;
X}
X
Xunparse( wrdlst, wrdcnt, str, delim )
Xchar *wrdlst[];
Xint wrdcnt;
Xchar *str;
Xchar *delim;
X{
X /*
X * Replace all the words in "str" with the words in "wrdlst",
X * maintaining the same word seperation distance as found in
X * the string.
X * A "word" is a sequence of characters delimited by one or more
X * of the characters found in the string "delim".
X */
X int wc;
X char strbuf[ MAXLINELEN ], *sp, *wp, *start;
X
X wc = 0; /* next word in "wrdlst" */
X sp = strbuf; /* points to our local string */
X start = str; /* save start address of "str" for later... */
X while ( *str )
X {
X /*
X * Copy the field delimiters from the original string to
X * our local version.
X */
X while ( instr( *str, delim ) )
X *sp++ = *str++;
X if ( !*str )
X break;
X /*
X * Skip over the field in the original string and...
X */
X while ( *str && !instr( *str, delim ) )
X ++str;
X
X if ( wc < wrdcnt )
X {
X /*
X * ...copy in the field in the wordlist instead.
X */
X wp = wrdlst[ wc++ ];
X while ( *wp )
X *sp++ = *wp++;
X }
X }
X /*
X * Tie off the local string, then copy it back to caller's string.
X */
X *sp = 0;
X strcpy( start, strbuf );
X}
X
Xinstr( c, s )
Xchar c, *s;
X{
X while ( *s )
X if ( c==*s++ )
X return 1;
X return 0;
X}
X
Xchar *
Xgetmem( len )
Xunsigned len;
X{
X char *cp;
X
X if ( cp=malloc( len ) )
X return cp;
X error( "out of memory", MEM_ERROR );
X}
X
Xchar *
Xnewfile( s )
Xchar *s;
X{
X Linecount = 0;
X if ( Filename = s )
X {
X#ifdef BDS_C
X if ( fopen( s, Fileptr = Curfbuf ) == -1 )
X#else
X if ( !(Fileptr = fopen( s, "r" )) )
X#endif
X error( "file not found", FILE_ERROR );
X }
X else
X {
X /*
X * No file name given - process standard input.
X */
X Fileptr = stdin;
X Filename = "standard input";
X }
X}
X
Xgetline()
X{
X /*
X * Read a line of text from current input file. Strip off
X * trailing record seperator (newline).
X */
X int rtn, len;
X
X for ( len=0; len<MAXLINELEN; ++len )
X {
X if ( (rtn = getcharacter()) == *Recordsep || rtn == -1 )
X break;
X Linebuf[ len ] = rtn;
X }
X Linebuf[ len ] = 0;
X
X if ( rtn == -1 )
X {
X endfile();
X return 0;
X }
X return 1;
X}
X
Xgetcharacter()
X{
X /*
X * Read a character from curren input file.
X * WARNING: your getc() must convert lines that end with CR+LF
X * to LF and CP/M's EOF character (^Z) to a -1.
X * Also, getc() must return a -1 when attempting to read from
X * an unopened file.
X */
X int c;
X
X#ifdef BDS_C
X /*
X * BDS C doesn't do CR+LF to LF and ^Z to -1 conversions <gag>
X */
X if ( (c = getc( Fileptr )) == '\r' )
X {
X if ( (c = getc( Fileptr )) != '\n' )
X {
X ungetc( c );
X c = '\r';
X }
X }
X else if ( c == 26 ) /* ^Z */
X c = -1;
X#else
X c = getc( Fileptr );
X#endif
X
X if ( c == *Recordsep )
X ++Recordcount;
X if ( c=='\n' )
X ++Linecount;
X
X return c;
X}
X
Xungetcharacter( c )
X{
X /*
X * Push a character back into the input stream.
X * If the character is a record seperator, or a newline character,
X * the record and line counters are adjusted appropriately.
X */
X if ( c == *Recordsep )
X --Recordcount;
X if ( c=='\n' )
X --Linecount;
X return ungetc( c, Fileptr );
X}
X
Xendfile()
X{
X fclose( Fileptr );
X Filename = Linecount = 0;
X}
X
Xerror( s, severe )
Xchar *s;
Xint severe;
X{
X char *cp, *errat;
X
X if ( Filename )
X fprintf( stderr, "%s:", Filename );
X
X if ( Linecount )
X fprintf( stderr, " line %d:", Linecount );
X
X fprintf( stderr, " %s\n", s );
X if ( severe )
X exit( severe );
X}
X
Xusage()
X{
X error( "Usage: bawk <actfile> [<file> ...]\n", USAGE_ERROR );
X}
X
Xmovemem( from, to, count )
Xchar *from, *to;
Xint count;
X{
X while ( count-- > 0 )
X *to++ = *from++;
X}
X
Xfillmem( array, count, value )
Xchar *array, value;
Xint count;
X{
X while ( count-- > 0 )
X *array++ = value;
X}
X
Xstrncmp( s, t, n )
Xchar *s, *t;
Xint n;
X{
X while ( --n>0 && *s && *t && *s==*t )
X {
X ++s;
X ++t;
X }
X if ( *s || *t )
X return *s - *t;
X return 0;
X}
X
Xnum( c )
Xchar c;
X{
X return '0'<=c && c<='9';
X}
X
Xalpha( c )
Xchar c;
X{
X return ('a'<=c && c<='z') || ('A'<=c && c<='Z') || c=='_';
X}
X
Xalphanum( c )
Xchar c;
X{
X return alpha( c ) || num( c );
X}
+ END-OF-FILE bawk.c
chmod 'u=rw,g=r,o=r' 'bawk.c'
set `wc -c 'bawk.c'`
count=$1
case $count in
19175) :;;
*) echo 'Bad character count in ''bawk.c' >&2
echo 'Count should be 19175' >&2
esac
echo Extracting 'bawk.h'
sed 's/^X//' > 'bawk.h' << '+ END-OF-FILE ''bawk.h'
X/*
X * Bawk constants and variable declarations.
X */
X#ifdef MAIN
X# define EXTERN
X#else
X# define EXTERN extern
X#endif
X
X/*#define DEBUG 1 remove this line to compile without debug statements */
X#ifdef DEBUG
XEXTERN char Debug; /* debug print flag */
X#endif
X
X/*
X * Table and buffer sizes
X */
X#define MAXLINELEN 128 /* longest input line */
X#define MAXWORDS (MAXLINELEN/2) /* max # of words in a line */
X#define MAXWORKBUFLEN 4096 /* longest action or regular expression */
X#define MAXVARTABSZ 50 /* max # of symbols */
X#define MAXVARLEN 10 /* symbol name length */
X#define MAXSTACKSZ 40 /* max value stack length (for expressions) */
X
X
X/**********************************************************
X * Current Input File variables *
X **********************************************************/
X/*
X * Current Input File pointer:
X */
XEXTERN FILE *Fileptr;
XEXTERN char *Filename; /* current input file name */
XEXTERN int Linecount; /* current input line number */
XEXTERN int Recordcount; /* record count */
X/*
X * Working buffers.
X */
XEXTERN char Linebuf[ MAXLINELEN ]; /* current input line buffer */
XEXTERN char *Fields[ MAXWORDS ]; /* pointers to the words in Linebuf */
XEXTERN int Fieldcount; /* and the # of words */
XEXTERN char Workbuf[ MAXWORKBUFLEN ]; /* work area for C action and */
X /* regular expression parsers */
X
X/**********************************************************
X * Regular Expression Parser variables *
X **********************************************************/
X/*
X * Tokens:
X */
X#define CHAR 1
X#define BOL 2
X#define EOL 3
X#define ANY 4
X#define CLASS 5
X#define NCLASS 6
X#define STAR 7
X#define PLUS 8
X#define MINUS 9
X#define ALPHA 10
X#define DIGIT 11
X#define NALPHA 12
X#define PUNCT 13
X#define RANGE 14
X#define ENDPAT 15
X
X
X/**********************************************************
X * C Actions Interpreter variables *
X **********************************************************/
X/*
X * Tokens:
X */
X#define T_STRING 'S' /* primaries: */
X#define T_DOLLAR '$'
X#define T_REGEXP 'r'
X#define T_CONSTANT 'C'
X#define T_VARIABLE 'V'
X#define T_FUNCTION 'F'
X#define T_SEMICOLON ';' /* punctuation */
X#define T_EOF 'Z'
X#define T_LBRACE '{'
X#define T_RBRACE '}'
X#define T_LPAREN '('
X#define T_RPAREN ')'
X#define T_LBRACKET '['
X#define T_RBRACKET ']'
X#define T_COMMA ','
X#define T_ASSIGN '=' /* operators: */
X#define T_MUL '*'
X#define T_DIV '/'
X#define T_MOD '%'
X#define T_ADD '+'
X#define T_SUB '-'
X#define T_SHL 'L'
X#define T_SHR 'R'
X#define T_LT '<'
X#define T_LE 'l'
X#define T_GT '>'
X#define T_GE 'g'
X#define T_EQ 'q'
X#define T_NE 'n'
X#define T_NOT '~'
X#define T_AND '&'
X#define T_XOR '^'
X#define T_IOR '|'
X#define T_LNOT '!'
X#define T_LAND 'a'
X#define T_LIOR 'o'
X#define T_INCR 'p'
X#define T_DECR 'm'
X#define T_IF 'i' /* keywords: */
X#define T_ELSE 'e'
X#define T_WHILE 'w'
X#define T_BREAK 'b'
X#define T_CHAR 'c'
X#define T_INT 't'
X#define T_BEGIN 'B'
X#define T_END 'E'
X#define T_NF 'f'
X#define T_NR '#'
X#define T_FS ' '
X#define T_RS '\n'
X#define T_FILENAME 'z'
X
X#define PATTERN 'P' /* indicates C statement is within a pattern */
X#define ACTION 'A' /* indicates C statement is within an action */
X
X/*
X * Symbol Table values
X */
X#define ACTUAL 0
X#define LVALUE 1
X#define BYTE 1
X#define WORD 2
X/*
X * Symbol table
X */
Xstruct variable {
X char vname[ MAXVARLEN ];
X char vclass;
X char vsize;
X int vlen;
X char *vptr;
X};
X#define VARIABLE struct variable
XEXTERN VARIABLE Vartab[ MAXVARTABSZ ], *Nextvar;
X/*
X * Value stack
X */
Xunion datum {
X int ival;
X char *dptr;
X char **ptrptr;
X};
X#define DATUM union datum
Xstruct item {
X char class;
X char lvalue;
X char size;
X DATUM value;
X};
X#define ITEM struct item
XEXTERN ITEM Stackbtm[ MAXSTACKSZ ], *Stackptr, *Stacktop;
X/*
X * Miscellaneous
X */
XEXTERN char *Actptr; /* pointer into Workbuf during compilation */
XEXTERN char Token; /* current input token */
XEXTERN DATUM Value; /* and its value */
XEXTERN char Saw_break; /* set when break stmt seen */
XEXTERN char Where; /* indicates whether C stmt is a PATTERN or ACTION */
XEXTERN char Fieldsep[3]; /* field seperator */
XEXTERN char Recordsep[3]; /* record seperator */
XEXTERN char *Beginact; /* BEGINning of input actions */
XEXTERN char *Endact; /* END of input actions */
X
X/**********************************************************
X * Rules structure *
X **********************************************************/
Xstruct rule {
X struct {
X char *start; /* C statements that match pattern start */
X char *stop; /* C statements that match pattern end */
X char startseen; /* set if both a start and stop pattern */
X /* given and if an input line matched the */
X /* start pattern */
X } pattern;
X char *action; /* contains quasi-C statements of actions */
X struct rule *nextrule; /* pointer to next rule */
X};
X#define RULE struct rule
XEXTERN RULE *Rules, /* rule structures linked list head */
X *Rulep; /* working pointer */
X
X
X/**********************************************************
X * Miscellaneous *
X **********************************************************/
X/*
X * Error exit values (returned to command shell)
X */
X#define USAGE_ERROR 1 /* error in invokation */
X#define FILE_ERROR 2 /* file not found errors */
X#define RE_ERROR 3 /* bad regular expression */
X#define ACT_ERROR 4 /* bad C action stmt */
X#define MEM_ERROR 5 /* out of memory errors */
X/*
X * Functions that return something special:
X */
Xextern char *str_compile(), *getmem(), *cclass(), *pmatch(), *fetchptr();
Xextern VARIABLE *findvar(), *addvar(), *decl();
Xextern char *newfile();
+ END-OF-FILE bawk.h
chmod 'u=rw,g=r,o=r' 'bawk.h'
set `wc -c 'bawk.h'`
count=$1
case $count in
6705) :;;
*) echo 'Bad character count in ''bawk.h' >&2
echo 'Count should be 6705' >&2
esac
echo Extracting 'bawkact.c'
sed 's/^X//' > 'bawkact.c' << '+ END-OF-FILE ''bawkact.c'
X/*
X * Bawk C actions compiler
X */
X#include <stdio.h>
X#include "bawk.h"
X
Xact_compile( actbuf )
Xchar *actbuf; /* where tokenized actions are compiled into */
X{
X Where = ACTION;
X return stmt_compile( actbuf );
X}
X
Xpat_compile( actbuf )
Xchar *actbuf; /* where tokenized actions are compiled into */
X{
X Where = PATTERN;
X return stmt_compile( actbuf );
X}
X
Xstmt_compile( actbuf )
Xchar *actbuf; /* where tokenized actions are compiled into */
X{
X /*
X * Read and tokenize C actions from current input file into the
X * action buffer. Strip out comments and whitespace in the
X * process.
X */
X char *actptr, /* actbuf pointer */
X *cp, /* work pointer */
X buf[MAXLINELEN];/* string buffer */
X int braces, /* counts '{}' pairs - return when 0 */
X parens, /* counts '()' pairs */
X i, /* temp */
X c; /* current input character */
X
X braces = parens = 0;
X actptr = actbuf;
X while ( (c = getcharacter()) != -1 )
X {
X /*
X * Skip over spaces, tabs and newlines
X */
X if ( c==' ' || c=='\t' || c=='\n' )
X continue;
X if ( c=='#' )
X {
X /*
X * Skip comments. Comments start with a '#' and
X * end at the next newline.
X */
X while ( (c = getcharacter()) != -1 && c!='\n' )
X ;
X continue;
X }
X
X if ( c=='{' )
X {
X if ( Where==PATTERN )
X {
X /*
X * We're compiling a pattern. The '{' marks
X * the beginning of an action statement.
X * Push the character back and return.
X */
X ungetcharacter( '{' );
X break;
X }
X else
X {
X /*
X * We must be compiling an action statement.
X * '{'s mark beginning of action or compound
X * statements.
X */
X ++braces;
X *actptr++ = T_LBRACE;
X }
X }
X else if ( c=='}' )
X {
X *actptr++ = T_RBRACE;
X if ( ! --braces )
X /*
X * Found the end of the action string
X */
X break;
X }
X else if ( c=='(' )
X {
X ++parens;
X *actptr++ = T_LPAREN;
X }
X else if ( c==')' )
X {
X if ( --parens < 0 )
X error( "mismatched '()'", ACT_ERROR );
X *actptr++ = T_RPAREN;
X }
X else if ( c==',' && !braces && !parens && Where==PATTERN )
X {
X /*
X * found a comma outside of any braces or parens-
X * this must be a regular expression seperator.
X */
X ungetcharacter( ',' );
X break;
X }
X
X /*
X * Check if it's a regular expression:
X */
X else if ( c=='/' )
X {
X /*
X * A '/' inside a pattern string starts a regular
X * expression. Inside action strings, a '/' is
X * the division operator.
X */
X if ( Where == PATTERN )
X goto dopattern;
X else
X *actptr++ = T_DIV;
X }
X else if ( c=='@' )
X {
Xdopattern:
X /*
X * Within action strings, only the '@' may be used to
X * delimit regular expressions
X */
X *actptr++ = T_REGEXP;
X ungetcharacter( c );
X actptr += re_compile( actptr );
X }
X
X /*
X * symbol, string or constant:
X */
X else if ( alpha( c ) )
X {
X /*
X * It's a symbol reference. Copy the symbol into
X * string buffer.
X */
X cp = buf;
X do
X *cp++ = c;
X while ( (c=getcharacter()) != -1 && alphanum( c ) );
X ungetcharacter( c );
X *cp = 0;
X /*
X * Check if a keyword, builtin function or variable.
X */
X if ( c = iskeyword( buf ) )
X *actptr++ = c;
X else if ( i = isfunction( buf ) )
X {
X *actptr++ = T_FUNCTION;
X storeint( actptr, i );
X actptr += sizeof( i );
X }
X else
X {
X /*
X * It's a symbol name.
X */
X *actptr++ = T_VARIABLE;
X if ( !(cp = findvar( buf )) )
X cp = addvar( buf );
X storeptr( actptr, cp );
X actptr += sizeof( cp );
X }
X }
X
X else if ( c == '"' )
X {
X /*
X * It's a string constant
X */
X *actptr++ = T_STRING;
X actptr = str_compile( actptr, '"' );
X }
X else if ( c == '\'' )
X {
X /*
X * It's a character constant
X */
X *actptr++ = T_CONSTANT;
X str_compile( buf, '\'' );
X storeint( actptr, *buf );
X actptr += sizeof( i );
X }
X
X else if ( num( c ) )
X {
X /*
X * It's a numeric constant
X */
X *actptr++ = T_CONSTANT;
X cp = buf;
X do
X *cp++ = c;
X while ( (c=getcharacter()) != -1 && num(c) );
X ungetcharacter( c );
X *cp = 0;
X storeint( actptr, atoi( buf ) );
X actptr += sizeof( i );
X }
X
X /*
X * unary operator:
X */
X else if ( c == '$' )
X *actptr++ = T_DOLLAR;
X
X /*
X * or binary operator:
X */
X else if ( c == '=' )
X {
X if ( (c=getcharacter()) == '=' )
X *actptr++ = T_EQ;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_ASSIGN;
X }
X }
X
X else if ( c == '!' )
X {
X if ( (c=getcharacter()) == '=' )
X *actptr++ = T_NE;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_LNOT;
X }
X }
X
X else if ( c == '<' )
X {
X if ( (c=getcharacter()) == '<' )
X *actptr++ = T_SHL;
X else if ( c == '=' )
X *actptr++ = T_LE;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_LT;
X }
X }
X
X else if ( c == '>' )
X {
X if ( (c=getcharacter()) == '>' )
X *actptr++ = T_SHR;
X else if ( c == '=' )
X *actptr++ = T_GE;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_GT;
X }
X }
X
X else if ( c == '&' )
X {
X if ( (c=getcharacter()) == '&' )
X *actptr++ = T_LAND;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_AND;
X }
X }
X
X else if ( c == '|' )
X {
X if ( (c=getcharacter()) == '|' )
X *actptr++ = T_LIOR;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_IOR;
X }
X }
X else if ( c == '+' )
X {
X if ( (c=getcharacter()) == '+' )
X *actptr++ = T_INCR;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_ADD;
X }
X }
X
X else if ( c == '-' )
X {
X if ( (c=getcharacter()) == '-' )
X *actptr++ = T_DECR;
X else
X {
X ungetcharacter( c );
X *actptr++ = T_SUB;
X }
X }
X
X /*
X * punctuation
X */
X else if ( instr( c, "[](),;*/%+-^~" ) )
X *actptr++ = c;
X
X else
X {
X /*
X * Bad character in input line
X */
X error( "lexical error", ACT_ERROR );
X }
X
X if ( actptr >= Workbuf + MAXWORKBUFLEN )
X error( "action too long", MEM_ERROR );
X }
X if ( braces || parens )
X error( "mismatched '{}' or '()'", ACT_ERROR );
X
X *actptr++ = T_EOF;
X
X return actptr - actbuf;
X}
X
X/* FIX FvK: was INT */
Xchar *str_compile( str, delim )
Xchar *str, delim;
X{
X /*
X * Compile a string from current input file into the given string
X * buffer. Stop when input character is the delimiter in "delim".
X * Returns a pointer to the first character after the string.
X */
X int c;
X char buf[ MAXLINELEN ];
X
X while ( (c = getcharacter()) != -1 && c != delim)
X {
X if ( c == '\\' )
X {
X switch ( c = getcharacter() )
X {
X case -1: goto err;
X case 'b': c = '\b'; break;
X case 'n': c = '\n'; break;
X case 't': c = '\t'; break;
X case 'f': c = '\f'; break;
X case 'r': c = '\r'; break;
X case '0':
X case '1':
X case '2':
X case '3':
X *buf = c;
X for ( c=1; c<3; ++c )
X {
X if ( (buf[c]=getcharacter()) == -1 )
X goto err;
X }
X buf[c] = 0;
X sscanf( buf, "%o", &c );
X break;
X case '\n':
X if ( getcharacter() == -1 )
X goto err;
X default:
X if ( (c = getcharacter()) == -1 )
X goto err;
X }
X }
X *str++ = c;
X }
X *str++ = 0;
X
X return str;
Xerr:
X sprintf( buf, "missing %c delimiter", delim );
X error( buf, 4 );
X}
X
Xstoreint( ip, i )
Xint *ip, i;
X{
X return *ip = i;
X}
X
Xstoreptr( pp, p )
Xchar **pp, *p;
X{
X return *pp = p;
X}
X
Xfetchint( ip )
Xint *ip;
X{
X return *ip;
X}
X
Xchar *
Xfetchptr( pp )
Xchar **pp;
X{
X return *pp;
X}
X
Xgetoken()
X{
X char *cp;
X int i;
X
X switch ( Token = *Actptr++ )
X {
X case T_STRING:
X case T_REGEXP:
X Value.dptr = Actptr;
X Actptr += strlen( Actptr ) + 1;
X break;
X case T_VARIABLE:
X Value.dptr = fetchptr( Actptr );
X Actptr += sizeof( cp );
X break;
X case T_FUNCTION:
X case T_CONSTANT:
X Value.ival = fetchint( Actptr );
X Actptr += sizeof( i );
X break;
X case T_EOF:
X --Actptr;
X default:
X Value.dptr = 0;
X }
X
X#ifdef DEBUG
X if ( Debug > 1 )
X printf( "Token='%c' (0x%x), Value=%d\n",
X Token,Token,Value.ival );
X#endif
X
X return Token;
X}
+ END-OF-FILE bawkact.c
chmod 'u=rw,g=r,o=r' 'bawkact.c'
set `wc -c 'bawkact.c'`
count=$1
case $count in
14754) :;;
*) echo 'Bad character count in ''bawkact.c' >&2
echo 'Count should be 14754' >&2
esac
exit 0