initial parser
[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 },
48 { "- ", Sub, 2, 1 },
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
67element_t *parser (char *str) {
68 element_t *root = NULL;
69 int i;
70
71 /* main loop */
72 while (*str != '\0') {
73 int found = 0;
74 element_t *new = NULL;
75 VERBOSE (DEBUG, PRINTOUT ("Processing: %s\n", str));
76
77 /* skip spaces and tabs */
78
79 if ((*str == ' ') || (*str == '\t')) {
80 str++;
81 continue;
82 }
83
84 /* look for operators */
85
86 for (i = 0; i < NB_OPERATORS; i++) {
87 keyword_t *operator = operators + i;
88 if (codecmp (operator->keyword, str) == 0) {
89 if ((root) && (root->func == Val)) {
90 VERBOSE (DEBUG, PRINTOUT ("Oper: %d\n", operator->func));
91 new = newelement (operator->func, operator->nbops);
92 if (new == NULL) {
93 return (element_t *)-1;
94 }
95 new->ops[0] = root;
96 root = new;
97 } else {
98 return (element_t *)(-1);
99 }
100 str += operator->offset;
101 found = 1;
102 break;
103 }
104 }
105 if (found) {
106 VERBOSE (DEBUG, PRINTOUT ("stop processing operator\n"));
107 continue;
108 }
109
110 /* look for functions */
111
112 for (i = 0; i < NB_FUNCTIONS; i++) {
113 keyword_t *function = functions + i;
114 if (codecmp (function->keyword, str) == 0) {
115 if (root == NULL) {
116 VERBOSE (DEBUG, PRINTOUT ("Func: %d\n", function->func));
117 new = newelement (function->func, function->nbops);
118 if (new == NULL) {
119 return (element_t *)-1;
120 }
121 root = new;
122 } else {
123 return (element_t *)(-1);
124 }
125 str += function->offset;
126 found = 1;
127 break;
128 }
129 }
130 if (found) {
131 VERBOSE (DEBUG, PRINTOUT ("stop processing function\n"));
132 continue;
133 }
134
135 /* last attend to detect addition and substraction */
136
137 if (((*str == '-') || (*str == '+')) &&
138 ((*(str + 1) >= '0') && (*(str + 1) <= '9')) &&
139 ((root) && (root->func == Val))) {
140 VERBOSE (DEBUG, PRINTOUT ("Oper: %d\n", Add));
141 new = newelement (Add, 2);
142 if (new == NULL) {
143 return (element_t *)-1;
144 }
145 new->ops[0] = root;
146 root = new;
147 }
148
149 /* look for number */
150
151 if (((*str >= '0') && (*str <= '9')) ||
152 (*str == '.') || (*str == '-') ||(*str == '+')) {
153 char *pt;
154 float value = strtof (str, &pt);
155 VERBOSE (DEBUG, PRINTOUT ("Value: %f\n", value));
156 if (str != pt) {
157 new = newelement (Val, 1);
158 new->value = value;
159 if (new == NULL) {
160 return (element_t *)-1;
161 }
162 if (root == NULL) {
163 root = new;
164 } else {
165 for (i = 0; i < root->nbops; i++) {
166 if (root->ops[i] == NULL) {
167 root->ops[i] = new;
168 found = 1;
169 break;
170 }
171 }
172 if (!found) {
173 return (element_t *)-1;
174 }
175 }
176 str = pt;
177 found = 1;
178 }
179 }
180
181 /* error */
182
183 if (!found) {
184 return (element_t *)-1;
185 }
186
187 }
188
189 return root;
190}
191
192/* print element tree */
193
194void print_element (element_t *root, int level)
195{
196 char *func = NULL;
197 int i;
198
199 if (root == NULL)
200 return;
201
202 for (i = 0; i < level; i++) {
203 PRINTOUT (" ");
204 }
205
206 switch (root->func) {
207 case Val: func = "Value"; break;
208 case Add: func = "Addition"; break;
209 case Sub: func = "Subtraction"; break;
210 case Mul: func = "Multiplication"; break;
211 case Div: func = "Division"; break;
212 case Pow: func = "Power"; break;
213 case Sqr: func = "Square Root"; break;
214 case Cos: func = "Cosine"; break;
215 case Sin: func = "Sine"; break;
216 case Atn: func = "Arc Tangent"; break;
217 case Log: func = "Logarithm"; break;
218 case Exp: func = "Exponantial"; break;
219 }
220
221 PRINTOUT ("Function: %s\n", func);
222
223 if (root->func == Val) {
224 for (i = 0; i < level; i++) {
225 PRINTOUT (" ");
226 }
227 PRINTOUT ("value: %f\n", root->value);
228 } else {
229 for (i = 0; i < root->nbops; i++) {
230 print_element (root->ops[i], level + 1);
231 }
232 }
233}
234
235/* vim: set ts=4 sw=4 et: */