correct issue when using %f with 0
[calc.git] / parser.c
CommitLineData
bc97a989
LM
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
11int 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
27element_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
44keyword_t operators[NB_OPERATORS] = {
45 { "+ ", Add, 2, 1 },
46 { "+\t", Add, 2, 1 },
47 { "- ", Sub, 2, 1 },
49223129 48 { "-\t", Sub, 2, 1 },
bc97a989
LM
49 { "*", Mul, 2, 1 },
50 { "/", Div, 2, 1 },
51 { "^", Pow, 2, 1 }
52};
53
54#define NB_FUNCTIONS 7
55keyword_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
0b489a77
LM
67element_t *parser (char *str, char **next)
68{
bc97a989 69 element_t *root = NULL;
0b489a77 70 int i, j;
bc97a989 71
49223129
LM
72 VERBOSE (DEBUG, PRINTOUT ("Starting parsing\n"));
73
bc97a989
LM
74 /* main loop */
75 while (*str != '\0') {
76 int found = 0;
77 element_t *new = NULL;
49223129 78 VERBOSE (INFO, PRINTOUT ("Processing: %s\n", str));
bc97a989
LM
79
80 /* skip spaces and tabs */
81
82 if ((*str == ' ') || (*str == '\t')) {
83 str++;
84 continue;
85 }
86
0b489a77
LM
87 /* skip commas */
88
89 if (*str == ',') {
efdfb543
LM
90 VERBOSE (DEBUG, PRINTOUT ("start processing coma\n"));
91 str++;
0b489a77 92 if (root == NULL) {
efdfb543 93 return parser (str, &str);
0b489a77
LM
94 } else if (root->func != Set) {
95 new = newelement (Set, MAX_OPERANDS);
efdfb543
LM
96 if (new == NULL) {
97 return ERROR_OP;
98 }
0b489a77
LM
99 new->ops[0] = root;
100 root = new;
efdfb543
LM
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"));
0b489a77 117 }
0b489a77
LM
118 continue;
119 }
120
121 /* check for parent */
122
0b489a77 123 if (*str == '(') {
49223129 124 VERBOSE (DEBUG, PRINTOUT ("start processing bracket\n"));
0b489a77 125 new = parser (str + 1, &str);
49223129
LM
126 if (new == ERROR_OP) {
127 return ERROR_OP;
0b489a77
LM
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 }
efdfb543
LM
148 } else {
149 if (new->func != Set) {
150 root = new;
151 } else {
152 return ERROR_OP;
153 }
0b489a77 154 }
49223129 155 VERBOSE (DEBUG, PRINTOUT ("stop processing bracket\n"));
efdfb543
LM
156 //if (next != NULL) {
157 // *next = str;
158 //}
159 //return root;
160 continue;
49223129
LM
161 }
162 if (*str == ')') {
163 if (next != NULL) {
164 *next = str + 1;
165 }
166 return root;
0b489a77
LM
167 }
168
bc97a989
LM
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) {
49223129
LM
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));
bc97a989
LM
178 new = newelement (operator->func, operator->nbops);
179 if (new == NULL) {
0b489a77 180 return ERROR_OP;
bc97a989
LM
181 }
182 new->ops[0] = root;
183 root = new;
49223129
LM
184 new = parser (str, &str);
185 if (new == ERROR_OP) {
186 return ERROR_OP;
187 }
188 root->ops[1] = new;
189 } else {
0b489a77 190 return ERROR_OP;
bc97a989 191 }
bc97a989 192 found = 1;
49223129 193 VERBOSE (DEBUG, PRINTOUT ("stop processing operator\n"));
bc97a989
LM
194 break;
195 }
196 }
197 if (found) {
bc97a989
LM
198 continue;
199 }
49223129 200
bc97a989
LM
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) {
49223129 206 VERBOSE (DEBUG, PRINTOUT ("start processing function\n"));
bc97a989 207 if (root == NULL) {
49223129 208 VERBOSE (INFO, PRINTOUT ("Func: %d\n", function->func));
bc97a989
LM
209 new = newelement (function->func, function->nbops);
210 if (new == NULL) {
0b489a77 211 return ERROR_OP;
bc97a989
LM
212 }
213 root = new;
214 } else {
0b489a77 215 return ERROR_OP;
bc97a989
LM
216 }
217 str += function->offset;
218 found = 1;
49223129 219 VERBOSE (DEBUG, PRINTOUT ("stop processing function\n"));
bc97a989
LM
220 break;
221 }
222 }
223 if (found) {
bc97a989
LM
224 continue;
225 }
226
0b489a77 227 /* last attend to detect addition and substraction */
bc97a989 228
0b489a77
LM
229 if (((*str == '-') || (*str == '+')) &&
230 ((*(str + 1) >= '0') && (*(str + 1) <= '9')) &&
231 ((root) && (root->func == Val))) {
49223129 232 VERBOSE (INFO, PRINTOUT ("Oper: %d\n", Add));
bc97a989
LM
233 new = newelement (Add, 2);
234 if (new == NULL) {
0b489a77 235 return ERROR_OP;
bc97a989
LM
236 }
237 new->ops[0] = root;
238 root = new;
0b489a77 239 }
bc97a989
LM
240
241 /* look for number */
242
49223129
LM
243 if (((*str >= '0') && (*str <= '9')) || (*str == '.')) {
244 VERBOSE (DEBUG, PRINTOUT ("start processing value\n"));
bc97a989
LM
245 char *pt;
246 float value = strtof (str, &pt);
49223129 247 VERBOSE (INFO, PRINTOUT ("Value: %f\n", value));
bc97a989
LM
248 if (str != pt) {
249 new = newelement (Val, 1);
bc97a989 250 if (new == NULL) {
0b489a77 251 return ERROR_OP;
bc97a989 252 }
49223129 253 new->value = value;
bc97a989
LM
254 if (root == NULL) {
255 root = new;
256 } else {
0b489a77
LM
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 }
bc97a989
LM
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) {
0b489a77 273 return ERROR_OP;
bc97a989
LM
274 }
275 }
276 str = pt;
277 found = 1;
278 }
49223129 279 VERBOSE (DEBUG, PRINTOUT ("stop processing value\n"));
bc97a989
LM
280 }
281
282 /* error */
283
284 if (!found) {
0b489a77 285 return ERROR_OP;
bc97a989
LM
286 }
287
288 }
289
49223129
LM
290 if (next != NULL) {
291 *next = str;
292 }
bc97a989
LM
293 return root;
294}
295
296/* print element tree */
297
298void print_element (element_t *root, int level)
299{
300 char *func = NULL;
301 int i;
302
49223129 303 if ((root == NULL) || (root == ERROR_OP)) {
bc97a989 304 return;
49223129
LM
305 }
306
bc97a989
LM
307 for (i = 0; i < level; i++) {
308 PRINTOUT (" ");
309 }
310
311 switch (root->func) {
312 case Val: func = "Value"; break;
0b489a77 313 case Set: func = "Set"; break;
bc97a989
LM
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: */