diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/formula.h | 101 | ||||
| -rw-r--r-- | 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 | |||
| 36 | class Formula | 36 | class Formula |
| 37 | { | 37 | { |
| 38 | public: | 38 | public: |
| 39 | class Func | ||
| 40 | { | ||
| 41 | public: | ||
| 42 | virtual prec operator()( prec )=0; | ||
| 43 | }; | ||
| 44 | |||
| 45 | typedef Hash<Bu::FString, prec> varHash; | ||
| 46 | typedef Hash<Bu::FString, Func *> funcHash; | ||
| 47 | |||
| 39 | Formula() | 48 | Formula() |
| 40 | { | 49 | { |
| 41 | } | 50 | } |
| 42 | 51 | ||
| 43 | virtual ~Formula() | 52 | virtual ~Formula() |
| 44 | { | 53 | { |
| 54 | for( typename funcHash::iterator i = hFunc.begin(); | ||
| 55 | i != hFunc.end(); i++ ) | ||
| 56 | { | ||
| 57 | delete (*i); | ||
| 58 | } | ||
| 45 | } | 59 | } |
| 46 | 60 | ||
| 47 | prec run( const Bu::FString &sFormulaSrc ) | 61 | prec run( const Bu::FString &sFormulaSrc ) |
| @@ -54,34 +68,28 @@ namespace Bu | |||
| 54 | break; | 68 | break; |
| 55 | else if( tNum == symSubtract ) | 69 | else if( tNum == symSubtract ) |
| 56 | { | 70 | { |
| 57 | tNum = nextToken( &sFormula ); | 71 | sOper.push( symNegate ); |
| 58 | if( tNum != symNumber ) | 72 | continue; |
| 59 | throw ParseException( | ||
| 60 | "Unary minus must be followed by a number, " | ||
| 61 | "variable, function, or parenthesis."); | ||
| 62 | sValue.top() = -sValue.top(); | ||
| 63 | } | 73 | } |
| 64 | else if( tNum == symNot ) | 74 | else if( tNum == symNot ) |
| 65 | { | 75 | { |
| 66 | tNum = nextToken( &sFormula ); | 76 | sOper.push( symNot ); |
| 67 | if( tNum != symNumber ) | 77 | continue; |
| 68 | throw ParseException( | ||
| 69 | "Unary, binary not must be followed by a number, " | ||
| 70 | "variable, function, or parenthesis."); | ||
| 71 | sValue.top() = static_cast<prec>( | ||
| 72 | ~static_cast<bin>(sValue.top()) | ||
| 73 | ); | ||
| 74 | } | 78 | } |
| 75 | else if( tNum == symOpenParen ) | 79 | else if( tNum == symOpenParen ) |
| 76 | { | 80 | { |
| 77 | sOper.push( tNum ); | 81 | sOper.push( tNum ); |
| 78 | continue; | 82 | continue; |
| 79 | } | 83 | } |
| 84 | else if( tNum == symFunction ) | ||
| 85 | { | ||
| 86 | sOper.push( symFunction ); | ||
| 87 | continue; | ||
| 88 | } | ||
| 80 | 89 | ||
| 81 | oppart: uint8_t tOpr = nextToken( &sFormula ); | 90 | oppart: uint8_t tOpr = nextToken( &sFormula ); |
| 82 | if( tOpr == symEOS ) | 91 | if( tOpr == symEOS ) |
| 83 | { | 92 | { |
| 84 | //printf("EOS "); | ||
| 85 | reduce(); | 93 | reduce(); |
| 86 | return sValue.top(); | 94 | return sValue.top(); |
| 87 | break; | 95 | break; |
| @@ -103,29 +111,8 @@ namespace Bu | |||
| 103 | return sValue.top(); | 111 | return sValue.top(); |
| 104 | } | 112 | } |
| 105 | 113 | ||
| 106 | |||
| 107 | typedef Hash<Bu::FString, prec> varHash; | ||
| 108 | varHash hVars; | 114 | varHash hVars; |
| 109 | |||
| 110 | typedef struct Func | ||
| 111 | { | ||
| 112 | prec operator()( prec x ) | ||
| 113 | { | ||
| 114 | return 0; | ||
| 115 | } | ||
| 116 | } Func; | ||
| 117 | |||
| 118 | typedef Hash<Bu::FString, Func> funcHash; | ||
| 119 | funcHash hFunc; | 115 | funcHash hFunc; |
| 120 | /* | ||
| 121 | typedef struct FuncSin : Func | ||
| 122 | { | ||
| 123 | prec operator()( prec x ) | ||
| 124 | { | ||
| 125 | return sin( x ); | ||
| 126 | } | ||
| 127 | } FuncSin; | ||
| 128 | */ | ||
| 129 | 116 | ||
| 130 | private: | 117 | private: |
| 131 | enum | 118 | enum |
| @@ -139,7 +126,9 @@ namespace Bu | |||
| 139 | symCloseParen, | 126 | symCloseParen, |
| 140 | symNumber, | 127 | symNumber, |
| 141 | symVariable, | 128 | symVariable, |
| 129 | symFunction, | ||
| 142 | symExponent, | 130 | symExponent, |
| 131 | symNegate, | ||
| 143 | symModulus, | 132 | symModulus, |
| 144 | 133 | ||
| 145 | symAnd, | 134 | symAnd, |
| @@ -152,6 +141,7 @@ namespace Bu | |||
| 152 | 141 | ||
| 153 | Bu::Stack<symType> sOper; | 142 | Bu::Stack<symType> sOper; |
| 154 | Bu::Stack<prec> sValue; | 143 | Bu::Stack<prec> sValue; |
| 144 | Bu::Stack<Bu::FString> sFunc; | ||
| 155 | 145 | ||
| 156 | private: | 146 | private: |
| 157 | symType getPrec( symType nOper ) | 147 | symType getPrec( symType nOper ) |
| @@ -180,6 +170,8 @@ namespace Bu | |||
| 180 | 170 | ||
| 181 | case symExponent: | 171 | case symExponent: |
| 182 | case symNot: | 172 | case symNot: |
| 173 | case symNegate: | ||
| 174 | case symFunction: | ||
| 183 | return 3; | 175 | return 3; |
| 184 | 176 | ||
| 185 | default: | 177 | default: |
| @@ -260,7 +252,8 @@ namespace Bu | |||
| 260 | ". in them." | 252 | ". in them." |
| 261 | ); | 253 | ); |
| 262 | } | 254 | } |
| 263 | if( cbuf == '.' || (cbuf >= '0' && cbuf <= '9') ) | 255 | if( cbuf == '.' || |
| 256 | (cbuf >= '0' && cbuf <= '9') ) | ||
| 264 | { | 257 | { |
| 265 | num[nPos++] = cbuf; | 258 | num[nPos++] = cbuf; |
| 266 | } | 259 | } |
| @@ -297,16 +290,21 @@ namespace Bu | |||
| 297 | else | 290 | else |
| 298 | { | 291 | { |
| 299 | tok[nPos] = '\0'; | 292 | tok[nPos] = '\0'; |
| 300 | //printf("Checking variable \"%s\"\n", tok ); | 293 | if( hVars.has( tok ) ) |
| 301 | try | ||
| 302 | { | 294 | { |
| 303 | sValue.push( hVars[tok] ); | 295 | sValue.push( hVars[tok] ); |
| 304 | return symNumber; | 296 | return symNumber; |
| 305 | } | 297 | } |
| 306 | catch( HashException &e ) | 298 | else if( hFunc.has( tok ) ) |
| 299 | { | ||
| 300 | sFunc.push( tok ); | ||
| 301 | return symFunction; | ||
| 302 | } | ||
| 303 | else | ||
| 307 | { | 304 | { |
| 308 | throw ParseException( | 305 | throw ParseException( |
| 309 | "No variable named \"%s\" exists.", | 306 | "No variable or function named " |
| 307 | "\"%s\" exists.", | ||
| 310 | tok | 308 | tok |
| 311 | ); | 309 | ); |
| 312 | } | 310 | } |
| @@ -326,7 +324,6 @@ namespace Bu | |||
| 326 | uint8_t nOpr = sOper.top(); | 324 | uint8_t nOpr = sOper.top(); |
| 327 | if( nOpr == symOpenParen ) | 325 | if( nOpr == symOpenParen ) |
| 328 | { | 326 | { |
| 329 | //printf("Found ( stopping reduction.\n"); | ||
| 330 | if( bCloseParen == true ) | 327 | if( bCloseParen == true ) |
| 331 | sOper.pop(); | 328 | sOper.pop(); |
| 332 | return; | 329 | return; |
| @@ -339,34 +336,28 @@ namespace Bu | |||
| 339 | switch( nOpr ) | 336 | switch( nOpr ) |
| 340 | { | 337 | { |
| 341 | case symAdd: | 338 | case symAdd: |
| 342 | //printf("%f + %f = %f\n", sValue.top(), dTop, sValue.top()+dTop ); | ||
| 343 | sValue.top() += dTop; | 339 | sValue.top() += dTop; |
| 344 | break; | 340 | break; |
| 345 | 341 | ||
| 346 | case symSubtract: | 342 | case symSubtract: |
| 347 | //printf("%f - %f = %f\n", sValue.top(), dTop, sValue.top()-dTop ); | ||
| 348 | sValue.top() -= dTop; | 343 | sValue.top() -= dTop; |
| 349 | break; | 344 | break; |
| 350 | 345 | ||
| 351 | case symMultiply: | 346 | case symMultiply: |
| 352 | //printf("%f * %f = %f\n", sValue.top(), dTop, sValue.top()*dTop ); | ||
| 353 | sValue.top() *= dTop; | 347 | sValue.top() *= dTop; |
| 354 | break; | 348 | break; |
| 355 | 349 | ||
| 356 | case symDivide: | 350 | case symDivide: |
| 357 | //printf("%f / %f = %f\n", sValue.top(), dTop, sValue.top()/dTop ); | ||
| 358 | sValue.top() /= dTop; | 351 | sValue.top() /= dTop; |
| 359 | break; | 352 | break; |
| 360 | 353 | ||
| 361 | case symExponent: | 354 | case symExponent: |
| 362 | //printf("%f ^ %f = %f\n", sValue.top(), dTop, pow(sValue.top(),dTop) ); | ||
| 363 | sValue.top() = static_cast<prec>( | 355 | sValue.top() = static_cast<prec>( |
| 364 | pow( sValue.top(), dTop ) | 356 | pow( sValue.top(), dTop ) |
| 365 | ); | 357 | ); |
| 366 | break; | 358 | break; |
| 367 | 359 | ||
| 368 | case symModulus: | 360 | case symModulus: |
| 369 | //printf("%f %% %f = %f\n", sValue.top(), dTop, fmod(sValue.top(),dTop) ); | ||
| 370 | sValue.top() = static_cast<prec>( | 361 | sValue.top() = static_cast<prec>( |
| 371 | fmod( sValue.top(), dTop ) | 362 | fmod( sValue.top(), dTop ) |
| 372 | ); | 363 | ); |
| @@ -392,6 +383,20 @@ namespace Bu | |||
| 392 | static_cast<bin>(dTop) | 383 | static_cast<bin>(dTop) |
| 393 | ); | 384 | ); |
| 394 | break; | 385 | break; |
| 386 | |||
| 387 | case symFunction: | ||
| 388 | sValue.push( (*hFunc.get( sFunc.pop() ))( dTop ) ); | ||
| 389 | break; | ||
| 390 | |||
| 391 | case symNegate: | ||
| 392 | sValue.push( -dTop ); | ||
| 393 | break; | ||
| 394 | |||
| 395 | case symNot: | ||
| 396 | sValue.push( static_cast<prec>( | ||
| 397 | ~static_cast<bin>(dTop) | ||
| 398 | ) ); | ||
| 399 | break; | ||
| 395 | } | 400 | } |
| 396 | } | 401 | } |
| 397 | 402 | ||
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 @@ | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "bu/formula.h" | 8 | #include "bu/formula.h" |
| 9 | #include <math.h> | ||
| 9 | 10 | ||
| 10 | int main( int argc, char *argv[] ) | 11 | int main( int argc, char *argv[] ) |
| 11 | { | 12 | { |
| @@ -17,7 +18,18 @@ int main( int argc, char *argv[] ) | |||
| 17 | Bu::Formula<uint32_t> uForm; | 18 | Bu::Formula<uint32_t> uForm; |
| 18 | Bu::Formula<double> dForm; | 19 | Bu::Formula<double> dForm; |
| 19 | 20 | ||
| 20 | printf("u: %s = %u\n", argv[1], uForm.run( argv[1] ) ); | 21 | class CeilFunc : public Bu::Formula<double>::Func |
| 22 | { | ||
| 23 | public: | ||
| 24 | virtual double operator()( double x ) | ||
| 25 | { | ||
| 26 | return ceil( x ); | ||
| 27 | } | ||
| 28 | }; | ||
| 29 | |||
| 30 | dForm.hFunc.insert( "ceil", new CeilFunc() ); | ||
| 31 | |||
| 32 | // printf("u: %s = %u\n", argv[1], uForm.run( argv[1] ) ); | ||
| 21 | printf("d: %s = %f\n", argv[1], dForm.run( argv[1] ) ); | 33 | printf("d: %s = %f\n", argv[1], dForm.run( argv[1] ) ); |
| 22 | 34 | ||
| 23 | return 0; | 35 | return 0; |
