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; |