From 40360b48f4d9ea82200528411a0ed62d2c0e10bb Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 20 Jan 2009 07:03:31 +0000 Subject: Awesome changes to the formula class! It actually does proper reduction for unary operators now, such as negate and not, and it now handles functions. Functions are actually implemented as unary operators at the moment, so they'll only act on a single value, no commas :-P, but it would probably be pretty easy to make it work on longer call lists. Although I do think that this will work for pretty much all cases out there. --- src/formula.h | 101 ++++++++++++++++++++++++++------------------------ src/tests/formula.cpp | 14 ++++++- 2 files changed, 66 insertions(+), 49 deletions(-) diff --git a/src/formula.h b/src/formula.h index c88e409..d1e77e3 100644 --- a/src/formula.h +++ b/src/formula.h @@ -36,12 +36,26 @@ namespace Bu class Formula { public: + class Func + { + public: + virtual prec operator()( prec )=0; + }; + + typedef Hash varHash; + typedef Hash funcHash; + Formula() { } virtual ~Formula() { + for( typename funcHash::iterator i = hFunc.begin(); + i != hFunc.end(); i++ ) + { + delete (*i); + } } prec run( const Bu::FString &sFormulaSrc ) @@ -54,34 +68,28 @@ namespace Bu break; else if( tNum == symSubtract ) { - tNum = nextToken( &sFormula ); - if( tNum != symNumber ) - throw ParseException( - "Unary minus must be followed by a number, " - "variable, function, or parenthesis."); - sValue.top() = -sValue.top(); + sOper.push( symNegate ); + continue; } else if( tNum == symNot ) { - tNum = nextToken( &sFormula ); - if( tNum != symNumber ) - throw ParseException( - "Unary, binary not must be followed by a number, " - "variable, function, or parenthesis."); - sValue.top() = static_cast( - ~static_cast(sValue.top()) - ); + sOper.push( symNot ); + continue; } else if( tNum == symOpenParen ) { sOper.push( tNum ); continue; } + else if( tNum == symFunction ) + { + sOper.push( symFunction ); + continue; + } oppart: uint8_t tOpr = nextToken( &sFormula ); if( tOpr == symEOS ) { - //printf("EOS "); reduce(); return sValue.top(); break; @@ -103,29 +111,8 @@ namespace Bu return sValue.top(); } - - typedef Hash varHash; varHash hVars; - - typedef struct Func - { - prec operator()( prec x ) - { - return 0; - } - } Func; - - typedef Hash funcHash; funcHash hFunc; -/* - typedef struct FuncSin : Func - { - prec operator()( prec x ) - { - return sin( x ); - } - } FuncSin; - */ private: enum @@ -139,7 +126,9 @@ namespace Bu symCloseParen, symNumber, symVariable, + symFunction, symExponent, + symNegate, symModulus, symAnd, @@ -152,6 +141,7 @@ namespace Bu Bu::Stack sOper; Bu::Stack sValue; + Bu::Stack sFunc; private: symType getPrec( symType nOper ) @@ -180,6 +170,8 @@ namespace Bu case symExponent: case symNot: + case symNegate: + case symFunction: return 3; default: @@ -260,7 +252,8 @@ namespace Bu ". in them." ); } - if( cbuf == '.' || (cbuf >= '0' && cbuf <= '9') ) + if( cbuf == '.' || + (cbuf >= '0' && cbuf <= '9') ) { num[nPos++] = cbuf; } @@ -297,16 +290,21 @@ namespace Bu else { tok[nPos] = '\0'; - //printf("Checking variable \"%s\"\n", tok ); - try + if( hVars.has( tok ) ) { sValue.push( hVars[tok] ); return symNumber; } - catch( HashException &e ) + else if( hFunc.has( tok ) ) + { + sFunc.push( tok ); + return symFunction; + } + else { throw ParseException( - "No variable named \"%s\" exists.", + "No variable or function named " + "\"%s\" exists.", tok ); } @@ -326,7 +324,6 @@ namespace Bu uint8_t nOpr = sOper.top(); if( nOpr == symOpenParen ) { - //printf("Found ( stopping reduction.\n"); if( bCloseParen == true ) sOper.pop(); return; @@ -339,34 +336,28 @@ namespace Bu switch( nOpr ) { case symAdd: - //printf("%f + %f = %f\n", sValue.top(), dTop, sValue.top()+dTop ); sValue.top() += dTop; break; case symSubtract: - //printf("%f - %f = %f\n", sValue.top(), dTop, sValue.top()-dTop ); sValue.top() -= dTop; break; case symMultiply: - //printf("%f * %f = %f\n", sValue.top(), dTop, sValue.top()*dTop ); sValue.top() *= dTop; break; case symDivide: - //printf("%f / %f = %f\n", sValue.top(), dTop, sValue.top()/dTop ); sValue.top() /= dTop; break; case symExponent: - //printf("%f ^ %f = %f\n", sValue.top(), dTop, pow(sValue.top(),dTop) ); sValue.top() = static_cast( pow( sValue.top(), dTop ) ); break; case symModulus: - //printf("%f %% %f = %f\n", sValue.top(), dTop, fmod(sValue.top(),dTop) ); sValue.top() = static_cast( fmod( sValue.top(), dTop ) ); @@ -392,6 +383,20 @@ namespace Bu static_cast(dTop) ); break; + + case symFunction: + sValue.push( (*hFunc.get( sFunc.pop() ))( dTop ) ); + break; + + case symNegate: + sValue.push( -dTop ); + break; + + case symNot: + sValue.push( static_cast( + ~static_cast(dTop) + ) ); + break; } } diff --git a/src/tests/formula.cpp b/src/tests/formula.cpp index 429c306..b3b0d5c 100644 --- a/src/tests/formula.cpp +++ b/src/tests/formula.cpp @@ -6,6 +6,7 @@ */ #include "bu/formula.h" +#include int main( int argc, char *argv[] ) { @@ -17,7 +18,18 @@ int main( int argc, char *argv[] ) Bu::Formula uForm; Bu::Formula dForm; - printf("u: %s = %u\n", argv[1], uForm.run( argv[1] ) ); + class CeilFunc : public Bu::Formula::Func + { + public: + virtual double operator()( double x ) + { + return ceil( x ); + } + }; + + dForm.hFunc.insert( "ceil", new CeilFunc() ); + +// printf("u: %s = %u\n", argv[1], uForm.run( argv[1] ) ); printf("d: %s = %f\n", argv[1], dForm.run( argv[1] ) ); return 0; -- cgit v1.2.3