home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HyperLib 1997 Winter - Disc 1
/
HYPERLIB-1997-Winter-CD1.ISO.7z
/
HYPERLIB-1997-Winter-CD1.ISO
/
オンラインウェア
/
PRG
/
bwbasic-2.10.sit
/
bwbasic-2.10
/
bwb_ops.c
< prev
next >
Wrap
Text File
|
1993-11-09
|
47KB
|
1,929 lines
/****************************************************************
bwb_ops.c Expression Parsing Operations
for Bywater BASIC Interpreter
Copyright (c) 1993, Ted A. Campbell
Bywater Software
email: tcamp@delphi.com
Copyright and Permissions Information:
All U.S. and international rights are claimed by the author,
Ted A. Campbell.
This software is released under the terms of the GNU General
Public License (GPL), which is distributed with this software
in the file "COPYING". The GPL specifies the terms under
which users may copy and use the software in this distribution.
A separate license is available for commercial distribution,
for information on which you should contact the author.
****************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "bwbasic.h"
#include "bwb_mes.h"
/* declarations for functions visible in this file only */
#if ANSI_C
static int op_oplevel( int level );
static int op_add( int level, int precision );
static int op_subtract( int level, int precision );
static int op_multiply( int level, int precision );
static int op_divide( int level, int precision );
static int op_assign( int level, int precision );
static int op_equals( int level, int precision );
static int op_lessthan( int level, int precision );
static int op_greaterthan( int level, int precision );
static int op_lteq( int level, int precision );
static int op_gteq( int level, int precision );
static int op_notequal( int level, int precision );
static int op_modulus( int level, int precision );
static int op_exponent( int level, int precision );
static int op_intdiv( int level, int precision );
static int op_or( int level, int precision );
static int op_and( int level, int precision );
static int op_not( int level, int precision );
static int op_xor( int level, int precision );
static int op_islevelstr( int level );
static int op_getprecision( int level );
static int op_isoperator( int operation );
static int op_pulldown( int how_far );
#else
static int op_oplevel();
static int op_add();
static int op_subtract();
static int op_multiply();
static int op_divide();
static int op_assign();
static int op_equals();
static int op_lessthan();
static int op_greaterthan();
static int op_lteq();
static int op_gteq();
static int op_notequal();
static int op_modulus();
static int op_exponent();
static int op_intdiv();
static int op_or();
static int op_and();
static int op_not();
static int op_xor();
static int op_islevelstr();
static int op_getprecision();
static int op_isoperator();
static int op_pulldown();
#endif /* ANSI_C for prototypes */
static int op_level;
/***************************************************************
FUNCTION: exp_operation()
DESCRIPTION: This function performs whatever operations
are necessary at the end of function bwb_exp()
(i.e., the end of the parsing of an expression;
see file bwb_exp.c).
***************************************************************/
#if ANSI_C
int
exp_operation( int entry_level )
#else
int
exp_operation( entry_level )
int entry_level;
#endif
{
register int precedence;
int operator;
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in exp_operation(): entered function." );
bwb_debug( bwb_ebuf );
#endif
/* cycle through all levels of precedence and perform required
operations */
for ( precedence = 0; precedence <= MAX_PRECEDENCE; ++precedence )
{
/* Operation loop: cycle through every level above entry level
and perform required operations as needed */
op_level = entry_level + 1;
while( ( op_level < CURTASK expsc )
&& ( op_isoperator( CURTASK exps[ op_level ].operation ) == FALSE ))
{
++op_level;
}
while ( ( op_level > entry_level ) && ( op_level < CURTASK expsc ) )
{
/* see if the operation at this level is an operator with the
appropriate precedence level by running through the table
of operators */
for ( operator = 0; operator < N_OPERATORS; ++operator )
{
if ( exp_ops[ operator ].operation == CURTASK exps[ op_level ].operation )
{
/* check for appropriate level of precedence */
if ( exp_ops[ operator ].precedence == precedence )
{
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in exp_operation(): level <%d> operation <%d>",
op_level, CURTASK exps[ op_level ].operation );
bwb_debug( bwb_ebuf );
#endif
op_oplevel( op_level ); /* perform the operation */
}
}
}
/* advance level if appropriate; one must check, however, since
the op_oplevel() function may have decremented CURTASK expsc */
if ( op_level < CURTASK expsc )
{
++op_level;
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in exp_operation() first increment op_level to <%d>",
op_level );
bwb_debug( bwb_ebuf );
#endif
while ( ( op_isoperator( CURTASK exps [ op_level ].operation ) == FALSE )
&& ( op_level < CURTASK expsc ) )
{
++op_level;
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in exp_operation() further increment op_level to <%d>",
op_level );
bwb_debug( bwb_ebuf );
#endif
}
} /* end of increment of op_level */
} /* end of for loop for stack levels */
} /* end of for loop for precedence levels */
return TRUE;
} /* end of function exp_operation() */
/***************************************************************
FUNCTION: op_oplevel()
DESCRIPTION: This function performs a specific operation
at a specific level as the expression parser
resolves its arguments.
***************************************************************/
#if ANSI_C
static int
op_oplevel( int level )
#else
static int
op_oplevel( level )
int level;
#endif
{
int precision;
/* set the precision */
if ( ( precision = op_getprecision( level ) ) == OP_ERROR )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "exp_operation(): failed to set precision." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch ); /*** ??? ***/
#endif
op_pulldown( 2 );
}
/* precision is set correctly */
else
{
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_oplevel(): level <%d>, precision <%c>",
level, precision );
bwb_debug( bwb_ebuf );
#endif
switch ( CURTASK exps[ level ].operation )
{
case OP_ADD:
op_add( level, precision );
break;
case OP_SUBTRACT:
op_subtract( level, precision );
break;
case OP_MULTIPLY:
op_multiply( level, precision );
break;
case OP_DIVIDE:
op_divide( level, precision );
break;
case OP_ASSIGN:
op_assign( level, precision );
break;
case OP_EQUALS:
op_equals( level, precision );
break;
case OP_LESSTHAN:
op_lessthan( level, precision );
break;
case OP_GREATERTHAN:
op_greaterthan( level, precision );
break;
case OP_LTEQ:
op_lteq( level, precision );
break;
case OP_GTEQ:
op_gteq( level, precision );
break;
case OP_NOTEQUAL:
op_notequal( level, precision );
break;
case OP_MODULUS:
op_modulus( level, precision );
break;
case OP_INTDIVISION:
op_intdiv( level, precision );
break;
case OP_OR:
op_or( level, precision );
break;
case OP_AND:
op_and( level, precision );
break;
case OP_NOT:
op_not( level, precision );
break;
case OP_XOR:
op_xor( level, precision );
break;
case OP_EXPONENT:
op_exponent( level, precision );
break;
default:
#if PROG_ERRORS
sprintf( bwb_ebuf, "PROGRAMMING ERROR: operator <%d> not (yet) supported.", CURTASK exps[ level ].operation );
op_pulldown( 2 );
bwb_error( bwb_ebuf );
#else
bwb_error( err_syntax );
#endif
break;
} /* end of case statement for operators */
} /* end of else statement, precision set */
return TRUE;
} /* end of function op_oplevel() */
/***************************************************************
FUNCTION: op_isoperator()
DESCRIPTION: This function detects whether its argument
is an operator.
***************************************************************/
#if ANSI_C
static int
op_isoperator( int operation )
#else
static int
op_isoperator( operation )
int operation;
#endif
{
register int c;
for( c = 0; c < N_OPERATORS; ++c )
{
if ( operation == exp_ops[ c ].operation )
{
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_isoperator(): found match <%s>",
exp_ops[ c ].symbol );
bwb_debug( bwb_ebuf );
#endif
return TRUE;
}
}
/* test failed; return FALSE */
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_isoperator(): no match found for operation <%d>",
operation );
bwb_debug( bwb_ebuf );
#endif
return FALSE;
}
/***************************************************************
FUNCTION: op_add()
DESCRIPTION: This function adds two numbers or
concatenates two strings.
***************************************************************/
#if ANSI_C
static int
op_add( int level, int precision )
#else
static int
op_add( level, precision )
int level;
int precision;
#endif
{
int error_condition;
error_condition = FALSE;
switch( precision )
{
case STRING:
/* both sides of the operation should be strings for
string addition; if not, report an error */
if ( ( op_islevelstr( level - 1 ) != TRUE )
|| ( op_islevelstr( level + 1 ) != TRUE ) )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "in op_add(): Type mismatch in string addition." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
error_condition = TRUE;
}
/* concatenate the two strings */
if ( error_condition == FALSE )
{
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_add(): try exp_getsval(), level <%d> op <%d> type <%c>:",
level - 1, CURTASK exps[ level - 1 ].operation, CURTASK exps[ level - 1 ].type );
bwb_debug( bwb_ebuf );
exp_getsval( &( CURTASK exps[ level - 1 ] ));
sprintf( bwb_ebuf, "in op_add(): try exp_getsval(), level <%d> op <%d> type <%c>:",
level + 1, CURTASK exps[ level + 1 ].operation, CURTASK exps[ level + 1 ].type );
bwb_debug( bwb_ebuf );
exp_getsval( &( CURTASK exps[ level + 1 ] ));
sprintf( bwb_ebuf, "in op_add(): string addition, exp_getsval()s completed" );
bwb_debug( bwb_ebuf );
#endif
str_cat( exp_getsval( &( CURTASK exps[ level - 1 ] ) ),
exp_getsval( &( CURTASK exps[ level + 1 ] ) ) );
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_add(): str_cat() returns <%d>-byte string to level <%d>",
exp_getsval( &( CURTASK exps[ level - 1 ] ) )->length, level - 1 );
bwb_debug( bwb_ebuf );
#endif
}
break;
case NUMBER:
CURTASK exps[ level - 1 ].nval
= exp_getnval( &( CURTASK exps[ level - 1 ] ))
+ exp_getnval( &( CURTASK exps[ level + 1 ] ));
CURTASK exps[ level - 1 ].operation = NUMBER;
break;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = (char) precision;
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_add() returns with operation <%d> type <%c>",
CURTASK exps[ level - 1 ].operation, CURTASK exps[ level - 1 ].type );
bwb_debug( bwb_ebuf );
#endif
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_subtract()
DESCRIPTION: This function subtracts the number on
the left from the number on the right.
***************************************************************/
#if ANSI_C
static int
op_subtract( int level, int precision )
#else
static int
op_subtract( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be subtracted." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
case NUMBER:
CURTASK exps[ level - 1 ].nval
= exp_getnval( &( CURTASK exps[ level - 1 ] ))
- exp_getnval( &( CURTASK exps[ level + 1 ] ));
break;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = (char) precision;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_multiply()
DESCRIPTION: This function multiplies the number on
the left by the number on the right.
***************************************************************/
#if ANSI_C
static int
op_multiply( int level, int precision )
#else
static int
op_multiply( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be multiplied." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
case NUMBER:
CURTASK exps[ level - 1 ].nval
= exp_getnval( &( CURTASK exps[ level - 1 ] ))
* exp_getnval( &( CURTASK exps[ level + 1 ] ));
break;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = (char) precision;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_divide()
DESCRIPTION: This function divides the number on
the left by the number on the right.
***************************************************************/
#if ANSI_C
static int
op_divide( int level, int precision )
#else
static int
op_divide( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
division; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be divided." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level + 1 ] ))
== (bnumber) 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) -1.0;
op_pulldown( 2 );
#if PROG_ERRORS
sprintf( bwb_ebuf, "Divide by 0." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_dbz );
#endif
return FALSE;
}
CURTASK exps[ level - 1 ].nval
= exp_getnval( &( CURTASK exps[ level - 1 ] ))
/ exp_getnval( &( CURTASK exps[ level + 1 ] ));
break;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = (char) precision;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_assign()
DESCRIPTION: This function assigns the value in the
right hand side to the variable in the
left hand side.
***************************************************************/
#if ANSI_C
static int
op_assign( int level, int precision )
#else
static int
op_assign( level, precision )
int level;
int precision;
#endif
{
/* Make sure the position one level below is a variable */
if ( CURTASK exps[ level - 1 ].operation != VARIABLE )
{
op_pulldown( 2 );
#if PROG_ERRORS
sprintf( bwb_ebuf, "in op_assign(): Assignment must be to variable: level -1 <%d> op <%d>",
level - 1, CURTASK exps[ level - 1 ].operation );
bwb_error( bwb_ebuf );
#else
bwb_error( err_syntax );
#endif
return FALSE;
}
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_assign(): entered function level <%d>",
level );
bwb_debug( bwb_ebuf );
#endif
/* if the assignment is numerical, then the precision should be set
to that of the variable on the left-hand side of the assignment */
if ( precision != STRING )
{
precision = (int) CURTASK exps[ level - 1 ].type;
}
switch( precision )
{
case STRING:
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_assign(): try exp_getsval(), level <%d> op <%d> type <%c>:",
level - 1, CURTASK exps[ level - 1 ].operation, CURTASK exps[ level - 1 ].type );
bwb_debug( bwb_ebuf );
exp_getsval( &( CURTASK exps[ level - 1 ] ));
sprintf( bwb_ebuf, "in op_assign(): try exp_getsval(), level <%d> op <%d> type <%c>:",
level + 1, CURTASK exps[ level + 1 ].operation, CURTASK exps[ level + 1 ].type );
bwb_debug( bwb_ebuf );
exp_getsval( &( CURTASK exps[ level + 1 ] ));
sprintf( bwb_ebuf, "in op_assign(): string addition, exp_getsval()s completed" );
bwb_debug( bwb_ebuf );
#endif
str_btob( exp_getsval( &( CURTASK exps[ level - 1 ] )),
exp_getsval( &( CURTASK exps[ level + 1 ] )) );
break;
case NUMBER:
* var_findnval( CURTASK exps[ level - 1 ].xvar,
CURTASK exps[ level - 1 ].array_pos ) =
CURTASK exps[ level - 1 ].nval =
exp_getnval( &( CURTASK exps[ level + 1 ] ) );
break;
default:
#if PROG_ERRORS
sprintf( bwb_ebuf, "in op_assign(): Variable before assignment operator has unidentified type." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
return FALSE;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = (char) precision;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_equals()
DESCRIPTION: This function compares two values and
returns an integer value: TRUE if they are
the same and FALSE if they are not.
***************************************************************/
#if ANSI_C
static int
op_equals( int level, int precision )
#else
static int
op_equals( level, precision )
int level;
int precision;
#endif
{
int error_condition;
static bstring b;
bstring *bp;
error_condition = FALSE;
b.rab = FALSE;
switch( precision )
{
case STRING:
/* both sides of the operation should be strings for
string addition; if not, report an error */
if ( ( op_islevelstr( level - 1 ) != TRUE )
|| ( op_islevelstr( level + 1 ) != TRUE ) )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "in op_equals(): Type mismatch in string comparison." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
error_condition = TRUE;
}
/* compare the two strings */
if ( error_condition == FALSE )
{
bp = exp_getsval( &( CURTASK exps[ level - 1 ] ));
#if OLDWAY
b.length = bp->length;
b.sbuffer = bp->sbuffer;
#endif
str_btob( &b, bp );
if ( str_cmp( &b,
exp_getsval( &( CURTASK exps[ level + 1 ] )) ) == 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
}
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level - 1 ] ))
== exp_getnval( &( CURTASK exps[ level + 1 ] )) )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
break;
}
/* set variable to integer and operation to NUMBER:
this must be done at the end, since at the beginning it
might cause op_islevelstr() to return a false error */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_lessthan()
DESCRIPTION: This function compares two values and
returns an integer value: TRUE if the
left hand value is less than the right,
and FALSE if it is not.
***************************************************************/
#if ANSI_C
static int
op_lessthan( int level, int precision )
#else
static int
op_lessthan( level, precision )
int level;
int precision;
#endif
{
int error_condition;
error_condition = FALSE;
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
if ( ( op_islevelstr( level - 1 ) != TRUE )
|| ( op_islevelstr( level + 1 ) != TRUE ) )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "Type mismatch in string comparison." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
error_condition = TRUE;
}
/* compare the two strings */
if ( error_condition == FALSE )
{
if ( str_cmp( exp_getsval( &( CURTASK exps[ level - 1 ] )),
exp_getsval( &( CURTASK exps[ level + 1 ] )) ) < 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
}
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level - 1 ] ))
< exp_getnval( &( CURTASK exps[ level + 1 ] )) )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
break;
}
/* set variable to integer and operation to NUMBER:
this must be done at the end, since at the beginning it
might cause op_islevelstr() to return a false error */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_greaterthan()
DESCRIPTION: This function compares two values and
returns an integer value: TRUE if the
left hand value is greater than the right,
and FALSE if it is not.
***************************************************************/
#if ANSI_C
static int
op_greaterthan( int level, int precision )
#else
static int
op_greaterthan( level, precision )
int level;
int precision;
#endif
{
int error_condition;
error_condition = FALSE;
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
if ( ( op_islevelstr( level - 1 ) != TRUE )
|| ( op_islevelstr( level + 1 ) != TRUE ) )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "Type mismatch in string comparison." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
error_condition = TRUE;
}
/* compare the two strings */
if ( error_condition == FALSE )
{
if ( str_cmp( exp_getsval( &( CURTASK exps[ level - 1 ] )),
exp_getsval( &( CURTASK exps[ level + 1 ] )) ) > 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
}
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level - 1 ] ))
> exp_getnval( &( CURTASK exps[ level + 1 ] )) )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
break;
}
/* set variable to integer and operation to NUMBER:
this must be done at the end, since at the beginning it
might cause op_islevelstr() to return a false error */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_lteq()
DESCRIPTION: This function compares two values and
returns an integer value: TRUE if the
left hand value is less than or equal
to the right, and FALSE if it is not.
***************************************************************/
#if ANSI_C
static int
op_lteq( int level, int precision )
#else
static int
op_lteq( level, precision )
int level;
int precision;
#endif
{
int error_condition;
error_condition = FALSE;
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
if ( ( op_islevelstr( level - 1 ) != TRUE )
|| ( op_islevelstr( level + 1 ) != TRUE ) )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "Type mismatch in string comparison." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
error_condition = TRUE;
}
/* compare the two strings */
if ( error_condition == FALSE )
{
if ( str_cmp( exp_getsval( &( CURTASK exps[ level - 1 ] )),
exp_getsval( &( CURTASK exps[ level + 1 ] )) ) <= 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
}
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level - 1 ] ))
<= exp_getnval( &( CURTASK exps[ level + 1 ] )) )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
break;
}
/* set variable to integer and operation to NUMBER:
this must be done at the end, since at the beginning it
might cause op_islevelstr() to return a false error */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_gteq()
DESCRIPTION: This function compares two values and
returns an integer value: TRUE if the
left hand value is greater than or equal
to the right, and FALSE if it is not.
***************************************************************/
#if ANSI_C
static int
op_gteq( int level, int precision )
#else
static int
op_gteq( level, precision )
int level;
int precision;
#endif
{
int error_condition;
error_condition = FALSE;
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
if ( ( op_islevelstr( level - 1 ) != TRUE )
|| ( op_islevelstr( level + 1 ) != TRUE ) )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "Type mismatch in string comparison." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
error_condition = TRUE;
}
/* compare the two strings */
if ( error_condition == FALSE )
{
if ( str_cmp( exp_getsval( &( CURTASK exps[ level - 1 ] )),
exp_getsval( &( CURTASK exps[ level + 1 ] )) ) >= 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
}
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level - 1 ] ))
>= exp_getnval( &( CURTASK exps[ level + 1 ] )) )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
break;
}
/* set variable to integer and operation to NUMBER:
this must be done at the end, since at the beginning it
might cause op_islevelstr() to return a false error */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_notequal()
DESCRIPTION: This function compares two values and
returns an integer value: TRUE if they
are not the same and FALSE if they are.
***************************************************************/
#if ANSI_C
static int
op_notequal( int level, int precision )
#else
static int
op_notequal( level, precision )
int level;
int precision;
#endif
{
int error_condition;
error_condition = FALSE;
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
if ( ( op_islevelstr( level - 1 ) != TRUE )
|| ( op_islevelstr( level + 1 ) != TRUE ) )
{
#if PROG_ERRORS
sprintf( bwb_ebuf, "Type mismatch in string comparison." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
error_condition = TRUE;
}
/* compare the two strings */
if ( error_condition == FALSE )
{
if ( str_cmp( exp_getsval( &( CURTASK exps[ level - 1 ] )),
exp_getsval( &( CURTASK exps[ level + 1 ] )) ) != 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
}
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level - 1 ] ))
!= exp_getnval( &( CURTASK exps[ level + 1 ] )) )
{
CURTASK exps[ level - 1 ].nval = (bnumber) TRUE;
}
else
{
CURTASK exps[ level - 1 ].nval = (bnumber) FALSE;
}
break;
}
/* set variable to integer and operation to NUMBER:
this must be done at the end, since at the beginning it
might cause op_islevelstr() to return a false error */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_modulus()
DESCRIPTION: This function divides the number on
the left by the number on the right
and returns the remainder.
***************************************************************/
#if ANSI_C
static int
op_modulus( int level, int precision )
#else
static int
op_modulus( level, precision )
int level;
int precision;
#endif
{
static double iportion;
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be divided." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_syntax );
#endif
break;
case NUMBER:
if ( exp_getnval( &( CURTASK exps[ level + 1 ] ))
== (bnumber) 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) -1;
op_pulldown( 2 );
#if PROG_ERRORS
sprintf( bwb_ebuf, "Divide by 0." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_dbz );
#endif
return FALSE;
}
CURTASK exps[ level ].nval
= exp_getnval( &( CURTASK exps[ level - 1 ] ))
/ exp_getnval( &( CURTASK exps[ level + 1 ] ));
modf( (double) CURTASK exps[ level ].nval, &iportion );
CURTASK exps[ level - 1 ].nval
= exp_getnval( &( CURTASK exps[ level - 1 ] ))
- ( exp_getnval( &( CURTASK exps[ level + 1 ] ))
* iportion );
break;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = (char) precision;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_exponent()
DESCRIPTION: This function finds the exponential value
of a number (on the left) to the power
indicated on the right-hand side.
***************************************************************/
#if ANSI_C
static int
op_exponent( int level, int precision )
#else
static int
op_exponent( level, precision )
int level;
int precision;
#endif
{
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_exponent(): entered function level <%d>.",
level );
bwb_debug ( bwb_ebuf );
#endif
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be taken as exponents." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
case NUMBER:
CURTASK exps[ level - 1 ].nval
= (bnumber) pow( (double) exp_getnval( &( CURTASK exps[ level - 1 ] )),
(double) exp_getnval( &( CURTASK exps[ level + 1 ] )) );
break;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = (char) precision;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_intdiv()
DESCRIPTION: This function divides the number on
the left by the number on the right,
returning the result as an integer.
***************************************************************/
#if ANSI_C
static int
op_intdiv( int level, int precision )
#else
static int
op_intdiv( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
string addition; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be divided." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
default:
if ( exp_getnval( &( CURTASK exps[ level + 1 ] ))
== (bnumber) 0 )
{
CURTASK exps[ level - 1 ].nval = (bnumber) -1;
op_pulldown( 2 );
#if PROG_ERRORS
sprintf( bwb_ebuf, "Divide by 0." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_dbz );
#endif
return FALSE;
}
CURTASK exps[ level - 1 ].nval
= exp_getnval( &( CURTASK exps[ level - 1 ] ))
/ exp_getnval( &( CURTASK exps[ level + 1 ] ));
break;
}
/* set variable to requested precision */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_or()
DESCRIPTION: This function compares two integers and
performs a logical NOT on them.
***************************************************************/
#if ANSI_C
static int
op_or( int level, int precision )
#else
static int
op_or( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
logical comparison; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be compared logically." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
case NUMBER:
CURTASK exps[ level - 1 ].nval
= (bnumber) ((int) exp_getnval( &( CURTASK exps[ level - 1 ] ))
| (int) exp_getnval( &( CURTASK exps[ level + 1 ] )));
break;
}
/* set variable type to integer */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_and()
DESCRIPTION: This function compares two integers and
performs a logical NOT on them.
***************************************************************/
#if ANSI_C
static int
op_and( int level, int precision )
#else
static int
op_and( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
logical comparison; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be compared logically." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
case NUMBER:
CURTASK exps[ level - 1 ].nval
= (bnumber) ((int) exp_getnval( &( CURTASK exps[ level - 1 ] ))
& (int) exp_getnval( &( CURTASK exps[ level + 1 ] )));
break;
}
/* set variable type to integer */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_not()
DESCRIPTION: This function compares two integers and
performs a logical NOT on them.
***************************************************************/
#if ANSI_C
static int
op_not( int level, int precision )
#else
static int
op_not( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
logical comparison; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be compared logically." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
default:
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_not(): argument is <%d>, precision <%c>",
(unsigned int) exp_getnval( &( CURTASK exps[ level + 1 ] )), precision );
bwb_debug( bwb_ebuf );
#endif
CURTASK exps[ level ].nval = (bnumber)
~( (int) exp_getnval( &( CURTASK exps[ level + 1 ] )) );
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_not(): result is <%d>, precision <%c>",
(int) r, precision );
bwb_debug( bwb_ebuf );
#endif
break;
}
/* set variable type to integer */
CURTASK exps[ level ].type = NUMBER;
CURTASK exps[ level ].operation = NUMBER;
/* decrement the stack once */
op_pulldown( 1 );
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_not(): CURTASK expsc <%d>, level <%d> result <%d>",
CURTASK expsc, level, CURTASK exps[ CURTASK expsc ].nval );
bwb_debug( bwb_ebuf );
#endif
return TRUE;
}
/***************************************************************
FUNCTION: op_xor()
DESCRIPTION: This function compares two integers and
performs a logical NOT on them.
***************************************************************/
#if ANSI_C
static int
op_xor( int level, int precision )
#else
static int
op_xor( level, precision )
int level;
int precision;
#endif
{
switch( precision )
{
case STRING:
/* both sides of the operation should be numbers for
logical comparison; if not, report an error */
#if PROG_ERRORS
sprintf( bwb_ebuf, "Strings cannot be compared logically." );
bwb_error( bwb_ebuf );
#else
bwb_error( err_mismatch );
#endif
break;
case NUMBER:
CURTASK exps[ level - 1 ].nval
= (bnumber) ((int) exp_getnval( &( CURTASK exps[ level - 1 ] ))
^ (int) exp_getnval( &( CURTASK exps[ level + 1 ] )));
break;
}
/* set variable type to integer */
CURTASK exps[ level - 1 ].type = NUMBER;
CURTASK exps[ level - 1 ].operation = NUMBER;
/* decrement the stack twice */
op_pulldown( 2 );
return TRUE;
}
/***************************************************************
FUNCTION: op_islevelstr()
DESCRIPTION: This function determines whether the
operation at a specified level involves a
string constant or variable.
***************************************************************/
#if ANSI_C
static int
op_islevelstr( int level )
#else
static int
op_islevelstr( level )
int level;
#endif
{
/* first see if the level holds a string constant */
if ( CURTASK exps[ level ].operation == CONST_STRING )
{
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_islevelstr(): string detected at level <%d>.",
level );
bwb_debug( bwb_ebuf );
#endif
return TRUE;
}
/* see if the level holds a string variable */
if ( CURTASK exps[ level ].operation == VARIABLE )
{
if ( CURTASK exps[ level ].xvar->type == STRING )
{
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_islevelstr(): string detected at level <%d>.",
level );
bwb_debug( bwb_ebuf );
#endif
return TRUE;
}
}
/* test has failed, return FALSE */
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_islevelstr(): string not detected at level <%d>.",
level );
bwb_debug( bwb_ebuf );
#endif
return FALSE;
}
/***************************************************************
FUNCTION: op_getprecision()
DESCRIPTION: This function finds the precision for
an operation by comparing the precision
at this level and that two levels below.
***************************************************************/
#if ANSI_C
static int
op_getprecision( int level )
#else
static int
op_getprecision( level )
int level;
#endif
{
/* first test for string value */
if ( ( CURTASK exps[ level + 1 ].type == STRING )
|| ( CURTASK exps[ level - 1 ].type == STRING ) )
{
return STRING;
}
/* Both are numbers, so we should be able to find a suitable
precision level by starting with the top and moving down;
check first for double precision */
else
{
return NUMBER;
}
}
/***************************************************************
FUNCTION: op_pulldown()
DESCRIPTION: This function pulls the expression stack
down a specified number of levels, decrementing
the expression stack counter (bycalling dec_esc())
and decrementing the current "level" of operation
processing.
***************************************************************/
#if ANSI_C
static int
op_pulldown( int how_far )
#else
static int
op_pulldown( how_far )
int how_far;
#endif
{
int level;
register int c;
#if INTENSIVE_DEBUG
sprintf( bwb_ebuf, "in op_pulldown(): pull down e stack <%d> place(s)",
how_far );
bwb_debug( bwb_ebuf );
#endif
/* first pull down the actual variables themselves */
level = op_level + ( 2 - how_far );
while ( CURTASK expsc >= ( level + how_far ) )
{
memcpy( &CURTASK exps[ level ], &CURTASK exps[ level + how_far ],
(size_t) ( sizeof( struct exp_ese )) );
++level;
}
/* decrement the expression stack counter */
for ( c = 0; c < how_far; ++c )
{
if ( dec_esc() == TRUE )
{
--op_level;
}
else
{
return FALSE;
}
}
return TRUE;
}