LISTING 2. Code File for FuncEval Object /********************************************************** * * * FuncEval.cpp * * * * Implementation file for FuncEval. * * * * Definition in FuncEval.hpp. * * * *********************************************************** * * * Copyright 1995 Randy C. Finch * * * **********************************************************/ /*-------------- INCLUDES ----------------*/ #include "FuncEval.hpp" /*---------- FUNCEVAL PRIVATE METHODS ------------*/ char FuncEval::CharInStr(UCHAR *s, UCHAR c) { while (*s != NULL) { if (*s == c) return TRUE; ++s; } return FALSE; } /* CharInStr */ void FuncEval::Deposit(double num) { Constants[CurConstant - SYMBASE] = num; } /* Deposit */ void FuncEval::Substitute(UCHAR symb, UCHAR *ptr, unsigned long len) { *ptr = symb; if (len > 1) { do { ++ptr; *ptr = *(ptr + len - 1); } while (*ptr != NULL); } } /* Substitute */ void FuncEval::RemoveSpaces(UCHAR *str) { UCHAR *ptr; while (*str != NULL) { if (*str == ' ') { ptr = str; do { *ptr = *(ptr + 1); ++ptr; } while ( *(ptr - 1) != NULL); --str; } ++str; } } /* RemoveSpaces */ void FuncEval::AddZero(UCHAR *ptr) { unsigned long len; UCHAR *i; len = strlen((char *)ptr); for (i=ptr+len+1; i>ptr; --i) *i = *(i - 1); *ptr = '0'; } /* AddZero */ UCHAR FuncEval::CPop() { if (cstack.top == 0) return 0; else { --cstack.top; return cstack.c[cstack.top + 1]; } } /* CPop */ char FuncEval::CPush(UCHAR c) { if (cstack.top == STACKSIZE) return FALSE; else { ++cstack.top; cstack.c[cstack.top] = c; return TRUE; } } /* CPush */ UCHAR FuncEval::CTopOfStack() { return cstack.c[cstack.top]; } /* CTopOfStack */ double FuncEval::NPop() { --nstack.top; return nstack.n[nstack.top + 1]; } /* NPop */ void FuncEval::NPush(double n) { ++nstack.top; nstack.n[nstack.top] = n; } /* NPush */ char FuncEval::IsFunction(UCHAR c) { if ( (c >= SIN) && (c <= LOG) ) return TRUE; else return FALSE; } /* IsFunction */ char FuncEval::IsSymbol(UCHAR c) { if ((c >= SYMBASE) && (c < SYMBASE+NUMSYM)) return TRUE; else return FALSE; } /* IsSymbol */ char FuncEval::Precedence(UCHAR c1, UCHAR c2) { if ( (CharInStr((UCHAR *)"+-*/",c1)) && (c2 == '^') ) return FALSE; else if ( (CharInStr((UCHAR *)"+-",c1)) && (CharInStr((UCHAR *)"*/",c2)) ) return FALSE; else if ( ((c1 == '(') && (c2 != ')')) || (c2 == '(') ) return FALSE; else if ( (CharInStr((UCHAR *)"+-*/^",c1)) && (IsFunction(c2)) ) return FALSE; else return TRUE; } /* Precedence */ UCHAR *FuncEval::CheckSyntax(UCHAR *str) { int numLP = 0, numRP = 0; if ( (CharInStr((UCHAR *)"/*^E)",*str)) && (strncmp((char *)str,(char *)"EXP",(UINT)3) != 0) ) { if (CharInStr((UCHAR *)"/*^",*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((UCHAR *)"*/^E",*str)) && (strncmp((char *)str,(char *)"EXP",(UINT)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((UCHAR *)")+-*/^",*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((UCHAR *)".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((char *)str,(char *)"EXP",(UINT)3) == 0) { SyntaxErr = MISSINGOP; return str; } else if ( (!CharInStr((UCHAR *)"+-*/^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((UCHAR *)"+-",*str)) && (!isdigit(*str)) ) { SyntaxErr = ILLEGALEXP; return str; } else { OneE = TRUE; } } /* else if */ else if (CharInStr((UCHAR *)"+-",*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((UCHAR *)"+-E",*(str-1))) { SyntaxErr = ILLEGALEXP; return str; } else { ExitFlag = TRUE; } } /* else if */ else { ++str; } /* else */ } /* while */ if( !CharInStr((UCHAR *)"+-*/)", *str) && (*str != NULL) ) { SyntaxErr = MISSINGOP; return str; } } /* else if */ else if (CharInStr((UCHAR *)"+-*/^",*str)) { ++str; if ( (CharInStr((UCHAR *)")E+-*/^",*str)) || (*str == NULL) ) { if (strncmp((char *)str,(char *)"EXP",(UINT)3) != 0) { SyntaxErr = MISPLACEDOP; return (str-1); } } } /* else if */ else if (CharInStr((UCHAR *)"XY",*str)) { ++str; if ( (!CharInStr((UCHAR *)")+-*/^",*str)) && (*str != NULL) ) { SyntaxErr = MISSINGOPRP; return str; } } /* else if */ else if (isupper(*str)) { if (strncmp((char *)str,(char *)"LN",(UINT)2) == 0) str += 2; else if (strncmp((char *)str,(char *)"SINH",(UINT)4) == 0) str += 4; else if (strncmp((char *)str,(char *)"COSH",(UINT)4) == 0) str += 4; else if (strncmp((char *)str,(char *)"TANH",(UINT)4) == 0) str += 4; else if (strncmp((char *)str,(char *)"SIN",(UINT)3) == 0) str += 3; else if (strncmp((char *)str,(char *)"COS",(UINT)3) == 0) str += 3; else if (strncmp((char *)str,(char *)"TAN",(UINT)3) == 0) str += 3; else if (strncmp((char *)str,(char *)"EXP",(UINT)3) == 0) str += 3; else if (strncmp((char *)str,(char *)"LOG",(UINT)3) == 0) str += 3; else if (strncmp((char *)str,(char *)"SQRT",(UINT)4) == 0) str += 4; else if (strncmp((char *)str,(char *)"ASIN",(UINT)4) == 0) str += 4; else if (strncmp((char *)str,(char *)"ACOS",(UINT)4) == 0) str += 4; else if (strncmp((char *)str,(char *)"ATAN",(UINT)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 */ char FuncEval::ConvertConstants(UCHAR *str) { UCHAR *ptr; ptr = str; if ( CharInStr((UCHAR *)"+-",*ptr) ) { AddZero(str); ptr += 2; } while ( *ptr != NULL ) { if ( (CharInStr((UCHAR *)"+-",*ptr)) && (*(ptr-1) == '(') ) AddZero(ptr); ++ptr; } /* while */ #if DEBUG printf("\nAddZero: %s\n", str); #endif { /* begin block */ unsigned long j; UCHAR numstr[80]; double number; ptr = str; CurConstant = SYMBASE; while ( *ptr != NULL) { if ( (*ptr == '.') || (isdigit(*ptr)) ) { unsigned long lennum = 1; while ( (CharInStr((UCHAR *)".E-+",*(ptr+lennum))) || (isdigit(*(ptr+lennum))) ) { if( (CharInStr((UCHAR *)"-+",*(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 */ void FuncEval::ConvertFunctions(UCHAR *str) { while ( *str != NULL ) { if ( (isupper(*str)) && (!CharInStr((UCHAR *)"XY",*str)) ) { if (strncmp((char *)str,(char *)"LN",(UINT)2) == 0) Substitute(LN,str,2L); else if (strncmp((char *)str,(char *)"SINH",(UINT)4) == 0) Substitute(SINH,str,4L); else if (strncmp((char *)str,(char *)"COSH",(UINT)4) == 0) Substitute(COSH,str,4L); else if (strncmp((char *)str,(char *)"TANH",(UINT)4) == 0) Substitute(TANH,str,4L); else if (strncmp((char *)str,(char *)"SIN",(UINT)3) == 0) Substitute(SIN,str,3L); else if (strncmp((char *)str,(char *)"COS",(UINT)3) == 0) Substitute(COS,str,3L); else if (strncmp((char *)str,(char *)"TAN",(UINT)3) == 0) Substitute(TAN,str,3L); else if (strncmp((char *)str,(char *)"EXP",(UINT)3) == 0) Substitute(EXP,str,3L); else if (strncmp((char *)str,(char *)"LOG",(UINT)3) == 0) Substitute(LOG,str,3L); else if (strncmp((char *)str,(char *)"SQRT",(UINT)4) == 0) Substitute(SQRT,str,4L); else if (strncmp((char *)str,(char *)"ASIN",(UINT)4) == 0) Substitute(ASIN,str,4L); else if (strncmp((char *)str,(char *)"ACOS",(UINT)4) == 0) Substitute(ACOS,str,4L); else if (strncmp((char *)str,(char *)"ATAN",(UINT)4) == 0) Substitute(ATAN,str,4L); } /* if */ ++str; } /* while */ } /* ConvertFunctions */ char FuncEval::InfixToPostfix(UCHAR *str) { unsigned long i1=0, i2=0; UCHAR 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; } } } /* else */ ++i1; } /* while */ while (cstack.top != 0) { TopSymbol = CPop(); if (TopSymbol != '(') { NewExpr[i2] = TopSymbol; ++i2; } } NewExpr[i2] = NULL; return TRUE; } /* InfixToPostfix */ double FuncEval::Calculate(UCHAR s, double n2, double n1) { 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 */ return 0.0; // should never happen, here to prevent compile warning } /* Calculate */ /*-------------- FUNCEVAL PUBLIC METHODS --------------*/ FuncEval::FuncEval() { ErrPosition = 0; } int FuncEval::Convert(UCHAR *FunctionString) { UCHAR *ptr; SyntaxErr = FALSE; RemoveSpaces(FunctionString); #if DEBUG printf("\nRemoveSpaces: %s\n", FunctionString); #endif strupr((char *)FunctionString); #if DEBUG printf("\nstrupr: %s\n", FunctionString); #endif if (ptr = CheckSyntax(FunctionString)) { ErrPosition = (int)(ptr-FunctionString)+1; return GetSyntaxErrNum(); } strcpy((char *)fstr,(char *)FunctionString); #if DEBUG printf("\nCheckSyntax: %s\n", fstr); #endif if (!ConvertConstants(fstr)) return GetSyntaxErrNum(); #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 GetSyntaxErrNum(); #if DEBUG { UCHAR *ptr; printf("\nInfixToPostfix: "); for(ptr = NewExpr; *ptr != NULL; ++ptr) printf("%d ", *ptr); printf("\n"); } #endif return GetSyntaxErrNum(); } /* Convert */ double FuncEval::Evaluate(double x, double y) { UCHAR symbol; long i = 0; double tempnum; 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 { tempnum = NPop(); NPush( Calculate(symbol, tempnum, NPop()) ); } ++i; } /* while */ return NPop(); } /* Evaluate */ int FuncEval::GetSyntaxErrNum() { return SyntaxErr; } char *FuncEval::GetSyntaxErrMessage() { if (SyntaxErr) { if (SyntaxErr == STACKUNDERFLOW) ErrMessage = (char *)"Stack underflow"; else if (SyntaxErr == STACKOVERFLOW) ErrMessage = (char *)"Stack overflow"; else if (SyntaxErr == TOOMANYCONST) ErrMessage = (char *)"Too many constants in function"; else { switch (SyntaxErr) { case MISPLACEDOP: ErrMessage = (char *)"Misplaced operator"; break; case ILLEGALCHAR: ErrMessage = (char *)"Illegal character"; break; case ILLEGALEXP: ErrMessage = (char *)"Illegal exponent"; break; case ILLEGALFUNC: ErrMessage = (char *)"Illegal function"; break; case MISSINGOP: ErrMessage = (char *)"Missing operator"; break; case MISSINGOPRP: ErrMessage = (char *)"Missing operator or right parenthesis"; break; case MISSINGLP: ErrMessage = (char *)"Missing left parenthesis"; break; case MISSINGRP: ErrMessage = (char *)"Missing right parenthesis"; break; case MISSINGPARM: ErrMessage = (char *)"Missing parameter"; break; case LONEDECIMAL: ErrMessage = (char *)"Lone decimal point"; break; case EXTRADECIMAL: ErrMessage = (char *)"Extra decimal"; break; case EXTRAE: ErrMessage = (char *)"Extra E"; break; } /* switch */ } /* else */ } /* if */ else { ErrMessage = (char *) "Acceptable"; } return ErrMessage; } int FuncEval::GetErrPosition() { return ErrPosition; }