aboutsummaryrefslogtreecommitdiff
path: root/src/old/formula.cpp
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2007-04-03 03:49:53 +0000
committerMike Buland <eichlan@xagasoft.com>2007-04-03 03:49:53 +0000
commitf4c20290509d7ed3a8fd5304577e7a4cc0b9d974 (patch)
tree13cdf64f7cf134f397a7165b7a3fe0807e37026b /src/old/formula.cpp
parent74d4c8cd27334fc7204d5a8773deb3d424565778 (diff)
downloadlibbu++-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.cpp262
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
3subExceptionDef( ParseException );
4
5Formula::Formula()
6{
7 hVars["pi"] = M_PI;
8 hVars["e"] = M_E;
9
10 hFunc["sin"] = FuncSin();
11}
12
13Formula::~Formula()
14{
15}
16
17double 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
38oppart: 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
63void 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
120uint8_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
147uint8_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