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