diff options
author | Mike Buland <eichlan@xagasoft.com> | 2009-01-20 07:03:31 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2009-01-20 07:03:31 +0000 |
commit | 40360b48f4d9ea82200528411a0ed62d2c0e10bb (patch) | |
tree | 0ec8ff2920108a833a72d674e081da0c575e9248 /src | |
parent | 2563702e7fa631efbd8f135309817c9d91bec728 (diff) | |
download | libbu++-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.
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; |