/* * Bawk C actions builtin functions, variable declaration, and * stack management routines. */ #include #include "bawk.h" #define MAXARGS 10 /* max # of arguments to a builtin func */ #define F_PRINTF 1 #define F_GETLINE 2 #define F_STRLEN 3 #define F_STRCPY 4 #define F_STRCMP 5 #define F_TOUPPER 6 #define F_TOLOWER 7 #define F_MATCH 8 #define F_NEXTFILE 9 isfunction( s ) char *s; { /* * Compare the string "s" to a list of builtin functions * and return its (non-zero) token number. * Return zero if "s" is not a function. */ if ( !strcmp( s, "printf" ) ) return F_PRINTF; if ( !strcmp( s, "getline" ) ) return F_GETLINE; if ( !strcmp( s, "strlen" ) ) return F_STRLEN; if ( !strcmp( s, "strcpy" ) ) return F_STRCPY; if ( !strcmp( s, "strcmp" ) ) return F_STRCMP; if ( !strcmp( s, "toupper" ) ) return F_TOUPPER; if ( !strcmp( s, "tolower" ) ) return F_TOLOWER; if ( !strcmp( s, "match" ) ) return F_MATCH; if ( !strcmp( s, "nextfile" ) ) return F_NEXTFILE; return 0; } iskeyword( s ) char *s; { /* * Compare the string "s" to a list of keywords and return its * (non-zero) token number. Return zero if "s" is not a keyword. */ if ( !strcmp( s, "char" ) ) return T_CHAR; if ( !strcmp( s, "int" ) ) return T_INT; if ( !strcmp( s, "if" ) ) return T_IF; if ( !strcmp( s, "else" ) ) return T_ELSE; if ( !strcmp( s, "while" ) ) return T_WHILE; if ( !strcmp( s, "break" ) ) return T_BREAK; if ( !strcmp( s, "NF" ) ) return T_NF; if ( !strcmp( s, "NR" ) ) return T_NR; if ( !strcmp( s, "FS" ) ) return T_FS; if ( !strcmp( s, "RS" ) ) return T_RS; if ( !strcmp( s, "FILENAME" ) ) return T_FILENAME; if ( !strcmp( s, "BEGIN" ) ) return T_BEGIN; if ( !strcmp( s, "END" ) ) return T_END; return 0; } function( funcnum ) { int argc, args[ MAXARGS ]; char lpar; argc = 0; if ( Token==T_LPAREN ) { lpar = 1; getoken(); } else lpar = 0; /* * If there are any arguments, evaluate them and copy their values * to a local array. */ if ( Token!=T_RPAREN && Token!=T_EOF ) { for ( ;; ) { expression(); if ( argcvname, name, MAXVARLEN ) ) return pvar; } return NULL; } VARIABLE * addvar( name ) char *name; { /* * Add a new variable to symbol table and assign it default * attributes (int name;) */ int i; if ( Nextvar <= Vartab + MAXVARTABSZ ) { i = 0; while ( ivname[i++] = *name++; if ( ivname[i] = 0; Nextvar->vclass = 0; Nextvar->vsize = WORD; Nextvar->vlen = 0; /* * Allocate some new room */ Nextvar->vptr = getmem( WORD ); fillmem( Nextvar->vptr, WORD, 0 ); } else error( "symbol table overflow", MEM_ERROR ); return Nextvar++; } declist() { /* * Parse a "char" or "int" statement. */ char type; type = Token; getoken(); decl( type ); while ( Token==T_COMMA ) { getoken(); decl( type ); } if ( Token==T_SEMICOLON ) getoken(); } VARIABLE * decl( type ) { /* * Parse an element of a "char" or "int" declaration list. * The function stmt_compile() has already entered the variable * into the symbol table as an integer, this routine simply changes * the symbol's class, size or length according to the declaraction. * WARNING: The interpreter depends on the fact that pointers are * the same length as int's. If your machine uses long's for * pointers either change the code or #define int long (or whatever). */ char class, size; int len; unsigned oldsize, newsize; VARIABLE *pvar; if ( Token==T_MUL ) { /* * it's a pointer */ getoken(); pvar = decl( type ); ++pvar->vclass; } else if ( Token==T_VARIABLE ) { /* * Simple variable so far. The token value (in the global * "Value" variable) is a pointer to the variable's symbol * table entry. */ pvar = Value.dptr; getoken(); class = 0; /* * Compute its length */ if ( Token==T_LBRACKET ) { /* * It's an array. */ getoken(); ++class; /* * Compute the dimension */ expression(); if ( Token!=T_RBRACKET ) error( "missing ']'", ACT_ERROR ); getoken(); len = popint(); } else /* * It's a simple variable - array length is zero. */ len = 0; size = (type==T_CHAR) ? BYTE : WORD; newsize = (len ? len : 1) * size; oldsize = (pvar->vlen ? pvar->vlen : 1) * pvar->vsize; if ( newsize != oldsize ) { /* * The amount of storage needed for the variable * has changed - free up memory allocated initially * and reallocate for new size. */ free( pvar->vptr ); pvar->vptr = getmem( newsize ); } /* * Now change the variable's attributes. */ pvar->vclass = class; pvar->vsize = size; pvar->vlen = len; } else syntaxerror(); return pvar; } assignment() { /* * Perform an assignment */ int ival; ival = popint(); /* * make sure we've got an lvalue */ if ( Stackptr->lvalue ) { if ( Stackptr->class ) movemem( &ival, Stackptr->value.dptr, WORD ); else movemem(&ival, Stackptr->value.dptr, Stackptr->size); pop(); pushint( ival ); } else error( "'=' needs an lvalue", ACT_ERROR ); } pop() { /* * Pop the stack and return the integer value */ if ( Stackptr >= Stackbtm ) return (Stackptr--)->value.ival; return error( "stack underflow", ACT_ERROR ); } push( pclass, plvalue, psize, pdatum ) char pclass, plvalue, psize; DATUM *pdatum; { /* * Push item parts onto the stack */ if ( ++Stackptr <= Stacktop ) { Stackptr->lvalue = plvalue; Stackptr->size = psize; if ( !(Stackptr->class = pclass) && !plvalue ) Stackptr->value.ival = pdatum->ival; else Stackptr->value.dptr = pdatum->dptr; } else error( "stack overflow", MEM_ERROR ); } pushint( intvalue ) int intvalue; { /* * push an integer onto the stack */ if ( ++Stackptr <= Stacktop ) { Stackptr->lvalue = Stackptr->class = 0; Stackptr->size = WORD; Stackptr->value.ival = intvalue; } else error( "stack overflow", MEM_ERROR ); } popint() { /* * Resolve the item on the top of the stack and return it */ int intvalue; if ( Stackptr->lvalue ) { /* * if it's a byte indirect, sign extend it */ if ( Stackptr->size == BYTE && !Stackptr->class ) intvalue = *Stackptr->value.dptr; else { /* * otherwise, it's an unsigned int */ intvalue = *Stackptr->value.ptrptr; } pop(); return intvalue; } else { /* * else it's an ACTUAL, just pop it */ return pop(); } }