bracket supported
[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;
85b4a72c 70 int i;
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
85b4a72c 87 /* check for open bracket */
0b489a77 88
0b489a77 89 if (*str == '(') {
49223129 90 VERBOSE (DEBUG, PRINTOUT ("start processing bracket\n"));
0b489a77 91 if (root) {
85b4a72c
LM
92 do {
93 found = 0;
94 new = parser (str + 1, &str);
95 if (new == ERROR_OP) {
96 return ERROR_OP;
97 }
98 for (i = 0; i < root->nbops; i++) {
99 if (root->ops[i] == NULL) {
0b489a77
LM
100 root->ops[i] = new;
101 found = 1;
102 break;
103 }
104 }
85b4a72c
LM
105 if (!found) {
106 return ERROR_OP;
107 }
108 } while (*str == ',');
109 } else {
110 root = newelement (Val, 1);
111 if (root == NULL) {
0b489a77
LM
112 return ERROR_OP;
113 }
85b4a72c
LM
114 new = parser (str + 1, &str);
115 if ((new == ERROR_OP) || (*str == ',')) {
efdfb543
LM
116 return ERROR_OP;
117 }
85b4a72c 118 root->ops[0] = new;
0b489a77 119 }
85b4a72c 120 str++;
49223129 121 VERBOSE (DEBUG, PRINTOUT ("stop processing bracket\n"));
efdfb543 122 continue;
49223129 123 }
85b4a72c
LM
124
125 /* check for closing bracket or koma */
126
127 if ((*str == ')') || (*str == ',')) {
49223129 128 if (next != NULL) {
85b4a72c 129 *next = str;
49223129
LM
130 }
131 return root;
0b489a77
LM
132 }
133
bc97a989
LM
134 /* look for operators */
135
136 for (i = 0; i < NB_OPERATORS; i++) {
137 keyword_t *operator = operators + i;
138 if (codecmp (operator->keyword, str) == 0) {
49223129
LM
139 VERBOSE (DEBUG, PRINTOUT ("start processing operator\n"));
140 str += operator->offset;
141 if ((root) && (root->func != Set)) {
142 VERBOSE (INFO, PRINTOUT ("Oper: %d\n", operator->func));
bc97a989
LM
143 new = newelement (operator->func, operator->nbops);
144 if (new == NULL) {
0b489a77 145 return ERROR_OP;
bc97a989
LM
146 }
147 new->ops[0] = root;
148 root = new;
49223129
LM
149 new = parser (str, &str);
150 if (new == ERROR_OP) {
151 return ERROR_OP;
152 }
153 root->ops[1] = new;
154 } else {
0b489a77 155 return ERROR_OP;
bc97a989 156 }
bc97a989 157 found = 1;
49223129 158 VERBOSE (DEBUG, PRINTOUT ("stop processing operator\n"));
bc97a989
LM
159 break;
160 }
161 }
162 if (found) {
bc97a989
LM
163 continue;
164 }
49223129 165
bc97a989
LM
166 /* look for functions */
167
168 for (i = 0; i < NB_FUNCTIONS; i++) {
169 keyword_t *function = functions + i;
170 if (codecmp (function->keyword, str) == 0) {
49223129 171 VERBOSE (DEBUG, PRINTOUT ("start processing function\n"));
bc97a989 172 if (root == NULL) {
49223129 173 VERBOSE (INFO, PRINTOUT ("Func: %d\n", function->func));
bc97a989
LM
174 new = newelement (function->func, function->nbops);
175 if (new == NULL) {
0b489a77 176 return ERROR_OP;
bc97a989
LM
177 }
178 root = new;
179 } else {
0b489a77 180 return ERROR_OP;
bc97a989
LM
181 }
182 str += function->offset;
183 found = 1;
49223129 184 VERBOSE (DEBUG, PRINTOUT ("stop processing function\n"));
bc97a989
LM
185 break;
186 }
187 }
188 if (found) {
bc97a989
LM
189 continue;
190 }
191
0b489a77 192 /* last attend to detect addition and substraction */
bc97a989 193
0b489a77
LM
194 if (((*str == '-') || (*str == '+')) &&
195 ((*(str + 1) >= '0') && (*(str + 1) <= '9')) &&
196 ((root) && (root->func == Val))) {
49223129 197 VERBOSE (INFO, PRINTOUT ("Oper: %d\n", Add));
bc97a989
LM
198 new = newelement (Add, 2);
199 if (new == NULL) {
0b489a77 200 return ERROR_OP;
bc97a989
LM
201 }
202 new->ops[0] = root;
203 root = new;
0b489a77 204 }
bc97a989
LM
205
206 /* look for number */
207
49223129
LM
208 if (((*str >= '0') && (*str <= '9')) || (*str == '.')) {
209 VERBOSE (DEBUG, PRINTOUT ("start processing value\n"));
bc97a989
LM
210 char *pt;
211 float value = strtof (str, &pt);
49223129 212 VERBOSE (INFO, PRINTOUT ("Value: %f\n", value));
bc97a989
LM
213 if (str != pt) {
214 new = newelement (Val, 1);
bc97a989 215 if (new == NULL) {
0b489a77 216 return ERROR_OP;
bc97a989 217 }
49223129 218 new->value = value;
bc97a989
LM
219 if (root == NULL) {
220 root = new;
221 } else {
0b489a77
LM
222 if (root->func == Val) {
223 element_t *set = newelement (Set, MAX_OPERANDS);
224 if (set == NULL) {
225 return ERROR_OP;
226 }
227 set->ops[0] = root;
228 root = set;
229 }
bc97a989
LM
230 for (i = 0; i < root->nbops; i++) {
231 if (root->ops[i] == NULL) {
232 root->ops[i] = new;
233 found = 1;
234 break;
235 }
236 }
237 if (!found) {
0b489a77 238 return ERROR_OP;
bc97a989
LM
239 }
240 }
241 str = pt;
242 found = 1;
243 }
49223129 244 VERBOSE (DEBUG, PRINTOUT ("stop processing value\n"));
bc97a989
LM
245 }
246
247 /* error */
248
249 if (!found) {
0b489a77 250 return ERROR_OP;
bc97a989
LM
251 }
252
253 }
254
49223129
LM
255 if (next != NULL) {
256 *next = str;
257 }
bc97a989
LM
258 return root;
259}
260
261/* print element tree */
262
263void print_element (element_t *root, int level)
264{
265 char *func = NULL;
266 int i;
267
49223129 268 if ((root == NULL) || (root == ERROR_OP)) {
bc97a989 269 return;
49223129
LM
270 }
271
bc97a989
LM
272 for (i = 0; i < level; i++) {
273 PRINTOUT (" ");
274 }
275
276 switch (root->func) {
277 case Val: func = "Value"; break;
0b489a77 278 case Set: func = "Set"; break;
bc97a989
LM
279 case Add: func = "Addition"; break;
280 case Sub: func = "Subtraction"; break;
281 case Mul: func = "Multiplication"; break;
282 case Div: func = "Division"; break;
283 case Pow: func = "Power"; break;
284 case Sqr: func = "Square Root"; break;
285 case Cos: func = "Cosine"; break;
286 case Sin: func = "Sine"; break;
287 case Atn: func = "Arc Tangent"; break;
288 case Log: func = "Logarithm"; break;
289 case Exp: func = "Exponantial"; break;
290 }
291
292 PRINTOUT ("Function: %s\n", func);
293
85b4a72c 294 if ((root->func == Val) && (root->ops[0] == NULL)) {
bc97a989
LM
295 for (i = 0; i < level; i++) {
296 PRINTOUT (" ");
297 }
298 PRINTOUT ("value: %f\n", root->value);
299 } else {
300 for (i = 0; i < root->nbops; i++) {
301 print_element (root->ops[i], level + 1);
302 }
303 }
304}
305
306/* vim: set ts=4 sw=4 et: */