home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
math
/
3dplot
/
src
/
funceval3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-19
|
15KB
|
775 lines
/**********************************************************
* *
* Convert() converts a string containing a math *
* function in two variables, X and Y, to a postfix *
* notation string with the numeric constants and *
* functions converted to one byte symbols. If any *
* syntax errors occur they will be posted in the global *
* external variable SyntaxErr. Definitions are in *
* syntxerr.h. *
* *
* Evaluate() will substitute the X and Y values passed *
* to it and return the value of the function. *
* *
* This program may be freely used for non-profit *
* purposes as long as the copyright notice remains *
* in the code. *
* *
***********************************************************
* *
* Copyright 1987 Randy C. Finch *
* *
**********************************************************/
/*-------------- INCLUDES ----------------*/
#include "common.h"
/*---------------- DEFINES -----------------*/
#define NUMSYM 128 /* Number of constants allowed in function */
#define SYMBASE 128 /* Base value for constants symbols */
#define STACKSIZE 256 /* Stack size */
#define SIN 1 /* Symbol for sine */
#define COS 2 /* Symbol for cosine */
#define TAN 3 /* Symbol for tangent */
#define ASIN 4 /* Symbol for arcsine */
#define ACOS 5 /* Symbol for arccosine */
#define ATAN 6 /* Symbol for arctangent */
#define SINH 7 /* Symbol for hyperbolic sine */
#define COSH 8 /* Symbol for hyperbolic cosine */
#define TANH 9 /* Symbol for hyperbolic tangent */
#define EXP 10 /* Symbol for exponential */
#define SQRT 11 /* Symbol for square root */
#define LN 12 /* Symbol for natural logarithm */
#define LOG 13 /* Symbol for logarithn base 10 */
#define NULL 0 /* Symbol for null */
#define TRUE 1 /* Symbol for true condition */
#define FALSE 0 /* Symbol for false condition */
/*------------ EXTERNAL GLOBALS ------------*/
unsigned char SyntaxErr;
/*---------------- GLOBALS ----------------*/
struct CharStack {
unsigned char c[STACKSIZE];
long top;
};
struct NumStack {
double n[STACKSIZE];
long top;
};
static struct CharStack cstack;
static struct NumStack nstack;
static double Constants[NUMSYM];
static unsigned char CurConstant;
static unsigned char NewExpr[256];
/*---------------- FUNCTIONS ----------------*/
static char CharInStr(s,c)
unsigned char *s;
unsigned char c;
{
while (*s != NULL) {
if (*s == c) return TRUE;
++s;
}
return FALSE;
} /* CharInStr */
static void Deposit(num)
double num;
{
Constants[CurConstant - SYMBASE] = num;
} /* Deposit */
static void Substitute(symb, ptr, len)
unsigned char symb;
unsigned char *ptr;
unsigned long len;
{
*ptr = symb;
if (len > 1) {
do {
++ptr;
*ptr = *(ptr + len - 1);
} while (*ptr != NULL);
}
} /* Substitute */
static void RemoveSpaces(str)
unsigned char *str;
{
unsigned char *ptr;
while (*str != NULL) {
if (*str == ' ') {
ptr = str;
do {
*ptr = *(ptr + 1);
++ptr;
} while ( *(ptr - 1) != NULL);
--str;
}
++str;
}
} /* RemoveSpaces */
static void AddZero(ptr)
char *ptr;
{
unsigned long len;
char *i;
len = strlen(ptr);
for (i=ptr+len+1; i>ptr; --i)
*i = *(i - 1);
*ptr = '0';
} /* AddZero */
static unsigned char CPop()
{
if (cstack.top == 0) return 0;
else {
--cstack.top;
return cstack.c[cstack.top + 1];
}
} /* CPop */
static char CPush(c)
unsigned char c;
{
if (cstack.top == STACKSIZE) return FALSE;
else {
++cstack.top;
cstack.c[cstack.top] = c;
return TRUE;
}
} /* CPush */
static unsigned char CTopOfStack()
{
return cstack.c[cstack.top];
} /* CTopOfStack */
static double NPop()
{
--nstack.top;
return nstack.n[nstack.top + 1];
} /* NPop */
static void NPush(n)
double n;
{
++nstack.top;
nstack.n[nstack.top] = n;
} /* NPush */
static char IsFunction(c)
unsigned char c;
{
if ( (c >= SIN) && (c <= LOG) )
return TRUE;
else
return FALSE;
} /* IsFunction */
static char IsSymbol(c)
unsigned char c;
{
if ((c >= SYMBASE) && (c < SYMBASE+NUMSYM))
return TRUE;
else
return FALSE;
} /* IsSymbol */
static char Precedence(c1,c2)
unsigned char c1,c2;
{
if ( (CharInStr("+-*/",c1)) && (c2 == '^') )
return FALSE;
else if ( (CharInStr("+-",c1)) && (CharInStr("*/",c2)) )
return FALSE;
else if ( ((c1 == '(') && (c2 != ')')) || (c2 == '(') )
return FALSE;
else if ( (CharInStr("+-*/^",c1)) && (IsFunction(c2)) )
return FALSE;
else
return TRUE;
} /* Precedence */
static unsigned char *CheckSyntax(str)
unsigned char *str;
{
int numLP = 0,
numRP = 0;
if ( (CharInStr("/*^E)",*str)) && (strncmp(str,"EXP",3) != 0) ) {
if (CharInStr("/*^",*str)) {
SyntaxErr = MISPLACEDOP;
return str;
}
else if (*str == 'E') {
SyntaxErr = ILLEGALEXP;
return str;
}
else {
SyntaxErr = MISSINGLP;
return str;
}
} /* if */
for (;;) { /* forever */
if (*str == '(') {
++numLP;
++str;
if ( (CharInStr("*/^E",*str)) && (strncmp(str,"EXP",3) != 0) ) {
if (*str == 'E') {
SyntaxErr = ILLEGALEXP;
return str;
}
else {
SyntaxErr = MISPLACEDOP;
return str;
}
} /* if */
if ( (*str == ')') || (*str == NULL) ) {
SyntaxErr = MISSINGPARM;
return str;
}
} /* if */
else if (*str == ')') {
++numRP;
++str;
if (numRP > numLP) {
SyntaxErr = MISSINGLP;
return (str-1);
}
else if ( (!CharInStr(")+-*/^",*str)) && (*str != NULL) ) {
SyntaxErr = MISSINGOP;
return str;
}
} /* else if */
else if ( (isdigit(*str)) || (*str == '.') ) {
char ExitFlag = FALSE,
OneDecimal = FALSE,
OneE = FALSE;
if (*str == '.') OneDecimal = TRUE;
++str;
if ( (OneDecimal == TRUE) && (!isdigit(*str)) ) {
SyntaxErr = LONEDECIMAL;
return (str - 1);
}
while ( ( (isdigit(*str)) || (CharInStr(".E)-+",*str))
|| (*str == NULL) ) && !ExitFlag ) {
if (*str == '.') {
++str;
if (OneE) {
SyntaxErr = ILLEGALEXP;
return (str-1);
}
else if (OneDecimal) {
SyntaxErr = EXTRADECIMAL;
return (str-1);
}
else if (strncmp(str,"EXP",3) == 0) {
SyntaxErr = MISSINGOP;
return str;
}
else if ( (!CharInStr("+-*/^E)",*str)) && (!isdigit(*str)) ) {
SyntaxErr = ILLEGALCHAR;
return str;
}
else {
OneDecimal = TRUE;
}
} /* if */
else if (*str == 'E') {
++str;
if (OneE) {
SyntaxErr = EXTRAE;
return (str-1);
}
else if ( (!CharInStr("+-",*str)) && (!isdigit(*str)) ) {
SyntaxErr = ILLEGALEXP;
return str;
}
else {
OneE = TRUE;
}
} /* else if */
else if (CharInStr("+-",*str)) {
if ( *(str-1) == 'E' )
++str;
else if ( !OneE || (OneE && isdigit(*(str-1))) )
ExitFlag = TRUE;
else {
SyntaxErr = MISPLACEDOP;
return str;
}
} /* else if */
else if ( (*str == ')') || (*str == NULL) ) {
if (CharInStr("+-E",*(str-1))) {
SyntaxErr = ILLEGALEXP;
return str;
}
else {
ExitFlag = TRUE;
}
} /* else if */
else {
++str;
} /* else */
} /* while */
if( !CharInStr("+-*/)", *str) && (*str != NULL) ) {
SyntaxErr = MISSINGOP;
return str;
}
} /* else if */
else if (CharInStr("+-*/^",*str)) {
++str;
if ( (CharInStr(")E+-*/^",*str)) || (*str == NULL) ) {
if (strncmp(str,"EXP",3) != 0) {
SyntaxErr = MISPLACEDOP;
return (str-1);
}
}
} /* else if */
else if (CharInStr("XY",*str)) {
++str;
if ( (!CharInStr(")+-*/^",*str)) && (*str != NULL) ) {
SyntaxErr = MISSINGOPRP;
return str;
}
} /* else if */
else if (isupper(*str)) {
if (strncmp(str,"LN",2) == 0) str += 2;
else if (strncmp(str,"SINH",4) == 0) str += 4;
else if (strncmp(str,"COSH",4) == 0) str += 4;
else if (strncmp(str,"TANH",4) == 0) str += 4;
else if (strncmp(str,"SIN",3) == 0) str += 3;
else if (strncmp(str,"COS",3) == 0) str += 3;
else if (strncmp(str,"TAN",3) == 0) str += 3;
else if (strncmp(str,"EXP",3) == 0) str += 3;
else if (strncmp(str,"LOG",3) == 0) str += 3;
else if (strncmp(str,"SQRT",4) == 0) str += 4;
else if (strncmp(str,"ASIN",4) == 0) str += 4;
else if (strncmp(str,"ACOS",4) == 0) str += 4;
else if (strncmp(str,"ATAN",4) == 0) str += 4;
else {
SyntaxErr = ILLEGALFUNC;
return str;
}
if (*str != '(') {
SyntaxErr = MISSINGLP;
return str;
}
} /* else if */
else if (*str == NULL) {
if (numLP < numRP) {
SyntaxErr = MISSINGLP;
return str;
}
else if (numLP > numRP) {
SyntaxErr = MISSINGRP;
return str;
}
else {
SyntaxErr = FALSE;
return 0L;
}
} /* else if */
else {
SyntaxErr = ILLEGALCHAR;
return str;
}
} /* for */
} /* CheckSyntax */
static char ConvertConstants(str)
unsigned char *str;
{
unsigned char *ptr;
ptr = str;
if ( CharInStr("+-",*ptr) ) {
AddZero(str);
ptr += 2;
}
while ( *ptr != NULL ) {
if ( (CharInStr("+-",*ptr)) && (*(ptr-1) == '(') )
AddZero(ptr);
++ptr;
} /* while */
#if DEBUG
printf("\nAddZero: %s\n", str);
#endif
{ /* begin block */
unsigned long j;
unsigned char numstr[80];
double number;
ptr = str;
CurConstant = SYMBASE;
while ( *ptr != NULL) {
if ( (*ptr == '.') || (isdigit(*ptr)) ) {
unsigned long lennum = 1;
while ( (CharInStr(".E-+",*(ptr+lennum))) || (isdigit(*(ptr+lennum))) ) {
if( (CharInStr("-+",*(ptr+lennum))) && (*(ptr+lennum-1) != 'E') )
break;
++lennum;
}
for (j=0; j<lennum; ++j)
*(numstr+j) = *(ptr+j);
*(numstr+j) = NULL;
number = atof(numstr);
Deposit(number);
Substitute(CurConstant, ptr, lennum);
++CurConstant;
if (CurConstant >= SYMBASE+NUMSYM) {
SyntaxErr = TOOMANYCONST;
return FALSE;
}
} /* if */
++ptr;
} /* while */
} /* end block */
return TRUE;
} /* ConvertConstants */
static void ConvertFunctions(str)
unsigned char *str;
{
while ( *str != NULL ) {
if ( (isupper(*str)) && (!CharInStr("XY",*str)) ) {
if (strncmp(str,"LN",2) == 0) Substitute(LN,str,2L);
else if (strncmp(str,"SINH",4) == 0) Substitute(SINH,str,4L);
else if (strncmp(str,"COSH",4) == 0) Substitute(COSH,str,4L);
else if (strncmp(str,"TANH",4) == 0) Substitute(TANH,str,4L);
else if (strncmp(str,"SIN",3) == 0) Substitute(SIN,str,3L);
else if (strncmp(str,"COS",3) == 0) Substitute(COS,str,3L);
else if (strncmp(str,"TAN",3) == 0) Substitute(TAN,str,3L);
else if (strncmp(str,"EXP",3) == 0) Substitute(EXP,str,3L);
else if (strncmp(str,"LOG",3) == 0) Substitute(LOG,str,3L);
else if (strncmp(str,"SQRT",4) == 0) Substitute(SQRT,str,4L);
else if (strncmp(str,"ASIN",4) == 0) Substitute(ASIN,str,4L);
else if (strncmp(str,"ACOS",4) == 0) Substitute(ACOS,str,4L);
else if (strncmp(str,"ATAN",4) == 0) Substitute(ATAN,str,4L);
} /* if */
++str;
} /* while */
} /* ConvertFunctions */
static char InfixToPostfix(str)
unsigned char *str;
{
unsigned long i1=0, i2=0;
unsigned char NextChar, TopSymbol;
cstack.top = 0; /* Initialize stack */
NewExpr[0] = NULL; /* Initialize expression */
while ( *(str+i1) != NULL ) {
NextChar = *(str+i1);
if ( (IsSymbol(NextChar)) || (NextChar == 'X') || (NextChar == 'Y') ) {
NewExpr[i2] = NextChar;
++i2;
}
else {
for (;;) { /* Forever */
if ( (cstack.top == 0) || (!Precedence(CTopOfStack(),NextChar)) )
break;
if ((TopSymbol = CPop()) == 0) {
SyntaxErr = STACKUNDERFLOW;
return FALSE;
}
if (cstack.top != 0) {
if ( (IsFunction( CTopOfStack() )) && (NextChar == ')') ) {
TopSymbol = CPop();
NewExpr[i2] = TopSymbol;
++i2;
break;
} /* if */
} /* if */
if ( (TopSymbol == '(') && (NextChar == ')') )
break;
if (TopSymbol != '(') {
NewExpr[i2] = TopSymbol;
++i2;
}
} /* for */
if (NextChar != ')') {
if (CPush(NextChar) == FALSE) {
SyntaxErr = STACKOVERFLOW;
return FALSE;
}
}
} /* if */
++i1;
} /* while */
while (cstack.top != 0) {
TopSymbol = CPop();
if (TopSymbol != '(') {
NewExpr[i2] = TopSymbol;
++i2;
}
}
NewExpr[i2] = NULL;
return TRUE;
} /* InfixToPostfix */
static double Calculate(s,n2,n1)
unsigned char s;
double n1,n2;
{
switch (s) {
case '+':
return (n1 + n2);
case '-':
return (n1 - n2);
case '*':
return (n1 * n2);
case '/':
return (n1 / n2);
case '^':
return ( exp(n2*log(n1)) );
case SIN:
return ( sin(n2) );
case COS:
return ( cos(n2) );
case TAN:
return ( tan(n2) );
case EXP:
return ( exp(n2) );
case SQRT:
return ( sqrt(n2) );
case LN:
return ( log(n2) );
case LOG:
return ( log10(n2) );
case ASIN:
return ( asin(n2) );
case ACOS:
return ( acos(n2) );
case ATAN:
return ( atan(n2) );
case SINH:
return ( sinh(n2) );
case COSH:
return ( cosh(n2) );
case TANH:
return ( tanh(n2) );
} /* switch */
} /* Calculate */
unsigned char *Convert(FunctionString)
unsigned char *FunctionString;
{
unsigned char fstr[512];
unsigned char *ptr;
SyntaxErr = FALSE;
RemoveSpaces(FunctionString);
#if DEBUG
printf("\nRemoveSpaces: %s\n", FunctionString);
#endif
strupr(FunctionString);
#if DEBUG
printf("\nstrupr: %s\n", FunctionString);
#endif
if ((ptr = CheckSyntax(FunctionString)) != 0) return ptr;
strcpy(fstr,FunctionString);
#if DEBUG
printf("\nCheckSyntax: %s\n", fstr);
#endif
if (!ConvertConstants(fstr)) return fstr;
#if DEBUG
printf("\nConvertConstants: ");
for(ptr = fstr; *ptr != NULL; ++ptr)
printf("%d ", *ptr);
printf("\n");
#endif
ConvertFunctions(fstr);
#if DEBUG
printf("\nConvertFunctions: ");
for(ptr = fstr; *ptr != NULL; ++ptr)
printf("%d ", *ptr);
printf("\n");
#endif
if (!InfixToPostfix(fstr)) return fstr;
#if DEBUG
{
unsigned char *ptr;
printf("\nInfixToPostfix: ");
for(ptr = NewExpr; *ptr != NULL; ++ptr)
printf("%d ", *ptr);
printf("\n");
}
#endif
return NewExpr;
} /* Convert */
double Evaluate(x,y)
double x, y;
{
unsigned char symbol;
long i = 0;
nstack.top = 0; /* Initialize stack */
while (NewExpr[i] != NULL) {
symbol = NewExpr[i];
if (symbol == 'X')
NPush(x);
else if (symbol == 'Y')
NPush(y);
else if (IsSymbol(symbol)) {
NPush( Constants[symbol-SYMBASE] );
}
else if (IsFunction(symbol)) {
NPush( Calculate(symbol, NPop(), 0.0) );
}
else {
NPush( Calculate(symbol, NPop(), NPop()) );
}
++i;
} /* while */
return NPop();
} /* Evaluate */