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