2ed8d9d845dd4f6749b021f582703fe9a92a168c
[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;
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 /* check for open bracket */
88
89 if (*str == '(') {
90 VERBOSE (DEBUG, PRINTOUT ("start processing bracket\n"));
91 if (root) {
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) {
100 root->ops[i] = new;
101 found = 1;
102 break;
103 }
104 }
105 if (!found) {
106 return ERROR_OP;
107 }
108 } while (*str == ',');
109 } else {
110 root = newelement (Val, 1);
111 if (root == NULL) {
112 return ERROR_OP;
113 }
114 new = parser (str + 1, &str);
115 if ((new == ERROR_OP) || (*str == ',')) {
116 return ERROR_OP;
117 }
118 root->ops[0] = new;
119 }
120 str++;
121 VERBOSE (DEBUG, PRINTOUT ("stop processing bracket\n"));
122 continue;
123 }
124
125 /* check for closing bracket or koma */
126
127 if ((*str == ')') || (*str == ',')) {
128 if (next != NULL) {
129 *next = str;
130 }
131 return root;
132 }
133
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) {
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));
143 new = newelement (operator->func, operator->nbops);
144 if (new == NULL) {
145 return ERROR_OP;
146 }
147 new->ops[0] = root;
148 root = new;
149 new = parser (str, &str);
150 if (new == ERROR_OP) {
151 return ERROR_OP;
152 }
153 root->ops[1] = new;
154 } else {
155 return ERROR_OP;
156 }
157 found = 1;
158 VERBOSE (DEBUG, PRINTOUT ("stop processing operator\n"));
159 break;
160 }
161 }
162 if (found) {
163 continue;
164 }
165
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) {
171 VERBOSE (DEBUG, PRINTOUT ("start processing function\n"));
172 if (root == NULL) {
173 VERBOSE (INFO, PRINTOUT ("Func: %d\n", function->func));
174 new = newelement (function->func, function->nbops);
175 if (new == NULL) {
176 return ERROR_OP;
177 }
178 root = new;
179 } else {
180 return ERROR_OP;
181 }
182 str += function->offset;
183 found = 1;
184 VERBOSE (DEBUG, PRINTOUT ("stop processing function\n"));
185 break;
186 }
187 }
188 if (found) {
189 continue;
190 }
191
192 /* last attend to detect addition and substraction */
193
194 if (((*str == '-') || (*str == '+')) &&
195 ((*(str + 1) >= '0') && (*(str + 1) <= '9')) &&
196 ((root) && (root->func == Val))) {
197 VERBOSE (INFO, PRINTOUT ("Oper: %d\n", Add));
198 new = newelement (Add, 2);
199 if (new == NULL) {
200 return ERROR_OP;
201 }
202 new->ops[0] = root;
203 root = new;
204 }
205
206 /* look for number */
207
208 if (((*str >= '0') && (*str <= '9')) || (*str == '.')) {
209 VERBOSE (DEBUG, PRINTOUT ("start processing value\n"));
210 char *pt;
211 float value = strtof (str, &pt);
212 VERBOSE (INFO, PRINTOUT ("Value: %f\n", value));
213 if (str != pt) {
214 new = newelement (Val, 1);
215 if (new == NULL) {
216 return ERROR_OP;
217 }
218 new->value = value;
219 if (root == NULL) {
220 root = new;
221 } else {
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 }
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) {
238 return ERROR_OP;
239 }
240 }
241 str = pt;
242 found = 1;
243 }
244 VERBOSE (DEBUG, PRINTOUT ("stop processing value\n"));
245 }
246
247 /* error */
248
249 if (!found) {
250 return ERROR_OP;
251 }
252
253 }
254
255 if (next != NULL) {
256 *next = str;
257 }
258 return root;
259 }
260
261 /* print element tree */
262
263 void print_element (element_t *root, int level)
264 {
265 char *func = NULL;
266 int i;
267
268 if ((root == NULL) || (root == ERROR_OP)) {
269 return;
270 }
271
272 for (i = 0; i < level; i++) {
273 PRINTOUT (" ");
274 }
275
276 switch (root->func) {
277 case Val: func = "Value"; break;
278 case Set: func = "Set"; break;
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
294 if ((root->func == Val) && (root->ops[0] == NULL)) {
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: */