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