Listing 1 Listing of FUNCEVAL.C /********************************************************** * * * 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. * * * *********************************************************** * * * funceval.c v3.0 -- Copyright 1988 Randy C. Finch * * * **********************************************************/ /*-------------- INCLUDES ----------------*/ #include #include #include #include #include #include #include "syntxerr.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= 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 */