e7c91888f15cec4380aabf2d6b65537a06ca200a
[calc.git] / parser.c
1 #include <malloc.h>
2 #include <stdlib.h>
3
4 #include "debug.h"
5 #include "fdprintf.h"
6
7 #include "parser.h"
8
9 /* compare codes */
10
11 int codecmp (char *ref, char *str)
12 {
13 int sig;
14
15 while (*ref != '\0') {
16 sig = *str++ - *ref++;
17 if (sig != 0) {
18 return (sig > 0) ? 1 : -1;
19 }
20 }
21
22 return 0;
23 }
24
25 /* allocate new element */
26
27 element_t *newelement (func_t function, int nbops)
28 {
29 element_t *new = (element_t *) calloc (1, sizeof (element_t));
30 if (new == NULL) {
31 VERBOSE (ERROR, fdprintf (stdfderr, "can't allocate memory\n"));
32 return NULL;
33 }
34 new->func = function;
35 new->nbops = nbops;
36
37 return new;
38 }
39
40 /* functions */
41
42 #define NB_OPERATORS 7
43
44 keyword_t operators[NB_OPERATORS] = {
45 { "+ ", Add, 2, 1 },
46 { "+\t", Add, 2, 1 },
47 { "- ", Sub, 2, 1 },
48 { "-\t", Sub, 2, 1 },
49 { "*", Mul, 2, 1 },
50 { "/", Div, 2, 1 },
51 { "^", Pow, 2, 1 }
52 };
53
54 #define NB_FUNCTIONS 7
55 keyword_t functions[NB_FUNCTIONS] = {
56 { "sqrt", Sqr, 1, 4 },
57 { "pow", Pow, 2, 3 },
58 { "cos", Cos, 1, 3 },
59 { "sin", Sin, 1, 3 },
60 { "atan", Atn, 1, 4 },
61 { "exp", Exp, 1, 3 },
62 { "log", Log, 1, 3 }
63 };
64
65 /* parser function */
66
67 element_t *parser (char *str, char **next)
68 {
69 element_t *root = NULL;
70 int i, j;
71
72 VERBOSE (DEBUG, PRINTOUT ("Starting parsing\n"));
73
74 /* main loop */
75 while (*str != '\0') {
76 int found = 0;
77 element_t *new = NULL;
78 VERBOSE (INFO, PRINTOUT ("Processing: %s\n", str));
79
80 /* skip spaces and tabs */
81
82 if ((*str == ' ') || (*str == '\t')) {
83 str++;
84 continue;
85 }
86
87 /* skip commas */
88
89 if (*str == ',') {
90 VERBOSE (DEBUG, PRINTOUT ("start processing coma\n"));
91 str++;
92 if (root == NULL) {
93 return parser (str, &str);
94 } else if (root->func != Set) {
95 new = newelement (Set, MAX_OPERANDS);
96 if (new == NULL) {
97 return ERROR_OP;
98 }
99 new->ops[0] = root;
100 root = new;
101 VERBOSE (DEBUG, PRINTOUT ("end processing first coma\n"));
102 } else /* if (root->func == Set) */ {
103 new = parser (str, &str);
104 if (!found){
105 return ERROR_OP;
106 }
107 for (i = 0; i < root->nbops; i++) {
108 if (root->ops[i] == NULL) {
109 root->ops[i] = new;
110 found = 1;
111 }
112 }
113 if (!found){
114 return ERROR_OP;
115 }
116 VERBOSE (DEBUG, PRINTOUT ("end processing other coma\n"));
117 }
118 continue;
119 }
120
121 /* check for parent */
122
123 if (*str == '(') {
124 VERBOSE (DEBUG, PRINTOUT ("start processing bracket\n"));
125 new = parser (str + 1, &str);
126 if (new == ERROR_OP) {
127 return ERROR_OP;
128 }
129 if (root) {
130 for (i = 0, j = 0; i < root->nbops; i++) {
131 if (root->ops[i] == NULL) {
132 if (new->func == Set) {
133 root->ops[i] = new->ops[j++];
134 if (new->ops[j] == NULL) {
135 found = 1;
136 break;
137 }
138 } else {
139 root->ops[i] = new;
140 found = 1;
141 break;
142 }
143 }
144 }
145 if (!found) {
146 return ERROR_OP;
147 }
148 } else {
149 if (new->func != Set) {
150 root = new;
151 } else {
152 return ERROR_OP;
153 }
154 }
155 VERBOSE (DEBUG, PRINTOUT ("stop processing bracket\n"));
156 //if (next != NULL) {
157 // *next = str;
158 //}
159 //return root;
160 continue;
161 }
162 if (*str == ')') {
163 if (next != NULL) {
164 *next = str + 1;
165 }
166 return root;
167 }
168
169 /* look for operators */
170
171 for (i = 0; i < NB_OPERATORS; i++) {
172 keyword_t *operator = operators + i;
173 if (codecmp (operator->keyword, str) == 0) {
174 VERBOSE (DEBUG, PRINTOUT ("start processing operator\n"));
175 str += operator->offset;
176 if ((root) && (root->func != Set)) {
177 VERBOSE (INFO, PRINTOUT ("Oper: %d\n", operator->func));
178 new = newelement (operator->func, operator->nbops);
179 if (new == NULL) {
180 return ERROR_OP;
181 }
182 new->ops[0] = root;
183 root = new;
184 new = parser (str, &str);
185 if (new == ERROR_OP) {
186 return ERROR_OP;
187 }
188 root->ops[1] = new;
189 } else {
190 return ERROR_OP;
191 }
192 found = 1;
193 VERBOSE (DEBUG, PRINTOUT ("stop processing operator\n"));
194 break;
195 }
196 }
197 if (found) {
198 continue;
199 }
200
201 /* look for functions */
202
203 for (i = 0; i < NB_FUNCTIONS; i++) {
204 keyword_t *function = functions + i;
205 if (codecmp (function->keyword, str) == 0) {
206 VERBOSE (DEBUG, PRINTOUT ("start processing function\n"));
207 if (root == NULL) {
208 VERBOSE (INFO, PRINTOUT ("Func: %d\n", function->func));
209 new = newelement (function->func, function->nbops);
210 if (new == NULL) {
211 return ERROR_OP;
212 }
213 root = new;
214 } else {
215 return ERROR_OP;
216 }
217 str += function->offset;
218 found = 1;
219 VERBOSE (DEBUG, PRINTOUT ("stop processing function\n"));
220 break;
221 }
222 }
223 if (found) {
224 continue;
225 }
226
227 /* last attend to detect addition and substraction */
228
229 if (((*str == '-') || (*str == '+')) &&
230 ((*(str + 1) >= '0') && (*(str + 1) <= '9')) &&
231 ((root) && (root->func == Val))) {
232 VERBOSE (INFO, PRINTOUT ("Oper: %d\n", Add));
233 new = newelement (Add, 2);
234 if (new == NULL) {
235 return ERROR_OP;
236 }
237 new->ops[0] = root;
238 root = new;
239 }
240
241 /* look for number */
242
243 if (((*str >= '0') && (*str <= '9')) || (*str == '.')) {
244 VERBOSE (DEBUG, PRINTOUT ("start processing value\n"));
245 char *pt;
246 float value = strtof (str, &pt);
247 VERBOSE (INFO, PRINTOUT ("Value: %f\n", value));
248 if (str != pt) {
249 new = newelement (Val, 1);
250 if (new == NULL) {
251 return ERROR_OP;
252 }
253 new->value = value;
254 if (root == NULL) {
255 root = new;
256 } else {
257 if (root->func == Val) {
258 element_t *set = newelement (Set, MAX_OPERANDS);
259 if (set == NULL) {
260 return ERROR_OP;
261 }
262 set->ops[0] = root;
263 root = set;
264 }
265 for (i = 0; i < root->nbops; i++) {
266 if (root->ops[i] == NULL) {
267 root->ops[i] = new;
268 found = 1;
269 break;
270 }
271 }
272 if (!found) {
273 return ERROR_OP;
274 }
275 }
276 str = pt;
277 found = 1;
278 }
279 VERBOSE (DEBUG, PRINTOUT ("stop processing value\n"));
280 }
281
282 /* error */
283
284 if (!found) {
285 return ERROR_OP;
286 }
287
288 }
289
290 if (next != NULL) {
291 *next = str;
292 }
293 return root;
294 }
295
296 /* print element tree */
297
298 void print_element (element_t *root, int level)
299 {
300 char *func = NULL;
301 int i;
302
303 if ((root == NULL) || (root == ERROR_OP)) {
304 return;
305 }
306
307 for (i = 0; i < level; i++) {
308 PRINTOUT (" ");
309 }
310
311 switch (root->func) {
312 case Val: func = "Value"; break;
313 case Set: func = "Set"; break;
314 case Add: func = "Addition"; break;
315 case Sub: func = "Subtraction"; break;
316 case Mul: func = "Multiplication"; break;
317 case Div: func = "Division"; break;
318 case Pow: func = "Power"; break;
319 case Sqr: func = "Square Root"; break;
320 case Cos: func = "Cosine"; break;
321 case Sin: func = "Sine"; break;
322 case Atn: func = "Arc Tangent"; break;
323 case Log: func = "Logarithm"; break;
324 case Exp: func = "Exponantial"; break;
325 }
326
327 PRINTOUT ("Function: %s\n", func);
328
329 if (root->func == Val) {
330 for (i = 0; i < level; i++) {
331 PRINTOUT (" ");
332 }
333 PRINTOUT ("value: %f\n", root->value);
334 } else {
335 for (i = 0; i < root->nbops; i++) {
336 print_element (root->ops[i], level + 1);
337 }
338 }
339 }
340
341 /* vim: set ts=4 sw=4 et: */