xref: /freebsd/usr.sbin/pmcstudy/eval_expr.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1d95b3509SRandall Stewart /*-
2*52467047SWarner Losh  * Copyright (c) 2015 Netflix, Inc.
3d95b3509SRandall Stewart  *
4d95b3509SRandall Stewart  * Redistribution and use in source and binary forms, with or without
5d95b3509SRandall Stewart  * modification, are permitted provided that the following conditions
6d95b3509SRandall Stewart  * are met:
7d95b3509SRandall Stewart  * 1. Redistributions of source code must retain the above copyright
8d95b3509SRandall Stewart  *    notice, this list of conditions and the following disclaimer,
9d95b3509SRandall Stewart  *    in this position and unchanged.
10d95b3509SRandall Stewart  * 2. Redistributions in binary form must reproduce the above copyright
11d95b3509SRandall Stewart  *    notice, this list of conditions and the following disclaimer in the
12d95b3509SRandall Stewart  *    documentation and/or other materials provided with the distribution.
13d95b3509SRandall Stewart  * 3. The name of the author may not be used to endorse or promote products
14d95b3509SRandall Stewart  *    derived from this software without specific prior written permission
15d95b3509SRandall Stewart  *
16d95b3509SRandall Stewart  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17d95b3509SRandall Stewart  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18d95b3509SRandall Stewart  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19d95b3509SRandall Stewart  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20d95b3509SRandall Stewart  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21d95b3509SRandall Stewart  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22d95b3509SRandall Stewart  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23d95b3509SRandall Stewart  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24d95b3509SRandall Stewart  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25d95b3509SRandall Stewart  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26d95b3509SRandall Stewart  */
27d95b3509SRandall Stewart #include <sys/types.h>
28d95b3509SRandall Stewart #include <stdio.h>
29d95b3509SRandall Stewart #include <stdlib.h>
30d95b3509SRandall Stewart #include <unistd.h>
31d95b3509SRandall Stewart #include <string.h>
32d95b3509SRandall Stewart #include <strings.h>
33d95b3509SRandall Stewart #include <ctype.h>
34d95b3509SRandall Stewart #include "eval_expr.h"
35d95b3509SRandall Stewart static struct expression *
alloc_and_hook_expr(struct expression ** exp_p,struct expression ** last_p)36d95b3509SRandall Stewart alloc_and_hook_expr(struct expression **exp_p, struct expression **last_p)
37d95b3509SRandall Stewart {
38d95b3509SRandall Stewart 	struct expression *ex, *at;
39d95b3509SRandall Stewart 
40d95b3509SRandall Stewart 	ex = malloc(sizeof(struct expression));
41d95b3509SRandall Stewart 	if (ex == NULL) {
42d95b3509SRandall Stewart 		printf("Out of memory in exp allocation\n");
43d95b3509SRandall Stewart 		exit(-2);
44d95b3509SRandall Stewart 	}
45d95b3509SRandall Stewart 	memset(ex, 0, sizeof(struct expression));
46d95b3509SRandall Stewart 	if (*exp_p == NULL) {
47d95b3509SRandall Stewart 		*exp_p = ex;
48d95b3509SRandall Stewart 	}
49d95b3509SRandall Stewart 	at = *last_p;
50d95b3509SRandall Stewart 	if (at == NULL) {
51d95b3509SRandall Stewart 		/* First one, its last */
52d95b3509SRandall Stewart 		*last_p = ex;
53d95b3509SRandall Stewart 	} else {
54d95b3509SRandall Stewart 		/* Chain it to the end and update last */
55d95b3509SRandall Stewart 		at->next = ex;
56d95b3509SRandall Stewart 		ex->prev = at;
57d95b3509SRandall Stewart 		*last_p = ex;
58d95b3509SRandall Stewart 	}
59d95b3509SRandall Stewart 	return (ex);
60d95b3509SRandall Stewart }
61d95b3509SRandall Stewart 
62d95b3509SRandall Stewart 
63d95b3509SRandall Stewart static int
validate_expr(struct expression * exp,int val1_is_set,int op_is_set,int val2_is_set,int * op_cnt)64d95b3509SRandall Stewart validate_expr(struct expression *exp, int val1_is_set, int op_is_set, int val2_is_set,
65d95b3509SRandall Stewart 	      int *op_cnt)
66d95b3509SRandall Stewart {
67d95b3509SRandall Stewart 	int val1, op, val2;
68d95b3509SRandall Stewart 	int open_cnt;
69d95b3509SRandall Stewart 	val1 = op = val2 = 0;
70d95b3509SRandall Stewart 	if (val1_is_set) {
71d95b3509SRandall Stewart 		val1 = 1;
72d95b3509SRandall Stewart 	}
73d95b3509SRandall Stewart 	if (op_is_set) {
74d95b3509SRandall Stewart 		op = 1;
75d95b3509SRandall Stewart 	}
76d95b3509SRandall Stewart 	if (val2_is_set) {
77d95b3509SRandall Stewart 		val2 = 1;
78d95b3509SRandall Stewart 	}
79d95b3509SRandall Stewart 	open_cnt = *op_cnt;
80d95b3509SRandall Stewart 	if (exp == NULL) {
81d95b3509SRandall Stewart 		/* End of the road */
82d95b3509SRandall Stewart 		if (val1 && op && val2 && (open_cnt == 0)) {
83d95b3509SRandall Stewart 			return(0);
84d95b3509SRandall Stewart 		} else {
85d95b3509SRandall Stewart 			return(1);
86d95b3509SRandall Stewart 		}
87d95b3509SRandall Stewart 	}
88d95b3509SRandall Stewart 	switch(exp->type) {
89d95b3509SRandall Stewart 	case TYPE_OP_PLUS:
90d95b3509SRandall Stewart 	case TYPE_OP_MINUS:
91d95b3509SRandall Stewart 	case TYPE_OP_MULT:
92d95b3509SRandall Stewart 	case TYPE_OP_DIVIDE:
93d95b3509SRandall Stewart 		if (val1 && op && val2) {
94d95b3509SRandall Stewart 			/* We are at x + y +
95d95b3509SRandall Stewart 			 * collapse back to val/op
96d95b3509SRandall Stewart 			 */
97d95b3509SRandall Stewart 			val1 = 1;
98d95b3509SRandall Stewart 			op = 1;
99d95b3509SRandall Stewart 			val2 = 0;
100d95b3509SRandall Stewart 		} else if ((op == 0) && (val1)) {
101d95b3509SRandall Stewart 			op = 1;
102d95b3509SRandall Stewart 		} else {
103d95b3509SRandall Stewart 			printf("Op but no val1 set\n");
104d95b3509SRandall Stewart 			return(-1);
105d95b3509SRandall Stewart 		}
106d95b3509SRandall Stewart 		break;
107d95b3509SRandall Stewart 	case TYPE_PARN_OPEN:
108d95b3509SRandall Stewart 		if (exp->next == NULL) {
109d95b3509SRandall Stewart 			printf("NULL after open paren\n");
110d95b3509SRandall Stewart 			exit(-1);
111d95b3509SRandall Stewart 		}
112d95b3509SRandall Stewart 		if ((exp->next->type == TYPE_OP_PLUS) ||
113d95b3509SRandall Stewart 		    (exp->next->type == TYPE_OP_MINUS) ||
114d95b3509SRandall Stewart 		    (exp->next->type == TYPE_OP_DIVIDE) ||
115d95b3509SRandall Stewart 		    (exp->next->type == TYPE_OP_MULT)) {
116d95b3509SRandall Stewart 			printf("'( OP' -- not allowed\n");
117d95b3509SRandall Stewart 			return(-1);
118d95b3509SRandall Stewart 		}
119d95b3509SRandall Stewart 		if (val1 && (op == 0)) {
120d95b3509SRandall Stewart 			printf("'Val (' -- not allowed\n");
121d95b3509SRandall Stewart 			return(-1);
122d95b3509SRandall Stewart 		}
123d95b3509SRandall Stewart 		if (val1 && op && val2) {
124d95b3509SRandall Stewart 			printf("'Val OP Val (' -- not allowed\n");
125d95b3509SRandall Stewart 			return(-1);
126d95b3509SRandall Stewart 		}
127d95b3509SRandall Stewart 		open_cnt++;
128d95b3509SRandall Stewart 		*op_cnt = open_cnt;
129d95b3509SRandall Stewart 		if (val1) {
130d95b3509SRandall Stewart 			if (validate_expr(exp->next, 0, 0, 0, op_cnt) == 0) {
131d95b3509SRandall Stewart 				val2 = 1;
132d95b3509SRandall Stewart 			} else {
133d95b3509SRandall Stewart 				return(-1);
134d95b3509SRandall Stewart 			}
135d95b3509SRandall Stewart 		} else {
136d95b3509SRandall Stewart 			return(validate_expr(exp->next, 0, 0, 0, op_cnt));
137d95b3509SRandall Stewart 		}
138d95b3509SRandall Stewart 		break;
139d95b3509SRandall Stewart 	case TYPE_PARN_CLOSE:
140d95b3509SRandall Stewart 		open_cnt--;
141d95b3509SRandall Stewart 		*op_cnt = open_cnt;
142d95b3509SRandall Stewart 		if (val1 && op && val2) {
143d95b3509SRandall Stewart 			return(0);
144d95b3509SRandall Stewart 		} else {
145d95b3509SRandall Stewart 			printf("Found close paren and not complete\n");
146d95b3509SRandall Stewart 			return(-1);
147d95b3509SRandall Stewart 		}
148d95b3509SRandall Stewart 		break;
149d95b3509SRandall Stewart 	case TYPE_VALUE_CON:
150d95b3509SRandall Stewart 	case TYPE_VALUE_PMC:
151d95b3509SRandall Stewart 		if (val1 == 0) {
152d95b3509SRandall Stewart 			val1 = 1;
153d95b3509SRandall Stewart 		} else if (val1 && op) {
154d95b3509SRandall Stewart 			val2 = 1;
155d95b3509SRandall Stewart 		} else {
156d95b3509SRandall Stewart 			printf("val1 set, val2 about to be set op empty\n");
157d95b3509SRandall Stewart 			return(-1);
158d95b3509SRandall Stewart 		}
159d95b3509SRandall Stewart 		break;
160d95b3509SRandall Stewart 	default:
161d95b3509SRandall Stewart 		printf("unknown type %d\n", exp->type);
162d95b3509SRandall Stewart 		exit(-5);
163d95b3509SRandall Stewart 		break;
164d95b3509SRandall Stewart 	}
165d95b3509SRandall Stewart 	return(validate_expr(exp->next, val1, op, val2, op_cnt));
166d95b3509SRandall Stewart }
167d95b3509SRandall Stewart 
168d95b3509SRandall Stewart void
print_exp(struct expression * exp)169d95b3509SRandall Stewart print_exp(struct expression *exp)
170d95b3509SRandall Stewart {
171d95b3509SRandall Stewart 	if (exp == NULL) {
172d95b3509SRandall Stewart 		printf("\n");
173d95b3509SRandall Stewart 		return;
174d95b3509SRandall Stewart 	}
175d95b3509SRandall Stewart 	switch(exp->type) {
176d95b3509SRandall Stewart 	case TYPE_OP_PLUS:
177d95b3509SRandall Stewart 		printf(" + ");
178d95b3509SRandall Stewart 		break;
179d95b3509SRandall Stewart 	case TYPE_OP_MINUS:
180d95b3509SRandall Stewart 		printf(" - ");
181d95b3509SRandall Stewart 		break;
182d95b3509SRandall Stewart 	case TYPE_OP_MULT:
183d95b3509SRandall Stewart 		printf(" * ");
184d95b3509SRandall Stewart 		break;
185d95b3509SRandall Stewart 	case TYPE_OP_DIVIDE:
186d95b3509SRandall Stewart 		printf(" / ");
187d95b3509SRandall Stewart 		break;
188d95b3509SRandall Stewart 	case TYPE_PARN_OPEN:
189d95b3509SRandall Stewart 		printf(" ( ");
190d95b3509SRandall Stewart 		break;
191d95b3509SRandall Stewart 	case TYPE_PARN_CLOSE:
192d95b3509SRandall Stewart 		printf(" ) ");
193d95b3509SRandall Stewart 		break;
194d95b3509SRandall Stewart 	case TYPE_VALUE_CON:
195d95b3509SRandall Stewart 		printf("%f", exp->value);
196d95b3509SRandall Stewart 		break;
197d95b3509SRandall Stewart 	case TYPE_VALUE_PMC:
198d95b3509SRandall Stewart 		printf("%s", exp->name);
199d95b3509SRandall Stewart 		break;
200d95b3509SRandall Stewart 	default:
201d95b3509SRandall Stewart 		printf("Unknown op %d\n", exp->type);
202d95b3509SRandall Stewart 		break;
203d95b3509SRandall Stewart 	}
204d95b3509SRandall Stewart 	print_exp(exp->next);
205d95b3509SRandall Stewart }
206d95b3509SRandall Stewart 
207d95b3509SRandall Stewart static void
walk_back_and_insert_paren(struct expression ** beg,struct expression * frm)208d95b3509SRandall Stewart walk_back_and_insert_paren(struct expression **beg, struct expression *frm)
209d95b3509SRandall Stewart {
210d95b3509SRandall Stewart 	struct expression *at, *ex;
211d95b3509SRandall Stewart 
212d95b3509SRandall Stewart 	/* Setup our new open paren */
213d95b3509SRandall Stewart 	ex = malloc(sizeof(struct expression));
214d95b3509SRandall Stewart 	if (ex == NULL) {
215d95b3509SRandall Stewart 		printf("Out of memory in exp allocation\n");
216d95b3509SRandall Stewart 		exit(-2);
217d95b3509SRandall Stewart 	}
218d95b3509SRandall Stewart 	memset(ex, 0, sizeof(struct expression));
219d95b3509SRandall Stewart 	ex->type = TYPE_PARN_OPEN;
220d95b3509SRandall Stewart 	/* Now lets place it */
221d95b3509SRandall Stewart 	at = frm->prev;
222d95b3509SRandall Stewart 	if (at == *beg) {
223d95b3509SRandall Stewart 		/* We are inserting at the head of the list */
224d95b3509SRandall Stewart 	in_beg:
225d95b3509SRandall Stewart 		ex->next = at;
226d95b3509SRandall Stewart 		at->prev = ex;
227d95b3509SRandall Stewart 		*beg = ex;
228d95b3509SRandall Stewart 		return;
229d95b3509SRandall Stewart 	} else if ((at->type == TYPE_VALUE_CON) ||
230d95b3509SRandall Stewart 	    (at->type == TYPE_VALUE_PMC)) {
231d95b3509SRandall Stewart 		/* Simple case we have a value in the previous position */
232d95b3509SRandall Stewart 	in_mid:
233d95b3509SRandall Stewart 		ex->prev = at->prev;
234d95b3509SRandall Stewart 		ex->prev->next = ex;
235d95b3509SRandall Stewart 		ex->next = at;
236d95b3509SRandall Stewart 		at->prev = ex;
237d95b3509SRandall Stewart 		return;
238d95b3509SRandall Stewart 	} else if (at->type == TYPE_PARN_CLOSE) {
239d95b3509SRandall Stewart 		/* Skip through until we reach beg or all ( closes */
240d95b3509SRandall Stewart 		int par_cnt=1;
241d95b3509SRandall Stewart 
242d95b3509SRandall Stewart 		at = at->prev;
243d95b3509SRandall Stewart 		while(par_cnt) {
244d95b3509SRandall Stewart 			if (at->type == TYPE_PARN_CLOSE) {
245d95b3509SRandall Stewart 				par_cnt++;
246d95b3509SRandall Stewart 			} else if (at->type == TYPE_PARN_OPEN) {
247d95b3509SRandall Stewart 				par_cnt--;
248d95b3509SRandall Stewart 				if (par_cnt == 0) {
249d95b3509SRandall Stewart 					break;
250d95b3509SRandall Stewart 				}
251d95b3509SRandall Stewart 			}
252d95b3509SRandall Stewart 			at = at->prev;
253d95b3509SRandall Stewart 		}
254d95b3509SRandall Stewart 		if (at == *beg) {
255d95b3509SRandall Stewart 			/* At beginning we insert */
256d95b3509SRandall Stewart 			goto in_beg;
257d95b3509SRandall Stewart 		} else {
258d95b3509SRandall Stewart 			goto in_mid;
259d95b3509SRandall Stewart 		}
260d95b3509SRandall Stewart 	} else {
261d95b3509SRandall Stewart 		printf("%s:Unexpected type:%d?\n",
262d95b3509SRandall Stewart 		       __FUNCTION__, at->type);
263d95b3509SRandall Stewart 		exit(-1);
264d95b3509SRandall Stewart 	}
265d95b3509SRandall Stewart }
266d95b3509SRandall Stewart 
267d95b3509SRandall Stewart static void
walk_fwd_and_insert_paren(struct expression * frm,struct expression ** added)268d95b3509SRandall Stewart walk_fwd_and_insert_paren(struct expression *frm, struct expression **added)
269d95b3509SRandall Stewart {
270d95b3509SRandall Stewart 	struct expression *at, *ex;
271d95b3509SRandall Stewart 	/* Setup our new close paren */
272d95b3509SRandall Stewart 	ex = malloc(sizeof(struct expression));
273d95b3509SRandall Stewart 	if (ex == NULL) {
274d95b3509SRandall Stewart 		printf("Out of memory in exp allocation\n");
275d95b3509SRandall Stewart 		exit(-2);
276d95b3509SRandall Stewart 	}
277d95b3509SRandall Stewart 	memset(ex, 0, sizeof(struct expression));
278d95b3509SRandall Stewart 	ex->type = TYPE_PARN_CLOSE;
279d95b3509SRandall Stewart 	*added = ex;
280d95b3509SRandall Stewart 	/* Now lets place it */
281d95b3509SRandall Stewart 	at = frm->next;
282d95b3509SRandall Stewart 	if ((at->type == TYPE_VALUE_CON) ||
283d95b3509SRandall Stewart 	    (at->type == TYPE_VALUE_PMC)) {
284d95b3509SRandall Stewart 		/* Simple case we have a value in the previous position */
285d95b3509SRandall Stewart 	insertit:
286d95b3509SRandall Stewart 		ex->next = at->next;
287d95b3509SRandall Stewart 		ex->prev = at;
288d95b3509SRandall Stewart 		at->next = ex;
289d95b3509SRandall Stewart 		return;
290d95b3509SRandall Stewart 	} else if (at->type == TYPE_PARN_OPEN) {
291d95b3509SRandall Stewart 		int par_cnt=1;
292d95b3509SRandall Stewart 		at = at->next;
293d95b3509SRandall Stewart 		while(par_cnt) {
294d95b3509SRandall Stewart 			if (at->type == TYPE_PARN_OPEN) {
295d95b3509SRandall Stewart 				par_cnt++;
296d95b3509SRandall Stewart 			} else if (at->type == TYPE_PARN_CLOSE) {
297d95b3509SRandall Stewart 				par_cnt--;
298d95b3509SRandall Stewart 				if (par_cnt == 0) {
299d95b3509SRandall Stewart 					break;
300d95b3509SRandall Stewart 				}
301d95b3509SRandall Stewart 			}
302d95b3509SRandall Stewart 			at = at->next;
303d95b3509SRandall Stewart 		}
304d95b3509SRandall Stewart 		goto insertit;
305d95b3509SRandall Stewart 	} else {
306d95b3509SRandall Stewart 		printf("%s:Unexpected type:%d?\n",
307d95b3509SRandall Stewart 		       __FUNCTION__,
308d95b3509SRandall Stewart 		       at->type);
309d95b3509SRandall Stewart 		exit(-1);
310d95b3509SRandall Stewart 	}
311d95b3509SRandall Stewart }
312d95b3509SRandall Stewart 
313d95b3509SRandall Stewart 
314d95b3509SRandall Stewart static void
add_precendence(struct expression ** beg,struct expression * start,struct expression * end)315d95b3509SRandall Stewart add_precendence(struct expression **beg, struct expression *start, struct expression *end)
316d95b3509SRandall Stewart {
317d95b3509SRandall Stewart 	/*
318d95b3509SRandall Stewart 	 * Between start and end add () around any * or /. This
319d95b3509SRandall Stewart 	 * is quite tricky since if there is a () set inside the
320d95b3509SRandall Stewart 	 * list we need to skip over everything in the ()'s considering
321d95b3509SRandall Stewart 	 * that just a value.
322d95b3509SRandall Stewart 	 */
323d95b3509SRandall Stewart 	struct expression *at, *newone;
324d95b3509SRandall Stewart 	int open_cnt;
325d95b3509SRandall Stewart 
326d95b3509SRandall Stewart 	at = start;
327d95b3509SRandall Stewart 	open_cnt = 0;
328d95b3509SRandall Stewart 	while(at != end) {
329d95b3509SRandall Stewart 		if (at->type == TYPE_PARN_OPEN) {
330d95b3509SRandall Stewart 			open_cnt++;
331d95b3509SRandall Stewart 		}
332d95b3509SRandall Stewart 		if (at->type == TYPE_PARN_CLOSE) {
333d95b3509SRandall Stewart 			open_cnt--;
334d95b3509SRandall Stewart 		}
335d95b3509SRandall Stewart 		if (open_cnt == 0) {
336d95b3509SRandall Stewart 			if ((at->type == TYPE_OP_MULT) ||
337d95b3509SRandall Stewart 			    (at->type == TYPE_OP_DIVIDE)) {
338d95b3509SRandall Stewart 				walk_back_and_insert_paren(beg, at);
339d95b3509SRandall Stewart 				walk_fwd_and_insert_paren(at, &newone);
340d95b3509SRandall Stewart 				at = newone->next;
341d95b3509SRandall Stewart 				continue;
342d95b3509SRandall Stewart 			}
343d95b3509SRandall Stewart 		}
344d95b3509SRandall Stewart 		at = at->next;
345d95b3509SRandall Stewart 	}
346d95b3509SRandall Stewart 
347d95b3509SRandall Stewart }
348d95b3509SRandall Stewart 
349d95b3509SRandall Stewart static void
set_math_precidence(struct expression ** beg,struct expression * exp,struct expression ** stopped)350d95b3509SRandall Stewart set_math_precidence(struct expression **beg, struct expression *exp, struct expression **stopped)
351d95b3509SRandall Stewart {
352d95b3509SRandall Stewart 	struct expression *at, *start, *end;
353d95b3509SRandall Stewart 	int cnt_lower, cnt_upper;
354d95b3509SRandall Stewart 	/*
355d95b3509SRandall Stewart 	 * Walk through and set any math precedence to
356d95b3509SRandall Stewart 	 * get proper precedence we insert () around * / over + -
357d95b3509SRandall Stewart 	 */
358d95b3509SRandall Stewart 	end = NULL;
359d95b3509SRandall Stewart 	start = at = exp;
360d95b3509SRandall Stewart 	cnt_lower = cnt_upper = 0;
361d95b3509SRandall Stewart 	while(at) {
362d95b3509SRandall Stewart 		if (at->type == TYPE_PARN_CLOSE) {
363d95b3509SRandall Stewart 			/* Done with that paren */
364d95b3509SRandall Stewart 			if (stopped) {
365d95b3509SRandall Stewart 				*stopped = at;
366d95b3509SRandall Stewart 			}
367d95b3509SRandall Stewart 			if (cnt_lower && cnt_upper) {
368d95b3509SRandall Stewart 				/* We have a mixed set ... add precedence between start/end */
369d95b3509SRandall Stewart 				add_precendence(beg, start, end);
370d95b3509SRandall Stewart 			}
371d95b3509SRandall Stewart 			return;
372d95b3509SRandall Stewart 		}
373d95b3509SRandall Stewart 		if (at->type == TYPE_PARN_OPEN) {
374d95b3509SRandall Stewart 			set_math_precidence(beg, at->next, &end);
375d95b3509SRandall Stewart 			at = end;
376d95b3509SRandall Stewart 			continue;
377d95b3509SRandall Stewart 		} else if ((at->type == TYPE_OP_PLUS) ||
378d95b3509SRandall Stewart 			   (at->type == TYPE_OP_MINUS)) {
379d95b3509SRandall Stewart 			cnt_lower++;
380d95b3509SRandall Stewart 		} else if ((at->type == TYPE_OP_DIVIDE) ||
381d95b3509SRandall Stewart 			   (at->type == TYPE_OP_MULT)) {
382d95b3509SRandall Stewart 			cnt_upper++;
383d95b3509SRandall Stewart 		}
384d95b3509SRandall Stewart 		at = at->next;
385d95b3509SRandall Stewart 	}
386d95b3509SRandall Stewart 	if (cnt_lower && cnt_upper) {
387d95b3509SRandall Stewart 		add_precendence(beg, start, NULL);
388d95b3509SRandall Stewart 	}
389d95b3509SRandall Stewart }
390d95b3509SRandall Stewart 
391d95b3509SRandall Stewart extern char **valid_pmcs;
392d95b3509SRandall Stewart extern int valid_pmc_cnt;
393d95b3509SRandall Stewart 
394d95b3509SRandall Stewart static void
pmc_name_set(struct expression * at)395d95b3509SRandall Stewart pmc_name_set(struct expression *at)
396d95b3509SRandall Stewart {
397d95b3509SRandall Stewart 	int i, idx, fnd;
398d95b3509SRandall Stewart 
399d95b3509SRandall Stewart 	if (at->name[0] == '%') {
400d95b3509SRandall Stewart 		/* Special number after $ gives index */
401d95b3509SRandall Stewart 		idx = strtol(&at->name[1], NULL, 0);
402d95b3509SRandall Stewart 		if (idx >= valid_pmc_cnt) {
403d95b3509SRandall Stewart 			printf("Unknown PMC %s -- largest we have is $%d -- can't run your expression\n",
404d95b3509SRandall Stewart 			       at->name, valid_pmc_cnt);
405d95b3509SRandall Stewart 			exit(-1);
406d95b3509SRandall Stewart 		}
407d95b3509SRandall Stewart 		strcpy(at->name, valid_pmcs[idx]);
408d95b3509SRandall Stewart 	} else {
409d95b3509SRandall Stewart 		for(i=0, fnd=0; i<valid_pmc_cnt; i++) {
410d95b3509SRandall Stewart 			if (strcmp(valid_pmcs[i], at->name) == 0) {
411d95b3509SRandall Stewart 				fnd = 1;
412d95b3509SRandall Stewart 				break;
413d95b3509SRandall Stewart 			}
414d95b3509SRandall Stewart 		}
415d95b3509SRandall Stewart 		if (!fnd) {
416d95b3509SRandall Stewart 			printf("PMC %s does not exist on this machine -- can't run your expression\n",
417d95b3509SRandall Stewart 			       at->name);
418d95b3509SRandall Stewart 			exit(-1);
419d95b3509SRandall Stewart 		}
420d95b3509SRandall Stewart 	}
421d95b3509SRandall Stewart }
422d95b3509SRandall Stewart 
423d95b3509SRandall Stewart struct expression *
parse_expression(char * str)424d95b3509SRandall Stewart parse_expression(char *str)
425d95b3509SRandall Stewart {
426d95b3509SRandall Stewart 	struct expression *exp=NULL, *last=NULL, *at;
427d95b3509SRandall Stewart 	int open_par, close_par;
428d95b3509SRandall Stewart 	int op_cnt=0;
429d95b3509SRandall Stewart 	size_t siz, i, x;
430d95b3509SRandall Stewart 	/*
431d95b3509SRandall Stewart 	 * Walk through a string expression and convert
432d95b3509SRandall Stewart 	 * it to a linked list of actions. We do this by:
433d95b3509SRandall Stewart 	 * a) Counting the open/close paren's, there must
434d95b3509SRandall Stewart 	 *    be a matching number.
435d95b3509SRandall Stewart 	 * b) If we have balanced paren's then create a linked list
436d95b3509SRandall Stewart 	 *    of the operators, then we validate that expression further.
437d95b3509SRandall Stewart 	 * c) Validating that we have:
438d95b3509SRandall Stewart 	 *      val OP val <or>
439d95b3509SRandall Stewart 	 *      val OP (  <and>
440d95b3509SRandall Stewart 	 *    inside every paran you have a:
441d95b3509SRandall Stewart 	 *      val OP val <or>
442d95b3509SRandall Stewart 	 *      val OP (   <recursively>
443d95b3509SRandall Stewart 	 * d) A final optional step (not implemented yet) would be
444463a577bSEitan Adler 	 *    to insert the mathematical precedence paran's. For
445d95b3509SRandall Stewart 	 *    the start we will just do the left to right evaluation and
446d95b3509SRandall Stewart 	 *    then later we can add this guy to add paran's to make it
447d95b3509SRandall Stewart 	 *    mathimatically correct... i.e instead of 1 + 2 * 3 we
448d95b3509SRandall Stewart 	 *    would translate it into 1 + ( 2 * 3).
449d95b3509SRandall Stewart 	 */
450d95b3509SRandall Stewart 	open_par = close_par = 0;
451d95b3509SRandall Stewart 	siz = strlen(str);
452d95b3509SRandall Stewart 	/* No trailing newline please */
453d95b3509SRandall Stewart 	if (str[(siz-1)] == '\n') {
454d95b3509SRandall Stewart 		str[(siz-1)] = 0;
455d95b3509SRandall Stewart 		siz--;
456d95b3509SRandall Stewart 	}
457d95b3509SRandall Stewart 	for(i=0; i<siz; i++) {
458d95b3509SRandall Stewart 		if (str[i] == '(') {
459d95b3509SRandall Stewart 			open_par++;
460d95b3509SRandall Stewart 		} else if (str[i] == ')') {
461d95b3509SRandall Stewart 			close_par++;
462d95b3509SRandall Stewart 		}
463d95b3509SRandall Stewart 	}
464d95b3509SRandall Stewart 	if (open_par != close_par) {
465d95b3509SRandall Stewart 		printf("Invalid expression '%s' %d open paren's and %d close?\n",
466d95b3509SRandall Stewart 		       str, open_par, close_par);
467d95b3509SRandall Stewart 		exit(-1);
468d95b3509SRandall Stewart 	}
469d95b3509SRandall Stewart 	for(i=0; i<siz; i++) {
470d95b3509SRandall Stewart 		if (str[i] == '(') {
471d95b3509SRandall Stewart 			at = alloc_and_hook_expr(&exp, &last);
472d95b3509SRandall Stewart 			at->type = TYPE_PARN_OPEN;
473d95b3509SRandall Stewart 		} else if (str[i] == ')') {
474d95b3509SRandall Stewart 			at = alloc_and_hook_expr(&exp, &last);
475d95b3509SRandall Stewart 			at->type = TYPE_PARN_CLOSE;
476d95b3509SRandall Stewart 		} else if (str[i] == ' ') {
477d95b3509SRandall Stewart 			/* Extra blank */
478d95b3509SRandall Stewart 			continue;
479d95b3509SRandall Stewart 		} else if (str[i] == '\t') {
480d95b3509SRandall Stewart 			/* Extra tab */
481d95b3509SRandall Stewart 			continue;
482d95b3509SRandall Stewart 		} else if (str[i] == '+') {
483d95b3509SRandall Stewart 			at = alloc_and_hook_expr(&exp, &last);
484d95b3509SRandall Stewart 			at->type = TYPE_OP_PLUS;
485d95b3509SRandall Stewart 		} else if (str[i] == '-') {
486d95b3509SRandall Stewart 			at = alloc_and_hook_expr(&exp, &last);
487d95b3509SRandall Stewart 			at->type = TYPE_OP_MINUS;
488d95b3509SRandall Stewart 		} else if (str[i] == '/') {
489d95b3509SRandall Stewart 			at = alloc_and_hook_expr(&exp, &last);
490d95b3509SRandall Stewart 			at->type = TYPE_OP_DIVIDE;
491d95b3509SRandall Stewart 		} else if (str[i] == '*') {
492d95b3509SRandall Stewart 			at = alloc_and_hook_expr(&exp, &last);
493d95b3509SRandall Stewart 			at->type = TYPE_OP_MULT;
494d95b3509SRandall Stewart 		} else {
495d95b3509SRandall Stewart 			/* Its a value or PMC constant */
496d95b3509SRandall Stewart 			at = alloc_and_hook_expr(&exp, &last);
497d95b3509SRandall Stewart 			if (isdigit(str[i]) || (str[i] == '.')) {
498d95b3509SRandall Stewart 				at->type = TYPE_VALUE_CON;
499d95b3509SRandall Stewart 			} else {
500d95b3509SRandall Stewart 				at->type = TYPE_VALUE_PMC;
501d95b3509SRandall Stewart 			}
502d95b3509SRandall Stewart 			x = 0;
503d95b3509SRandall Stewart 			while ((str[i] != ' ') &&
504d95b3509SRandall Stewart 			       (str[i] != '\t') &&
505d95b3509SRandall Stewart 			       (str[i] != 0) &&
506d95b3509SRandall Stewart 			       (str[i] != ')') &&
507d95b3509SRandall Stewart 			       (str[i] != '(')) {
508d95b3509SRandall Stewart 				/* We collect the constant until a space or tab */
509d95b3509SRandall Stewart 				at->name[x] = str[i];
510d95b3509SRandall Stewart 				i++;
511d95b3509SRandall Stewart 				x++;
512d95b3509SRandall Stewart 				if (x >=(sizeof(at->name)-1)) {
513d95b3509SRandall Stewart 					printf("Value/Constant too long %d max:%d\n",
514d95b3509SRandall Stewart 					       (int)x, (int)(sizeof(at->name)-1));
515d95b3509SRandall Stewart 					exit(-3);
516d95b3509SRandall Stewart 				}
517d95b3509SRandall Stewart 			}
518d95b3509SRandall Stewart 			if (str[i] != 0) {
519d95b3509SRandall Stewart 				/* Need to back up and see the last char since
520d95b3509SRandall Stewart 				 * the for will increment the loop.
521d95b3509SRandall Stewart 				 */
522d95b3509SRandall Stewart 				i--;
523d95b3509SRandall Stewart 			}
524d95b3509SRandall Stewart 			/* Now we have pulled the string, set it up */
525d95b3509SRandall Stewart 			if (at->type == TYPE_VALUE_CON) {
526d95b3509SRandall Stewart 				at->state = STATE_FILLED;
527d95b3509SRandall Stewart 				at->value = strtod(at->name, NULL);
528d95b3509SRandall Stewart 			} else {
529d95b3509SRandall Stewart 				pmc_name_set(at);
530d95b3509SRandall Stewart 			}
531d95b3509SRandall Stewart 		}
532d95b3509SRandall Stewart 	}
533d95b3509SRandall Stewart 	/* Now lets validate its a workable expression */
534d95b3509SRandall Stewart 	if (validate_expr(exp, 0, 0, 0, &op_cnt)) {
535d95b3509SRandall Stewart 		printf("Invalid expression\n");
536d95b3509SRandall Stewart 		exit(-4);
537d95b3509SRandall Stewart 	}
538d95b3509SRandall Stewart 	set_math_precidence(&exp, exp, NULL);
539d95b3509SRandall Stewart 	return (exp);
540d95b3509SRandall Stewart }
541d95b3509SRandall Stewart 
542d95b3509SRandall Stewart 
543d95b3509SRandall Stewart 
544d95b3509SRandall Stewart static struct expression *
gather_exp_to_paren_close(struct expression * exp,double * val_fill)545d95b3509SRandall Stewart gather_exp_to_paren_close(struct expression *exp, double *val_fill)
546d95b3509SRandall Stewart {
547d95b3509SRandall Stewart 	/*
548d95b3509SRandall Stewart 	 * I have been given ( ???
549d95b3509SRandall Stewart 	 * so I could see either
550d95b3509SRandall Stewart 	 * (
551d95b3509SRandall Stewart 	 * or
552d95b3509SRandall Stewart 	 * Val Op
553d95b3509SRandall Stewart 	 *
554d95b3509SRandall Stewart 	 */
555d95b3509SRandall Stewart 	struct expression *lastproc;
556d95b3509SRandall Stewart 	double val;
557d95b3509SRandall Stewart 
558d95b3509SRandall Stewart 	if (exp->type == TYPE_PARN_OPEN) {
559d95b3509SRandall Stewart 		lastproc = gather_exp_to_paren_close(exp->next, &val);
560d95b3509SRandall Stewart 		*val_fill = val;
561d95b3509SRandall Stewart 	} else {
562d95b3509SRandall Stewart 		*val_fill = run_expr(exp, 0, &lastproc);
563d95b3509SRandall Stewart 	}
564d95b3509SRandall Stewart 	return(lastproc);
565d95b3509SRandall Stewart }
566d95b3509SRandall Stewart 
567d95b3509SRandall Stewart 
568d95b3509SRandall Stewart double
run_expr(struct expression * exp,int initial_call,struct expression ** lastone)569d95b3509SRandall Stewart run_expr(struct expression *exp, int initial_call, struct expression **lastone)
570d95b3509SRandall Stewart {
571d95b3509SRandall Stewart 	/*
572d95b3509SRandall Stewart 	 * We expect to find either
573d95b3509SRandall Stewart 	 * a) A Open Paren
574d95b3509SRandall Stewart 	 * or
575d95b3509SRandall Stewart 	 * b) Val-> Op -> Val
576d95b3509SRandall Stewart 	 * or
577d95b3509SRandall Stewart 	 * c) Val-> Op -> Open Paren
578d95b3509SRandall Stewart 	 */
579d95b3509SRandall Stewart 	double val1, val2, res;
580d95b3509SRandall Stewart 	struct expression *op, *other_half, *rest;
581d95b3509SRandall Stewart 
582d95b3509SRandall Stewart 	if (exp->type == TYPE_PARN_OPEN) {
583d95b3509SRandall Stewart 		op = gather_exp_to_paren_close(exp->next, &val1);
584d95b3509SRandall Stewart 	} else if(exp->type == TYPE_VALUE_CON) {
585d95b3509SRandall Stewart 		val1 = exp->value;
586d95b3509SRandall Stewart 		op = exp->next;
587d95b3509SRandall Stewart 	} else if (exp->type ==  TYPE_VALUE_PMC) {
588d95b3509SRandall Stewart 		val1 = exp->value;
589d95b3509SRandall Stewart 		op = exp->next;
590d95b3509SRandall Stewart 	} else {
591d95b3509SRandall Stewart 		printf("Illegal value in %s huh?\n", __FUNCTION__);
592d95b3509SRandall Stewart 		exit(-1);
593d95b3509SRandall Stewart 	}
594d95b3509SRandall Stewart 	if (op == NULL) {
595d95b3509SRandall Stewart 		return (val1);
596d95b3509SRandall Stewart 	}
597d95b3509SRandall Stewart more_to_do:
598d95b3509SRandall Stewart 	other_half = op->next;
599d95b3509SRandall Stewart 	if (other_half->type == TYPE_PARN_OPEN) {
600d95b3509SRandall Stewart 		rest = gather_exp_to_paren_close(other_half->next, &val2);
601d95b3509SRandall Stewart 	} else if(other_half->type == TYPE_VALUE_CON) {
602d95b3509SRandall Stewart 		val2 = other_half->value;
603d95b3509SRandall Stewart 		rest = other_half->next;
604d95b3509SRandall Stewart 	} else if (other_half->type ==  TYPE_VALUE_PMC) {
605d95b3509SRandall Stewart 		val2 = other_half->value;
606d95b3509SRandall Stewart 		rest = other_half->next;
607d95b3509SRandall Stewart 	} else {
608d95b3509SRandall Stewart 		printf("Illegal2 value in %s huh?\n", __FUNCTION__);
609d95b3509SRandall Stewart 		exit(-1);
610d95b3509SRandall Stewart 	}
611d95b3509SRandall Stewart 	switch(op->type) {
612d95b3509SRandall Stewart 	case TYPE_OP_PLUS:
613d95b3509SRandall Stewart 		res = val1 + val2;
614d95b3509SRandall Stewart 		break;
615d95b3509SRandall Stewart 	case TYPE_OP_MINUS:
616d95b3509SRandall Stewart 		res = val1 - val2;
617d95b3509SRandall Stewart 		break;
618d95b3509SRandall Stewart 	case TYPE_OP_MULT:
619d95b3509SRandall Stewart 		res = val1 * val2;
620d95b3509SRandall Stewart 		break;
621d95b3509SRandall Stewart 	case TYPE_OP_DIVIDE:
622d95b3509SRandall Stewart 		if (val2 != 0.0)
623d95b3509SRandall Stewart 			res = val1 / val2;
624d95b3509SRandall Stewart 		else {
625d95b3509SRandall Stewart 			printf("Division by zero averted\n");
626d95b3509SRandall Stewart 			res = 1.0;
627d95b3509SRandall Stewart 		}
628d95b3509SRandall Stewart 		break;
629d95b3509SRandall Stewart 	default:
630d95b3509SRandall Stewart 		printf("Op is not an operator -- its %d\n",
631d95b3509SRandall Stewart 		       op->type);
632d95b3509SRandall Stewart 		exit(-1);
633d95b3509SRandall Stewart 		break;
634d95b3509SRandall Stewart 	}
635d95b3509SRandall Stewart 	if (rest == NULL) {
636d95b3509SRandall Stewart 		if (lastone) {
637d95b3509SRandall Stewart 			*lastone = NULL;
638d95b3509SRandall Stewart 		}
639d95b3509SRandall Stewart 		return (res);
640d95b3509SRandall Stewart 	}
641d95b3509SRandall Stewart 	if ((rest->type == TYPE_PARN_CLOSE) && (initial_call == 0)) {
642d95b3509SRandall Stewart 		if (lastone) {
643d95b3509SRandall Stewart 			*lastone = rest->next;
644d95b3509SRandall Stewart 		}
645d95b3509SRandall Stewart 		return(res);
646d95b3509SRandall Stewart 	}
647d95b3509SRandall Stewart 	/* There is more, as in
648d95b3509SRandall Stewart 	 * a + b + c
649d95b3509SRandall Stewart 	 * where we just did a + b
650d95b3509SRandall Stewart 	 * so now it becomes val1 is set to res and
651d95b3509SRandall Stewart 	 * we need to proceed with the rest of it.
652d95b3509SRandall Stewart 	 */
653d95b3509SRandall Stewart 	val1 = res;
654d95b3509SRandall Stewart 	op = rest;
655d95b3509SRandall Stewart 	if ((op->type != TYPE_OP_PLUS) &&
656d95b3509SRandall Stewart 	    (op->type != TYPE_OP_MULT) &&
657d95b3509SRandall Stewart 	    (op->type != TYPE_OP_MINUS) &&
658d95b3509SRandall Stewart 	    (op->type != TYPE_OP_DIVIDE)) {
659d95b3509SRandall Stewart 		printf("%s ending on type:%d not an op??\n", __FUNCTION__, op->type);
660d95b3509SRandall Stewart 		return(res);
661d95b3509SRandall Stewart 	}
662d95b3509SRandall Stewart 	if (op)
663d95b3509SRandall Stewart 		goto more_to_do;
664d95b3509SRandall Stewart 	return (res);
665d95b3509SRandall Stewart }
666d95b3509SRandall Stewart 
667d95b3509SRandall Stewart #ifdef STAND_ALONE_TESTING
668d95b3509SRandall Stewart 
669d95b3509SRandall Stewart static double
calc_expr(struct expression * exp)670d95b3509SRandall Stewart calc_expr(struct expression *exp)
671d95b3509SRandall Stewart {
672d95b3509SRandall Stewart 	struct expression *at;
673d95b3509SRandall Stewart 	double xx;
674d95b3509SRandall Stewart 
675d95b3509SRandall Stewart 	/* First clear PMC's setting */
676d95b3509SRandall Stewart 	for(at = exp; at != NULL; at = at->next) {
677d95b3509SRandall Stewart 		if (at->type == TYPE_VALUE_PMC) {
678d95b3509SRandall Stewart 			at->state = STATE_UNSET;
679d95b3509SRandall Stewart 		}
680d95b3509SRandall Stewart 	}
681d95b3509SRandall Stewart 	/* Now for all pmc's make up values .. here is where I would pull them */
682d95b3509SRandall Stewart 	for(at = exp; at != NULL; at = at->next) {
683d95b3509SRandall Stewart 		if (at->type == TYPE_VALUE_PMC) {
684d95b3509SRandall Stewart 			at->value = (random() * 1.0);
685d95b3509SRandall Stewart 			at->state = STATE_FILLED;
686d95b3509SRandall Stewart 			if (at->value == 0.0) {
687d95b3509SRandall Stewart 				/* So we don't have div by 0 */
688d95b3509SRandall Stewart 				at->value = 1.0;
689d95b3509SRandall Stewart 			}
690d95b3509SRandall Stewart 		}
691d95b3509SRandall Stewart 	}
692d95b3509SRandall Stewart 	/* Now lets calculate the expression */
693d95b3509SRandall Stewart 	print_exp(exp);
694d95b3509SRandall Stewart 	xx = run_expr(exp, 1, NULL);
695d95b3509SRandall Stewart 	printf("Answer is %f\n", xx);
696d95b3509SRandall Stewart 	return(xx);
697d95b3509SRandall Stewart }
698d95b3509SRandall Stewart 
699d95b3509SRandall Stewart 
700d95b3509SRandall Stewart int
main(int argc,char ** argv)701d95b3509SRandall Stewart main(int argc, char **argv)
702d95b3509SRandall Stewart {
703d95b3509SRandall Stewart 	struct expression *exp;
704d95b3509SRandall Stewart 	if (argc < 2) {
705d95b3509SRandall Stewart 		printf("Use %s expression\n", argv[0]);
706d95b3509SRandall Stewart 		return(-1);
707d95b3509SRandall Stewart 	}
708d95b3509SRandall Stewart 	exp = parse_expression(argv[1]);
709d95b3509SRandall Stewart 	printf("Now the calc\n");
710d95b3509SRandall Stewart 	calc_expr(exp);
711d95b3509SRandall Stewart 	return(0);
712d95b3509SRandall Stewart }
713d95b3509SRandall Stewart 
714d95b3509SRandall Stewart #endif
715