diff options
author | Mike Buland <eichlan@xagasoft.com> | 2007-04-03 03:49:53 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2007-04-03 03:49:53 +0000 |
commit | f4c20290509d7ed3a8fd5304577e7a4cc0b9d974 (patch) | |
tree | 13cdf64f7cf134f397a7165b7a3fe0807e37026b /src/old/formula.cpp | |
parent | 74d4c8cd27334fc7204d5a8773deb3d424565778 (diff) | |
download | libbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.tar.gz libbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.tar.bz2 libbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.tar.xz libbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.zip |
Ok, no code is left in src, it's all in src/old. We'll gradually move code back
into src as it's fixed and re-org'd. This includes tests, which, I may write a
unit test system into libbu++ just to make my life easier.
Diffstat (limited to 'src/old/formula.cpp')
-rw-r--r-- | src/old/formula.cpp | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/old/formula.cpp b/src/old/formula.cpp new file mode 100644 index 0000000..cf63cf3 --- /dev/null +++ b/src/old/formula.cpp | |||
@@ -0,0 +1,262 @@ | |||
1 | #include "formula.h" | ||
2 | |||
3 | subExceptionDef( ParseException ); | ||
4 | |||
5 | Formula::Formula() | ||
6 | { | ||
7 | hVars["pi"] = M_PI; | ||
8 | hVars["e"] = M_E; | ||
9 | |||
10 | hFunc["sin"] = FuncSin(); | ||
11 | } | ||
12 | |||
13 | Formula::~Formula() | ||
14 | { | ||
15 | } | ||
16 | |||
17 | double Formula::run( char *sFormula ) | ||
18 | { | ||
19 | for(;;) | ||
20 | { | ||
21 | uint8_t tNum = nextToken( &sFormula ); | ||
22 | if( tNum == symEOS ) | ||
23 | break; | ||
24 | else if( tNum == symSubtract ) | ||
25 | { | ||
26 | tNum = nextToken( &sFormula ); | ||
27 | if( tNum != symNumber ) | ||
28 | throw ParseException("Unary minus must be followed by a number, " | ||
29 | "variable, function, or parenthesis."); | ||
30 | sValue.top() = -sValue.top(); | ||
31 | } | ||
32 | else if( tNum == symOpenParen ) | ||
33 | { | ||
34 | sOper.push( tNum ); | ||
35 | continue; | ||
36 | } | ||
37 | |||
38 | oppart: uint8_t tOpr = nextToken( &sFormula ); | ||
39 | if( tOpr == symEOS ) | ||
40 | { | ||
41 | //printf("EOS "); | ||
42 | reduce(); | ||
43 | return sValue.top(); | ||
44 | break; | ||
45 | } | ||
46 | if( !sOper.empty() && getPrec( sOper.top() ) > getPrec( tOpr ) ) | ||
47 | { | ||
48 | reduce(); | ||
49 | } | ||
50 | if( tOpr != symCloseParen ) | ||
51 | { | ||
52 | sOper.push( tOpr ); | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | reduce( true ); | ||
57 | goto oppart; | ||
58 | } | ||
59 | } | ||
60 | return sValue.top(); | ||
61 | } | ||
62 | |||
63 | void Formula::reduce( bool bCloseParen ) | ||
64 | { | ||
65 | while( !sOper.empty() ) | ||
66 | { | ||
67 | uint8_t nOpr = sOper.top(); | ||
68 | if( nOpr == symOpenParen ) | ||
69 | { | ||
70 | //printf("Found ( stopping reduction.\n"); | ||
71 | if( bCloseParen == true ) | ||
72 | sOper.pop(); | ||
73 | return; | ||
74 | } | ||
75 | sOper.pop(); | ||
76 | |||
77 | double dTop = sValue.top(); | ||
78 | sValue.pop(); | ||
79 | |||
80 | switch( nOpr ) | ||
81 | { | ||
82 | case symAdd: | ||
83 | //printf("%f + %f = %f\n", sValue.top(), dTop, sValue.top()+dTop ); | ||
84 | sValue.top() += dTop; | ||
85 | break; | ||
86 | |||
87 | case symSubtract: | ||
88 | //printf("%f - %f = %f\n", sValue.top(), dTop, sValue.top()-dTop ); | ||
89 | sValue.top() -= dTop; | ||
90 | break; | ||
91 | |||
92 | case symMultiply: | ||
93 | //printf("%f * %f = %f\n", sValue.top(), dTop, sValue.top()*dTop ); | ||
94 | sValue.top() *= dTop; | ||
95 | break; | ||
96 | |||
97 | case symDivide: | ||
98 | //printf("%f / %f = %f\n", sValue.top(), dTop, sValue.top()/dTop ); | ||
99 | sValue.top() /= dTop; | ||
100 | break; | ||
101 | |||
102 | case symExponent: | ||
103 | //printf("%f ^ %f = %f\n", sValue.top(), dTop, pow(sValue.top(),dTop) ); | ||
104 | sValue.top() = pow( sValue.top(), dTop ); | ||
105 | break; | ||
106 | |||
107 | case symModulus: | ||
108 | //printf("%f %% %f = %f\n", sValue.top(), dTop, fmod(sValue.top(),dTop) ); | ||
109 | sValue.top() = fmod( sValue.top(), dTop ); | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if( bCloseParen == true ) | ||
115 | { | ||
116 | throw ParseException("Close-paren found without matching open-paren."); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | uint8_t Formula::getPrec( uint8_t nOper ) | ||
121 | { | ||
122 | switch( nOper ) | ||
123 | { | ||
124 | case symNumber: | ||
125 | case symVariable: | ||
126 | case symOpenParen: | ||
127 | case symCloseParen: | ||
128 | return 0; | ||
129 | |||
130 | case symAdd: | ||
131 | case symSubtract: | ||
132 | return 1; | ||
133 | |||
134 | case symMultiply: | ||
135 | case symDivide: | ||
136 | case symModulus: | ||
137 | return 2; | ||
138 | |||
139 | case symExponent: | ||
140 | return 3; | ||
141 | |||
142 | default: | ||
143 | return 0; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | uint8_t Formula::nextToken( char **sBuf ) | ||
148 | { | ||
149 | for(;;) | ||
150 | { | ||
151 | char cbuf = **sBuf; | ||
152 | ++(*sBuf); | ||
153 | switch( cbuf ) | ||
154 | { | ||
155 | case '+': | ||
156 | return symAdd; | ||
157 | |||
158 | case '-': | ||
159 | return symSubtract; | ||
160 | |||
161 | case '*': | ||
162 | return symMultiply; | ||
163 | |||
164 | case '/': | ||
165 | return symDivide; | ||
166 | |||
167 | case '^': | ||
168 | return symExponent; | ||
169 | |||
170 | case '%': | ||
171 | return symModulus; | ||
172 | |||
173 | case '(': | ||
174 | return symOpenParen; | ||
175 | |||
176 | case ')': | ||
177 | return symCloseParen; | ||
178 | |||
179 | case ' ': | ||
180 | case '\t': | ||
181 | case '\n': | ||
182 | case '\r': | ||
183 | break; | ||
184 | |||
185 | case '\0': | ||
186 | return symEOS; | ||
187 | |||
188 | default: | ||
189 | if( cbuf == '.' || (cbuf >= '0' && cbuf <= '9') ) | ||
190 | { | ||
191 | char num[50]={cbuf}; | ||
192 | int nPos = 1; | ||
193 | bool bDot = false; | ||
194 | |||
195 | for(;;) | ||
196 | { | ||
197 | cbuf = **sBuf; | ||
198 | if( cbuf == '.' ) | ||
199 | { | ||
200 | if( bDot == false ) | ||
201 | bDot = true; | ||
202 | else | ||
203 | throw ParseException( | ||
204 | "Numbers cannot have more than one " | ||
205 | ". in them." | ||
206 | ); | ||
207 | } | ||
208 | if( cbuf == '.' || (cbuf >= '0' && cbuf <= '9') ) | ||
209 | { | ||
210 | num[nPos++] = cbuf; | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | num[nPos] = '\0'; | ||
215 | sValue.push( strtod( num, NULL ) ); | ||
216 | return symNumber; | ||
217 | } | ||
218 | ++(*sBuf); | ||
219 | } | ||
220 | } | ||
221 | else if( (cbuf >= 'a' && cbuf <= 'z') || | ||
222 | (cbuf >= 'A' && cbuf <= 'Z') || | ||
223 | (cbuf == '_') ) | ||
224 | { | ||
225 | char tok[50]={cbuf}; | ||
226 | int nPos = 1; | ||
227 | |||
228 | for(;;) | ||
229 | { | ||
230 | cbuf = **sBuf; | ||
231 | if( (cbuf >= 'a' && cbuf <= 'z') || | ||
232 | (cbuf >= 'A' && cbuf <= 'Z') || | ||
233 | (cbuf >= '0' && cbuf <= '9') || | ||
234 | cbuf == '_' || cbuf == '.' || cbuf == ':' ) | ||
235 | { | ||
236 | tok[nPos++] = cbuf; | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | tok[nPos] = '\0'; | ||
241 | //printf("Checking variable \"%s\"\n", tok ); | ||
242 | try | ||
243 | { | ||
244 | sValue.push( hVars[tok] ); | ||
245 | return symNumber; | ||
246 | } | ||
247 | catch( HashException &e ) | ||
248 | { | ||
249 | throw ParseException( | ||
250 | "No variable named \"%s\" exists.", | ||
251 | tok | ||
252 | ); | ||
253 | } | ||
254 | } | ||
255 | ++(*sBuf); | ||
256 | } | ||
257 | } | ||
258 | break; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||