summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2009-01-20 07:03:31 +0000
committerMike Buland <eichlan@xagasoft.com>2009-01-20 07:03:31 +0000
commit40360b48f4d9ea82200528411a0ed62d2c0e10bb (patch)
tree0ec8ff2920108a833a72d674e081da0c575e9248
parent2563702e7fa631efbd8f135309817c9d91bec728 (diff)
downloadlibbu++-40360b48f4d9ea82200528411a0ed62d2c0e10bb.tar.gz
libbu++-40360b48f4d9ea82200528411a0ed62d2c0e10bb.tar.bz2
libbu++-40360b48f4d9ea82200528411a0ed62d2c0e10bb.tar.xz
libbu++-40360b48f4d9ea82200528411a0ed62d2c0e10bb.zip
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.
-rw-r--r--src/formula.h101
-rw-r--r--src/tests/formula.cpp14
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
10int main( int argc, char *argv[] ) 11int 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;