Minix1.5/commands/bawk/bawksym.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Bawk C actions builtin functions, variable declaration, and
 * stack management routines.
 */
#include <ctype.h>
#include <stdio.h>
#include "bawk.h"

#define MAXARGS         10      /* max # of arguments to a builtin func */
#define F_PRINT         1
#define F_PRINTF        2
#define F_GETLINE       3
#define F_STRLEN        4
#define F_STRCPY        5
#define F_STRCMP        6
#define F_TOUPPER       7
#define F_TOLOWER       8
#define F_MATCH         9
#define F_NEXTFILE      10

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, "print") )
                return F_PRINT;
        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, j;
        char lpar;
        DATUM args[ MAXARGS ];

        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.  Clear the array first.
         */

        for (j = 0; j < MAXARGS; j++) args[j].ival = 0;

        if ( Token!=T_RPAREN && Token!=T_EOF )
        {
                for ( ;; )
                {
                        expression();
                        if ( argc<MAXARGS )
                                args[ argc++ ].ival = popint();
                        else
                                popint();
                        if ( Token==T_COMMA )
                                getoken();
                        else
                                break;
                }
        }
        if ( lpar )
        {
        	if ( Token!=T_RPAREN )
                	error( "missing ')'", ACT_ERROR );
	        else
	                getoken();
	}

        switch ( funcnum )
        {
        case F_PRINT:   /* quick and simple string printing */
                pushint( (INT)pprint( args ) );
                break;
        case F_PRINTF:  /* just like the real printf() function */
                pushint( (INT)pprntf( args[0].dptr, &args[1] ) );
                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( (INT)getline() );
                Fieldcount = parse( Linebuf, Fields, Fieldsep );
                break;
        case F_STRLEN:  /* calculate length of string argument */
                pushint( (INT)strlen( args[0].dptr ) );
                break;
        case F_STRCPY:  /* copy second string argument to first string */
                pushint( (INT)strcpy( args[0].dptr, args[1].dptr ) );
                break;
        case F_STRCMP:  /* compare two strings */
                pushint( (INT)strcmp( args[0].dptr, args[1].dptr ) );
                break;
        case F_TOUPPER: /* convert the character argument to upper case */
                pushint( (INT)toupper( args[0].ival ) );
                break;
        case F_TOLOWER: /* convert the character argument to lower case */
                pushint( (INT)tolower( args[0].ival ) );
                break;
        case F_MATCH:   /* match a string argument to a regular expression */
                pushint( (INT)match( args[0].dptr, args[1].dptr ) );
                break;
        case F_NEXTFILE:/* close current input file and process next file */
                pushint( (INT)endfile() );
                break;
        default:        /* oops! */
                error( "bad function call", ACT_ERROR );
        }
}

VARIABLE *
findvar( s )
char *s;
{
        /*
         * Search the symbol table for a variable whose name is "s".
         */
        VARIABLE *pvar;
        int i;
        char name[ MAXVARLEN ];

        i = 0;
        while ( i < MAXVARLEN && alphanum( *s ) )
                name[i++] = *s++;
        if ( i<MAXVARLEN )
                name[i] = 0;

        for ( pvar = Vartab; pvar<Nextvar; ++pvar )
        {
                if ( !strncmp( pvar->vname, 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 ( i<MAXVARLEN && alphanum( *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 = getmem((unsigned int) 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 = (VARIABLE *)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((char *) &ival, Stackptr->value.dptr, WORD );
                else
                        movemem((char *) &ival, Stackptr->value.dptr, Stackptr->size);
                pop();
                pushint( ival );
        }
        else
                error( "'=' needs an lvalue", ACT_ERROR );
}

INT 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 );
}

INT 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 = *(int *)Stackptr->value.dptr;
                }
                pop();
                return intvalue;
        }
        else
        {
                /*
                 * else it's an ACTUAL, just pop it
                 */
                return pop();
        }
}


pprint( args )
DATUM args[];
{
	/*
	 * execute the "print string, ..." command
	 */
	int i;

	for ( i=0; i<MAXARGS; i++ )
		if ( args[i].dptr != (char *)NULL )
			printf(" %s", args[i].dptr);
 	printf("\n");  /* AWK's default behaviour */

	return 0;
}


pprntf( fmt, args )
char *fmt;
DATUM args[];
{
	/*
	 * execute the "printf fmt, data ..." command
	 */
	char lfmt[40], *t;
	register char *s;
	int i, type, lflg;
#define LINT	0
#define SINT	1
#define	PNTR	2

	s = fmt;
	i = 0;
	while ( *s != '\0' && i < MAXARGS-1 )
	{
		if ( *s != '%' )
		{
			putc( *s++, stdout );
			continue;
		}
		t = lfmt;
		*t++ = *s++;		/* % */
		if ( *s == '-' || *s == '+' )
			*t++ = *s++;	/* sign */
		while ( *s >= '0' && *s <= '9' || *s == '*' )
			*t++ = *s++;	/* width */
		if ( *s == '.' )
			*t++ = *s++;	/* . */
		while ( *s >= '0' && *s <= '9' || *s == '*' )
			*t++ = *s++;	/* digits */

		lflg = (*s == 'l' || *s == 'L');
		if ( lflg )
			*t++ = *s++ ;
		if ( *s == 'd' || *s == 'D' || *s == 'u' || *s == 'U' ||
		     *s == 'x' || *s == 'X' || *s == 'o' || *s == 'O' )
		{
			type = lflg ? LINT : SINT;
			*t++ = *s++;
		}
		else if ( *s == 'p' || *s == 'P' || *s == 's' || *s == 'S' )
		{
			type = PNTR;
			*t++ = *s++;
		}
		else /* yuk. Better to forbid %e, %f and %g here ? */
		{
			type = SINT;
			if (*s) *t++ = *s++;
		}
		*t++ = '\0';

		switch ( type )
		{
		    case LINT:
			printf( lfmt, (long) args[i++].ival );
			break;
		    case SINT:
			printf( lfmt, (int) args[i++].ival );
			break;
		    case PNTR:
			printf( lfmt, args[i++].dptr );
			break;
		    default:
			/* impossible */
			break;
		}
	}

	return 0;
}