home *** CD-ROM | disk | FTP | other *** search
- /*
- * Bawk C actions builtin functions, variable declaration, and
- * stack management routines.
- */
- #include <stdio.h>
- #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 ( i<MAXVARLEN )
- name[i] = 0;
-
- for ( pvar = Vartab; pvar<Nextvar; ++pvar )
- {
- if ( !strncmp( pvar->vname, 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 ( i<MAXVARLEN && (isalnum( *name ) || (*name == '_')))
- Nextvar->vname[i++] = *name++;
- if ( i<MAXVARLEN )
- Nextvar->vname[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());
- }
- }
-
-