/* * 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 int isfunction( s ) register 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. */ DBUG_ENTER("isfunction"); switch(*s) { case 'g': if ( !strcmp( s, "getline" ) ) DBUG_RETURN(F_GETLINE); break; case 'm': if ( !strcmp( s, "match" ) ) DBUG_RETURN(F_MATCH); break; case 'n': if ( !strcmp( s, "nextfile" ) ) DBUG_RETURN(F_NEXTFILE); break; case 'p': if ( !strcmp( s, "printf" ) ) DBUG_RETURN(F_PRINTF); break; case 's': if ( !strcmp( s, "strlen" ) ) DBUG_RETURN(F_STRLEN); if ( !strcmp( s, "strcpy" ) ) DBUG_RETURN(F_STRCPY); if ( !strcmp( s, "strcmp" ) ) DBUG_RETURN(F_STRCMP); break; case 't': if ( !strcmp( s, "toupper" ) ) DBUG_RETURN(F_TOUPPER); if ( !strcmp( s, "tolower" ) ) DBUG_RETURN(F_TOLOWER); break; default:; } DBUG_RETURN(0); } int iskeyword( s ) register 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. */ DBUG_ENTER("iskeyword"); switch(*s) { case 'b': if ( !strcmp( s, "break" ) ) DBUG_RETURN(T_BREAK); break; case 'c': if ( !strcmp( s, "char" ) ) DBUG_RETURN(T_CHAR); break; case 'e': if ( !strcmp( s, "else" ) ) DBUG_RETURN(T_ELSE); break; case 'i': if ( !strcmp( s, "int" ) ) DBUG_RETURN(T_INT); if ( !strcmp( s, "if" ) ) DBUG_RETURN(T_IF); break; case 'w': if ( !strcmp( s, "while" ) ) DBUG_RETURN(T_WHILE); break; case 'B': if ( !strcmp( s, "BEGIN" ) ) DBUG_RETURN(T_BEGIN); break; case 'E': if ( !strcmp( s, "END" ) ) DBUG_RETURN(T_END); break; case 'F': if ( !strcmp( s, "FS" ) ) DBUG_RETURN(T_FS); if ( !strcmp( s, "FILENAME" ) ) DBUG_RETURN(T_FILENAME); break; case 'N': if ( !strcmp( s, "NF" ) ) DBUG_RETURN(T_NF); if ( !strcmp( s, "NR" ) ) DBUG_RETURN(T_NR); break; case 'R': if ( !strcmp( s, "RS" ) ) DBUG_RETURN(T_RS); break; default:; } DBUG_RETURN(0); } void function( funcnum, arg_root ) register int funcnum; register EXPR_NODE *arg_root; { register int argc, args[ MAXARGS ]; DBUG_ENTER("function"); argc = 0; /* * If there are any arguments, evaluate them and copy their values * to a local array. */ for(; argc < MAXARGS && arg_root; arg_root = arg_root->right) { walk_tree(arg_root->left); args[ argc++ ] = popint(); } switch ( funcnum ) { case F_PRINTF: /* just like the real printf() function */ pushint( printf( (char *) args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9] ) ); break; case F_GETLINE: /* * Get the next line of input from the current input file * and parse according to the current field seperator. * Don't forget to free up the previous line's words first... */ while ( Fieldcount ) free( Fields[ --Fieldcount ] ); pushint( getline() ); Fieldcount = parse( Linebuf, Fields, Fieldsep ); break; case F_STRLEN: /* calculate length of string argument */ pushint( strlen( args[0] ) ); break; case F_STRCPY: /* copy second string argument to first string */ pushint( strcpy( args[0], args[1] ) ); break; case F_STRCMP: /* compare two strings */ pushint( strcmp( args[0], args[1] ) ); break; case F_TOUPPER: /* convert the character argument to upper case */ pushint( toupper( args[0] ) ); break; case F_TOLOWER: /* convert the character argument to lower case */ pushint( tolower( args[0] ) ); break; case F_MATCH: /* match a string argument to a regular expression */ pushint( match( (char *) args[0], (char *) args[1] ) ); break; case F_NEXTFILE:/* close current input file and process next file */ endfile(); pushint( 1 ); /* is this a correct value? jw */ break; default: /* oops! */ error( "bad function call", ACT_ERROR ); } DBUG_VOID_RETURN; } VARIABLE * findvar( s ) register char *s; { /* * Search the symbol table for a variable whose name is "s". */ register VARIABLE *pvar; register int i; register char name[ MAXVARLEN ]; DBUG_ENTER("findvar"); i = 0; while ( i < MAXVARLEN && (isalnum( *s ) || (*s == '_'))) name[i++] = *s++; if ( ivname, name, MAXVARLEN ) ) DBUG_RETURN(pvar); } DBUG_RETURN(NULL); } VARIABLE * addvar( name ) register char *name; { /* * Add a new variable to symbol table and assign it default * attributes (int name;) */ register int i; DBUG_ENTER("addvar"); 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 = get_clear_memory( WORD ); } else error( "symbol table overflow", MEM_ERROR ); DBUG_RETURN(Nextvar++); } EXPR_NODE *declist_parse() { /* * Parse a "char" or "int" statement. */ register char type; register EXPR_NODE *root, *end_pointer; DBUG_ENTER("declist_parse"); type = Token; getoken(); root = end_pointer = decl_parse( type ); while ( Token==T_COMMA ) { getoken(); end_pointer->right = decl_parse( type ); end_pointer = end_pointer->right; } if ( Token==T_SEMICOLON ) getoken(); DBUG_RETURN(root); } EXPR_NODE *decl_parse( type ) register int 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). */ register char class, size; register VARIABLE *pvar; register VARDECL *pdecl; register EXPR_NODE *node; EXPR_NODE *action; DBUG_ENTER("decl_parse"); if ( Token==T_MUL ) { /* * it's a pointer */ getoken(); node = decl_parse( type ); if(node->operator == T_DECLARE) ((VARDECL *) (node->right))->vclass += 1; else ((VARDECL *) (node->right->right))->vclass += 1; } 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. */ pdecl = (VARDECL *) getmemory(sizeof(VARDECL)); pvar = (VARIABLE *) Value.dptr; getoken(); class = 0; /* * Compute its length */ if ( Token==T_LBRACKET ) { /* * It's an array. */ node = get_expr_node((char) T_ARRAY_DECLARE); node->left = action = get_expr_node((char) T_ARRAY_DECLARE); action->left = (EXPR_NODE *) pdecl; getoken(); ++class; /* * Parse the dimension expression */ action->right = expr_parse(); if ( Token!=T_RBRACKET ) error( "missing ']'", ACT_ERROR ); getoken(); } else { /* * It's a simple variable. */ node = get_expr_node((char) T_DECLARE); node->left = (EXPR_NODE *) pdecl; } size = (type==T_CHAR) ? BYTE : WORD; pdecl->variable = pvar; pdecl->vclass = class; pdecl->vsize = size; } else syntaxerror(); DBUG_RETURN(node); } void assignment() { /* * Perform an assignment */ int ival; DBUG_ENTER("assignment"); ival = popint(); /* * make sure we've got an lvalue */ if ( Stackptr->lvalue ) { if ( Stackptr->class ) movmem((char *) &ival, Stackptr->value.dptr, WORD ); else movmem((char *) &ival, Stackptr->value.dptr, Stackptr->size); pop(); pushint( ival ); } else error( "'=' needs an lvalue", ACT_ERROR ); DBUG_VOID_RETURN; } int pop() { /* * Pop the stack and return the integer value */ DBUG_ENTER("pop"); if ( Stackptr >= Stackbtm ) DBUG_RETURN((Stackptr--)->value.ival); DBUG_RETURN(error( "stack underflow", ACT_ERROR )); } void push( pclass, plvalue, psize, pdatum ) register char pclass, plvalue, psize; register DATUM *pdatum; { /* * Push item parts onto the stack */ DBUG_ENTER("push"); 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 ); DBUG_VOID_RETURN; } void pushint( intvalue ) register int intvalue; { /* * push an integer onto the stack */ DBUG_ENTER("pushint"); if ( ++Stackptr <= Stacktop ) { Stackptr->lvalue = Stackptr->class = 0; Stackptr->size = WORD; Stackptr->value.ival = intvalue; } else error( "stack overflow", MEM_ERROR ); DBUG_VOID_RETURN; } int popint() { /* * Resolve the item on the top of the stack and return it */ register int intvalue; DBUG_ENTER("popint"); 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 = (int) (*Stackptr->value.ptrptr); } pop(); DBUG_RETURN(intvalue); } else { /* * else it's an ACTUAL, just pop it */ DBUG_RETURN(pop()); } }