[comp.os.minix] Bawk, part 1 of 2

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