new rule: wipe
[calc.git] / parser.c
1 #include <malloc.h>
2 #include <math.h>
3 #include <stdlib.h>
4
5 #include "debug.h"
6 #include "fdprintf.h"
7
8 #include "parser.h"
9
10 /* compare codes */
11
12 int codecmp (char *ref, char *str)
13 {
14 int sig;
15
16 while (*ref != '\0') {
17 if (*ref == '\t') {
18 sig = (*str == '.') ? -1 : ((*str >= '0') && (*str <= '9'));
19 } else {
20 sig = *str - *ref;
21 }
22 if (sig != 0) {
23 return (sig > 0) ? 1 : -1;
24 }
25 str++;
26 ref++;
27 }
28
29 return 0;
30 }
31
32 /* allocate new element */
33
34 element_t *newelement (func_t function, int nbops, int prio)
35 {
36 element_t *new = (element_t *) calloc (1, sizeof (element_t));
37 if (new == NULL) {
38 VERBOSE (ERROR, fdprintf (stdfderr, "can't allocate memory\n"));
39 return NULL;
40 }
41 new->func = function;
42 new->nbops = nbops;
43 new->prio = prio;
44
45 return new;
46 }
47
48 /* functions */
49
50 #define NB_OPERATORS 6
51
52 keyword_t operators[NB_OPERATORS] = {
53 { "+\t", Add, 2, 1, 1},
54 { "-\t", Sub, 2, 1, 1},
55 { "*", Mul, 2, 1, 2},
56 { "/", Div, 2, 1, 2},
57 { "%", Mod, 2, 1, 3},
58 { "^", Pow, 2, 1, 4}
59 };
60
61 #define NB_FUNCTIONS 9
62 keyword_t functions[NB_FUNCTIONS] = {
63 { "sqrt", Sqr, 1, 4, 5},
64 { "pow", Pow, 2, 3, 5},
65 { "cos", Cos, 1, 3, 5},
66 { "sin", Sin, 1, 3, 5},
67 { "atan", Atn, 1, 4, 5},
68 { "exp", Exp, 1, 3, 5},
69 { "log", Log, 1, 3, 5},
70 { "quit", Qui, 0, 4, 5},
71 { "help", Hel, 0, 4, 5}
72 };
73
74 /* subparser function */
75
76 element_t *subparser (element_t **proot, char **pstr, func_t func, int nbops, int prio)
77 {
78 element_t *new = newelement (func, nbops, prio);
79 if (new == NULL) {
80 return ERROR_OP;
81 }
82 new->ops[0] = *proot;
83 new->ops[1] = parser (*pstr, pstr, new->prio);
84 if (new->ops[1] == ERROR_OP) {
85 return ERROR_OP;
86 }
87 *proot = newelement (Val, 1, 5);
88 if (*proot == ERROR_OP) {
89 return ERROR_OP;
90 }
91 (*proot)->ops[0] = new;
92
93 return *proot;
94 }
95
96 /* parser function */
97
98 element_t *parser (char *str, char **next, int prio)
99 {
100 element_t *root = NULL;
101 int i;
102
103 VERBOSE (DEBUG, PRINTOUT ("Starting parsing\n"));
104
105 /* main loop */
106 while (*str != '\0') {
107 int found = 0;
108 element_t *new = NULL;
109 VERBOSE (INFO, PRINTOUT ("Processing: %s\n", str));
110
111 /* skip spaces and tabs */
112
113 if ((*str == ' ') || (*str == '\t')) {
114 str++;
115 continue;
116 }
117
118 /* check for open bracket */
119
120 if (*str == '(') {
121 VERBOSE (DEBUG, PRINTOUT ("start processing bracket\n"));
122 if (root) {
123 do {
124 found = 0;
125 new = parser (str + 1, &str, 0);
126 if (new == ERROR_OP) {
127 return ERROR_OP;
128 }
129 for (i = 0; i < root->nbops; i++) {
130 if (root->ops[i] == NULL) {
131 root->ops[i] = new;
132 found = 1;
133 break;
134 }
135 }
136 if (!found) {
137 return ERROR_OP;
138 }
139 } while (*str == ',');
140 } else {
141 root = newelement (Val, 1, 5);
142 if (root == NULL) {
143 return ERROR_OP;
144 }
145 new = parser (str + 1, &str, 0);
146 if ((new == ERROR_OP) || (*str == ',')) {
147 return ERROR_OP;
148 }
149 root->ops[0] = new;
150 }
151 str++;
152 VERBOSE (DEBUG, PRINTOUT ("stop processing bracket\n"));
153 continue;
154 }
155
156 /* check for closing bracket or koma */
157
158 if ((*str == ')') || (*str == ',')) {
159 if (next != NULL) {
160 *next = str;
161 }
162 return root;
163 }
164
165 /* look for operators */
166
167 for (i = 0; i < NB_OPERATORS; i++) {
168 keyword_t *operator = operators + i;
169 if (codecmp (operator->keyword, str) == 0) {
170 VERBOSE (DEBUG, PRINTOUT ("start processing operator\n"));
171 if (root) {
172 if ((prio) && (prio > operator->prio)) {
173 VERBOSE (DEBUG, PRINTOUT ("stop because operator priority\n"));
174 *next = str;
175 return root;
176 }
177 str += operator->offset;
178 VERBOSE (INFO, PRINTOUT ("Oper: %d\n", operator->func));
179 if (subparser (&root, &str, operator->func, operator->nbops, operator->prio) == ERROR_OP) {
180 return ERROR_OP;
181 }
182 } else if (*str == '-') {
183 new = newelement (Sig, 1, 9);
184 if (new == NULL) {
185 return ERROR_OP;
186 }
187 root = new;
188 } else {
189 return ERROR_OP;
190 }
191 found = 1;
192 VERBOSE (DEBUG, PRINTOUT ("stop processing operator\n"));
193 break;
194 }
195 }
196 if (found) {
197 continue;
198 }
199
200 /* look for functions */
201
202 for (i = 0; i < NB_FUNCTIONS; i++) {
203 keyword_t *function = functions + i;
204 if (codecmp (function->keyword, str) == 0) {
205 VERBOSE (DEBUG, PRINTOUT ("start processing function\n"));
206 if (root == NULL) {
207 VERBOSE (INFO, PRINTOUT ("Func: %d\n", function->func));
208 new = newelement (function->func, function->nbops, function->prio);
209 if (new == NULL) {
210 return ERROR_OP;
211 }
212 root = new;
213 } else {
214 return ERROR_OP;
215 }
216 str += function->offset;
217 found = 1;
218 VERBOSE (DEBUG, PRINTOUT ("stop processing function\n"));
219 break;
220 }
221 }
222 if (found) {
223 continue;
224 }
225
226 /* look for number */
227
228 if (((*str >= '0') && (*str <= '9')) ||
229 (*str == '.') || (*str == '+') || (*str == '-')) {
230 VERBOSE (DEBUG, PRINTOUT ("start processing value\n"));
231 char *pt;
232 float value = strtof (str, &pt);
233 VERBOSE (INFO, PRINTOUT ("Value: %f\n", value));
234 if (str != pt) {
235 if (root == NULL) {
236 new = newelement (Val, 1, 5);
237 if (new == NULL) {
238 return ERROR_OP;
239 }
240 new->value = value;
241 root = new;
242 str = pt;
243 } else if (root->func == Val) {
244 if ((*str == '+') || (*str == '-')) {
245 if ((prio) && (prio > 1)) {
246 VERBOSE (DEBUG, PRINTOUT ("stop because operator priority\n"));
247 *next = str;
248 return root;
249 }
250 if (subparser (&root, &str, Add, 2, 1) == ERROR_OP) {
251 return ERROR_OP;
252 }
253 } else {
254 return ERROR_OP;
255 }
256 } else {
257 return ERROR_OP;
258 }
259 found = 1;
260 }
261 VERBOSE (DEBUG, PRINTOUT ("stop processing value\n"));
262 }
263
264 /* error */
265
266 if (!found) {
267 return ERROR_OP;
268 }
269
270 }
271
272 if (next != NULL) {
273 *next = str;
274 }
275 return root;
276 }
277
278 /* print element tree */
279
280 void print_element (element_t *root, int level)
281 {
282 char *func = NULL;
283 int i;
284
285 if ((root == NULL) || (root == ERROR_OP)) {
286 return;
287 }
288
289 for (i = 0; i < level; i++) {
290 PRINTOUT (" ");
291 }
292
293 switch (root->func) {
294 case Val: func = "Value"; break;
295 case Sig: func = "Sign"; break;
296 case Add: func = "Addition"; break;
297 case Sub: func = "Subtraction"; break;
298 case Mul: func = "Multiplication"; break;
299 case Div: func = "Division"; break;
300 case Mod: func = "Modulo"; break;
301 case Pow: func = "Power"; break;
302 case Sqr: func = "Square Root"; break;
303 case Cos: func = "Cosine"; break;
304 case Sin: func = "Sine"; break;
305 case Atn: func = "Arc Tangent"; break;
306 case Log: func = "Logarithm"; break;
307 case Exp: func = "Exponantial"; break;
308 case Qui: func = "Quit"; break;
309 case Hel: func = "Help"; break;
310 }
311
312 PRINTOUT ("Function: %s\n", func);
313
314 if ((root->func == Val) && (root->ops[0] == NULL)) {
315 for (i = 0; i < level; i++) {
316 PRINTOUT (" ");
317 }
318 PRINTOUT ("value: %f\n", root->value);
319 } else {
320 for (i = 0; i < root->nbops; i++) {
321 print_element (root->ops[i], level + 1);
322 }
323 }
324 }
325
326 /* quit function */
327
328 void quit (void)
329 {
330 PRINTOUT ("bye\n");
331 exit (0);
332 }
333
334 /* help message */
335
336 void help (void)
337 {
338 PRINTOUT ("calc is a simple calculator\n\n");
339 PRINTOUT ("supported operators:\n");
340 PRINTOUT (" + - * / % ^\n\n");
341 PRINTOUT ("supported functions:\n");
342 PRINTOUT (" pow sqrt cos sin atan log exp\n\n");
343 PRINTOUT ("miscellaneous functions:\n");
344 PRINTOUT (" quit help\n");
345 }
346
347 /* evaluate element tree */
348
349 #define MASK_SUB 0x1
350 #define MASK_DIV 0x2
351
352 double evaluate_element (element_t *root, char mask)
353 {
354 double op0 = 0, op1 = 0;
355 char nextmask = mask;
356
357 if ((root == NULL) || (root == ERROR_OP)) {
358 VERBOSE (WARNING, PRINTOUT ("error while evaluating\n"));
359 return 0;
360 }
361
362 /* mask to manage sub operator sub and div */
363 switch (root->func) {
364 case Add:
365 nextmask &= ~MASK_SUB;
366 nextmask &= ~MASK_DIV;
367 break;
368 case Sub:
369 nextmask |= MASK_SUB;
370 nextmask &= ~MASK_DIV;
371 break;
372 case Mul:
373 nextmask &= ~MASK_DIV;
374 break;
375 case Div:
376 nextmask |= MASK_DIV;
377 break;
378 default:
379 nextmask = mask;
380 }
381
382 switch (root->func) {
383 case Val:
384 case Sig:
385 op0 = (root->ops[0]) ? evaluate_element (root->ops[0], nextmask) : root->value;
386 break;
387 case Add:
388 case Sub:
389 case Mul:
390 case Div:
391 case Mod:
392 case Pow:
393 if (root->ops[1]) {
394 op1 = evaluate_element (root->ops[1], nextmask);
395 } else {
396 VERBOSE (WARNING, PRINTOUT ("error while evaluating (op[1])\n"));
397 return 0;
398 }
399 /* fallthrough */
400 case Sqr:
401 case Cos:
402 case Sin:
403 case Atn:
404 case Log:
405 case Exp:
406 if (root->ops[0]) {
407 op0 = evaluate_element (root->ops[0], 0);
408 } else {
409 VERBOSE (WARNING, PRINTOUT ("error while evaluating (op[0])\n"));
410 return 0;
411 }
412 break;
413 case Qui:
414 case Hel:
415 break;
416 }
417
418 switch (root->func) {
419 case Val: return op0;
420 case Sig: return -op0;
421 case Add: return ((mask & MASK_SUB) == 0) ? op0 + op1 : op0 - op1;
422 case Sub: return ((mask & MASK_SUB) == 0) ? op0 - op1 : op0 + op1;
423 case Mul: return ((mask & MASK_DIV) == 0) ? op0 * op1 : op0 / op1;
424 case Div: return ((mask & MASK_DIV) == 0) ? op0 / op1 : op0 * op1;
425 case Mod: return fmod (op0, op1);
426 case Pow: return pow (op0, op1);
427 case Sqr: return sqrt (op0);
428 case Cos: return cos (op0);
429 case Sin: return sin (op0);
430 case Atn: return atan (op0);
431 case Log: return log (op0);
432 case Exp: return exp (op0);
433 case Qui: quit (); break;
434 case Hel: help (); break;
435 }
436
437 return 0;
438 }
439
440 /* vim: set ts=4 sw=4 et: */