1185377Ssam/*-
2187831Ssam * Copyright (c) 2015 Netflix Inc.
3185377Ssam * All rights reserved.
4185377Ssam *
5185377Ssam * Redistribution and use in source and binary forms, with or without
6185377Ssam * modification, are permitted provided that the following conditions
7185377Ssam * are met:
8185377Ssam * 1. Redistributions of source code must retain the above copyright
9185377Ssam *    notice, this list of conditions and the following disclaimer,
10185377Ssam *    in this position and unchanged.
11185377Ssam * 2. Redistributions in binary form must reproduce the above copyright
12185377Ssam *    notice, this list of conditions and the following disclaimer in the
13185377Ssam *    documentation and/or other materials provided with the distribution.
14185377Ssam * 3. The name of the author may not be used to endorse or promote products
15185377Ssam *    derived from this software without specific prior written permission
16185377Ssam *
17187831Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18185377Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19185377Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20185377Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21185377Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22185377Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23185377Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24185377Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25185377Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26185377Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27185377Ssam */
28185377Ssam#include <sys/types.h>
29185377Ssam#include <stdio.h>
30185377Ssam#include <stdlib.h>
31185377Ssam#include <unistd.h>
32185377Ssam#include <string.h>
33185377Ssam#include <strings.h>
34185377Ssam#include <ctype.h>
35185377Ssam#include "eval_expr.h"
36185377Ssam__FBSDID("$FreeBSD$");
37185377Ssam
38185377Ssamstatic struct expression *
39185377Ssamalloc_and_hook_expr(struct expression **exp_p, struct expression **last_p)
40185377Ssam{
41185377Ssam	struct expression *ex, *at;
42185377Ssam
43185377Ssam	ex = malloc(sizeof(struct expression));
44185377Ssam	if (ex == NULL) {
45185377Ssam		printf("Out of memory in exp allocation\n");
46185377Ssam		exit(-2);
47185377Ssam	}
48185377Ssam	memset(ex, 0, sizeof(struct expression));
49185377Ssam	if (*exp_p == NULL) {
50185377Ssam		*exp_p = ex;
51185377Ssam	}
52185377Ssam	at = *last_p;
53185377Ssam	if (at == NULL) {
54185377Ssam		/* First one, its last */
55185377Ssam		*last_p = ex;
56185377Ssam	} else {
57185377Ssam		/* Chain it to the end and update last */
58185377Ssam		at->next = ex;
59185377Ssam		ex->prev = at;
60185377Ssam		*last_p = ex;
61185377Ssam	}
62185377Ssam	return (ex);
63185377Ssam}
64185377Ssam
65185377Ssam
66185377Ssamstatic int
67185377Ssamvalidate_expr(struct expression *exp, int val1_is_set, int op_is_set, int val2_is_set,
68185377Ssam	      int *op_cnt)
69185377Ssam{
70185377Ssam	int val1, op, val2;
71185377Ssam	int open_cnt;
72185377Ssam	val1 = op = val2 = 0;
73185377Ssam	if (val1_is_set) {
74185377Ssam		val1 = 1;
75185377Ssam	}
76185377Ssam	if (op_is_set) {
77185377Ssam		op = 1;
78185377Ssam	}
79185377Ssam	if (val2_is_set) {
80185377Ssam		val2 = 1;
81185377Ssam	}
82185377Ssam	open_cnt = *op_cnt;
83185377Ssam	if (exp == NULL) {
84185377Ssam		/* End of the road */
85185377Ssam		if (val1 && op && val2 && (open_cnt == 0)) {
86185377Ssam			return(0);
87185377Ssam		} else {
88185377Ssam			return(1);
89185377Ssam		}
90185377Ssam	}
91185377Ssam	switch(exp->type) {
92185377Ssam	case TYPE_OP_PLUS:
93185377Ssam	case TYPE_OP_MINUS:
94185377Ssam	case TYPE_OP_MULT:
95185377Ssam	case TYPE_OP_DIVIDE:
96185377Ssam		if (val1 && op && val2) {
97185377Ssam			/* We are at x + y +
98185377Ssam			 * collapse back to val/op
99185377Ssam			 */
100185377Ssam			val1 = 1;
101185377Ssam			op = 1;
102185377Ssam			val2 = 0;
103185377Ssam		} else if ((op == 0) && (val1)) {
104185377Ssam			op = 1;
105185377Ssam		} else {
106185377Ssam			printf("Op but no val1 set\n");
107185377Ssam			return(-1);
108185377Ssam		}
109185377Ssam		break;
110185377Ssam	case TYPE_PARN_OPEN:
111185377Ssam		if (exp->next == NULL) {
112185377Ssam			printf("NULL after open paren\n");
113185377Ssam			exit(-1);
114185377Ssam		}
115185377Ssam		if ((exp->next->type == TYPE_OP_PLUS) ||
116185377Ssam		    (exp->next->type == TYPE_OP_MINUS) ||
117185377Ssam		    (exp->next->type == TYPE_OP_DIVIDE) ||
118185377Ssam		    (exp->next->type == TYPE_OP_MULT)) {
119185377Ssam			printf("'( OP' -- not allowed\n");
120185377Ssam			return(-1);
121185377Ssam		}
122185377Ssam		if (val1 && (op == 0)) {
123185377Ssam			printf("'Val (' -- not allowed\n");
124185377Ssam			return(-1);
125185377Ssam		}
126185377Ssam		if (val1 && op && val2) {
127185377Ssam			printf("'Val OP Val (' -- not allowed\n");
128185377Ssam			return(-1);
129185377Ssam		}
130185377Ssam		open_cnt++;
131185377Ssam		*op_cnt = open_cnt;
132185377Ssam		if (val1) {
133185377Ssam			if (validate_expr(exp->next, 0, 0, 0, op_cnt) == 0) {
134185377Ssam				val2 = 1;
135187831Ssam			} else {
136185377Ssam				return(-1);
137187831Ssam			}
138187831Ssam		} else {
139185377Ssam			return(validate_expr(exp->next, 0, 0, 0, op_cnt));
140187831Ssam		}
141185377Ssam		break;
142185377Ssam	case TYPE_PARN_CLOSE:
143185377Ssam		open_cnt--;
144187831Ssam		*op_cnt = open_cnt;
145187831Ssam		if (val1 && op && val2) {
146187831Ssam			return(0);
147185377Ssam		} else {
148185377Ssam			printf("Found close paren and not complete\n");
149185377Ssam			return(-1);
150185377Ssam		}
151185377Ssam		break;
152185377Ssam	case TYPE_VALUE_CON:
153185377Ssam	case TYPE_VALUE_PMC:
154185377Ssam		if (val1 == 0) {
155185377Ssam			val1 = 1;
156185377Ssam		} else if (val1 && op) {
157185377Ssam			val2 = 1;
158185377Ssam		} else {
159185377Ssam			printf("val1 set, val2 about to be set op empty\n");
160185377Ssam			return(-1);
161185377Ssam		}
162185377Ssam		break;
163185377Ssam	default:
164185377Ssam		printf("unknown type %d\n", exp->type);
165185377Ssam		exit(-5);
166185377Ssam		break;
167185377Ssam	}
168185377Ssam	return(validate_expr(exp->next, val1, op, val2, op_cnt));
169185377Ssam}
170185377Ssam
171185377Ssamvoid
172185377Ssamprint_exp(struct expression *exp)
173185377Ssam{
174185377Ssam	if (exp == NULL) {
175185377Ssam		printf("\n");
176185377Ssam		return;
177185377Ssam	}
178185377Ssam	switch(exp->type) {
179185377Ssam	case TYPE_OP_PLUS:
180185377Ssam		printf(" + ");
181185377Ssam		break;
182185377Ssam	case TYPE_OP_MINUS:
183185377Ssam		printf(" - ");
184185377Ssam		break;
185185377Ssam	case TYPE_OP_MULT:
186185377Ssam		printf(" * ");
187185377Ssam		break;
188185377Ssam	case TYPE_OP_DIVIDE:
189185377Ssam		printf(" / ");
190185377Ssam		break;
191185377Ssam	case TYPE_PARN_OPEN:
192185377Ssam		printf(" ( ");
193185377Ssam		break;
194185377Ssam	case TYPE_PARN_CLOSE:
195185377Ssam		printf(" ) ");
196185377Ssam		break;
197185377Ssam	case TYPE_VALUE_CON:
198185377Ssam		printf("%f", exp->value);
199185377Ssam		break;
200185377Ssam	case TYPE_VALUE_PMC:
201185377Ssam		printf("%s", exp->name);
202185377Ssam		break;
203185377Ssam	default:
204185377Ssam		printf("Unknown op %d\n", exp->type);
205185377Ssam		break;
206185377Ssam	}
207185377Ssam	print_exp(exp->next);
208185377Ssam}
209185377Ssam
210185377Ssamstatic void
211185377Ssamwalk_back_and_insert_paren(struct expression **beg, struct expression *frm)
212185377Ssam{
213185377Ssam	struct expression *at, *ex;
214185377Ssam
215185377Ssam	/* Setup our new open paren */
216185377Ssam	ex = malloc(sizeof(struct expression));
217185377Ssam	if (ex == NULL) {
218185377Ssam		printf("Out of memory in exp allocation\n");
219185377Ssam		exit(-2);
220185377Ssam	}
221185377Ssam	memset(ex, 0, sizeof(struct expression));
222185377Ssam	ex->type = TYPE_PARN_OPEN;
223185377Ssam	/* Now lets place it */
224185377Ssam	at = frm->prev;
225185377Ssam	if (at == *beg) {
226185377Ssam		/* We are inserting at the head of the list */
227185377Ssam	in_beg:
228185377Ssam		ex->next = at;
229185377Ssam		at->prev = ex;
230185377Ssam		*beg = ex;
231185377Ssam		return;
232185377Ssam	} else if ((at->type == TYPE_VALUE_CON) ||
233185377Ssam	    (at->type == TYPE_VALUE_PMC)) {
234185377Ssam		/* Simple case we have a value in the previous position */
235185377Ssam	in_mid:
236185377Ssam		ex->prev = at->prev;
237185377Ssam		ex->prev->next = ex;
238185377Ssam		ex->next = at;
239185377Ssam		at->prev = ex;
240185377Ssam		return;
241185377Ssam	} else if (at->type == TYPE_PARN_CLOSE) {
242185377Ssam		/* Skip through until we reach beg or all ( closes */
243185377Ssam		int par_cnt=1;
244185377Ssam
245185377Ssam		at = at->prev;
246185377Ssam		while(par_cnt) {
247185377Ssam			if (at->type == TYPE_PARN_CLOSE) {
248185377Ssam				par_cnt++;
249185377Ssam			} else if (at->type == TYPE_PARN_OPEN) {
250185377Ssam				par_cnt--;
251185377Ssam				if (par_cnt == 0) {
252185377Ssam					break;
253185377Ssam				}
254185377Ssam			}
255226760Sadrian			at = at->prev;
256185377Ssam		}
257185377Ssam		if (at == *beg) {
258185377Ssam			/* At beginning we insert */
259185377Ssam			goto in_beg;
260185377Ssam		} else {
261185377Ssam			goto in_mid;
262185377Ssam		}
263185377Ssam	} else {
264185377Ssam		printf("%s:Unexpected type:%d?\n",
265185377Ssam		       __FUNCTION__, at->type);
266185377Ssam		exit(-1);
267185377Ssam	}
268185377Ssam}
269185377Ssam
270185380Ssamstatic void
271185377Ssamwalk_fwd_and_insert_paren(struct expression *frm, struct expression **added)
272185380Ssam{
273185377Ssam	struct expression *at, *ex;
274185380Ssam	/* Setup our new close paren */
275185380Ssam	ex = malloc(sizeof(struct expression));
276185377Ssam	if (ex == NULL) {
277185377Ssam		printf("Out of memory in exp allocation\n");
278185377Ssam		exit(-2);
279185377Ssam	}
280185377Ssam	memset(ex, 0, sizeof(struct expression));
281185377Ssam	ex->type = TYPE_PARN_CLOSE;
282185377Ssam	*added = ex;
283185377Ssam	/* Now lets place it */
284185377Ssam	at = frm->next;
285185377Ssam	if ((at->type == TYPE_VALUE_CON) ||
286185377Ssam	    (at->type == TYPE_VALUE_PMC)) {
287185377Ssam		/* Simple case we have a value in the previous position */
288185380Ssam	insertit:
289185380Ssam		ex->next = at->next;
290185377Ssam		ex->prev = at;
291185377Ssam		at->next = ex;
292185377Ssam		return;
293185377Ssam	} else if (at->type == TYPE_PARN_OPEN) {
294185377Ssam		int par_cnt=1;
295185377Ssam		at = at->next;
296185377Ssam		while(par_cnt) {
297185377Ssam			if (at->type == TYPE_PARN_OPEN) {
298185377Ssam				par_cnt++;
299185377Ssam			} else if (at->type == TYPE_PARN_CLOSE) {
300185377Ssam				par_cnt--;
301185377Ssam				if (par_cnt == 0) {
302185377Ssam					break;
303185377Ssam				}
304185377Ssam			}
305185377Ssam			at = at->next;
306185377Ssam		}
307185377Ssam		goto insertit;
308185377Ssam	} else {
309185377Ssam		printf("%s:Unexpected type:%d?\n",
310185377Ssam		       __FUNCTION__,
311185377Ssam		       at->type);
312185377Ssam		exit(-1);
313185377Ssam	}
314185377Ssam}
315185377Ssam
316185377Ssam
317185377Ssamstatic void
318185377Ssamadd_precendence(struct expression **beg, struct expression *start, struct expression *end)
319185377Ssam{
320185377Ssam	/*
321185377Ssam	 * Between start and end add () around any * or /. This
322187831Ssam	 * is quite tricky since if there is a () set inside the
323234774Sadrian	 * list we need to skip over everything in the ()'s considering
324185377Ssam	 * that just a value.
325222265Sadrian	 */
326222265Sadrian	struct expression *at, *newone;
327222265Sadrian	int open_cnt;
328185377Ssam
329185377Ssam	at = start;
330185377Ssam	open_cnt = 0;
331185377Ssam	while(at != end) {
332185377Ssam		if (at->type == TYPE_PARN_OPEN) {
333185377Ssam			open_cnt++;
334218012Sadrian		}
335204579Srpaulo		if (at->type == TYPE_PARN_CLOSE) {
336204579Srpaulo			open_cnt--;
337204579Srpaulo		}
338185377Ssam		if (open_cnt == 0) {
339185377Ssam			if ((at->type == TYPE_OP_MULT) ||
340185377Ssam			    (at->type == TYPE_OP_DIVIDE)) {
341185380Ssam				walk_back_and_insert_paren(beg, at);
342185380Ssam				walk_fwd_and_insert_paren(at, &newone);
343185380Ssam				at = newone->next;
344185380Ssam				continue;
345185380Ssam			}
346185380Ssam		}
347185380Ssam		at = at->next;
348185377Ssam	}
349185377Ssam
350185377Ssam}
351185377Ssam
352185377Ssamstatic void
353185377Ssamset_math_precidence(struct expression **beg, struct expression *exp, struct expression **stopped)
354185377Ssam{
355185377Ssam	struct expression *at, *start, *end;
356185377Ssam	int cnt_lower, cnt_upper;
357185377Ssam	/*
358185377Ssam	 * Walk through and set any math precedence to
359185377Ssam	 * get proper precedence we insert () around * / over + -
360185377Ssam	 */
361185377Ssam	end = NULL;
362185377Ssam	start = at = exp;
363185377Ssam	cnt_lower = cnt_upper = 0;
364185377Ssam	while(at) {
365185377Ssam		if (at->type == TYPE_PARN_CLOSE) {
366185377Ssam			/* Done with that paren */
367185380Ssam			if (stopped) {
368185380Ssam				*stopped = at;
369185380Ssam			}
370185380Ssam			if (cnt_lower && cnt_upper) {
371185380Ssam				/* We have a mixed set ... add precedence between start/end */
372185380Ssam				add_precendence(beg, start, end);
373185380Ssam			}
374185380Ssam			return;
375185380Ssam		}
376185380Ssam		if (at->type == TYPE_PARN_OPEN) {
377185380Ssam			set_math_precidence(beg, at->next, &end);
378185380Ssam			at = end;
379185380Ssam			continue;
380185380Ssam		} else if ((at->type == TYPE_OP_PLUS) ||
381185380Ssam			   (at->type == TYPE_OP_MINUS)) {
382185380Ssam			cnt_lower++;
383185380Ssam		} else if ((at->type == TYPE_OP_DIVIDE) ||
384185380Ssam			   (at->type == TYPE_OP_MULT)) {
385185380Ssam			cnt_upper++;
386185380Ssam		}
387185380Ssam		at = at->next;
388185380Ssam	}
389185380Ssam	if (cnt_lower && cnt_upper) {
390185377Ssam		add_precendence(beg, start, NULL);
391185377Ssam	}
392185377Ssam}
393185377Ssam
394185377Ssamextern char **valid_pmcs;
395185377Ssamextern int valid_pmc_cnt;
396185377Ssam
397185377Ssamstatic void
398185377Ssampmc_name_set(struct expression *at)
399185377Ssam{
400185377Ssam	int i, idx, fnd;
401185377Ssam
402185377Ssam	if (at->name[0] == '%') {
403187831Ssam		/* Special number after $ gives index */
404187831Ssam		idx = strtol(&at->name[1], NULL, 0);
405187831Ssam		if (idx >= valid_pmc_cnt) {
406185377Ssam			printf("Unknown PMC %s -- largest we have is $%d -- can't run your expression\n",
407188012Ssam			       at->name, valid_pmc_cnt);
408188012Ssam			exit(-1);
409185377Ssam		}
410185377Ssam		strcpy(at->name, valid_pmcs[idx]);
411188012Ssam	} else {
412187831Ssam		for(i=0, fnd=0; i<valid_pmc_cnt; i++) {
413187831Ssam			if (strcmp(valid_pmcs[i], at->name) == 0) {
414185377Ssam				fnd = 1;
415185377Ssam				break;
416185377Ssam			}
417185377Ssam		}
418185377Ssam		if (!fnd) {
419185377Ssam			printf("PMC %s does not exist on this machine -- can't run your expression\n",
420185377Ssam			       at->name);
421185377Ssam			exit(-1);
422185377Ssam		}
423185377Ssam	}
424185377Ssam}
425185377Ssam
426185377Ssamstruct expression *
427185377Ssamparse_expression(char *str)
428185377Ssam{
429185377Ssam	struct expression *exp=NULL, *last=NULL, *at;
430185377Ssam	int open_par, close_par;
431185377Ssam	int op_cnt=0;
432185377Ssam	size_t siz, i, x;
433185377Ssam	/*
434185377Ssam	 * Walk through a string expression and convert
435225444Sadrian	 * it to a linked list of actions. We do this by:
436185377Ssam	 * a) Counting the open/close paren's, there must
437185377Ssam	 *    be a matching number.
438185377Ssam	 * b) If we have balanced paren's then create a linked list
439185377Ssam	 *    of the operators, then we validate that expression further.
440185377Ssam	 * c) Validating that we have:
441185377Ssam	 *      val OP val <or>
442185377Ssam	 *      val OP (  <and>
443185377Ssam	 *    inside every paran you have a:
444185377Ssam	 *      val OP val <or>
445185377Ssam	 *      val OP (   <recursively>
446185377Ssam	 * d) A final optional step (not implemented yet) would be
447185377Ssam	 *    to insert the mathematical precedence paran's. For
448185377Ssam	 *    the start we will just do the left to right evaluation and
449185377Ssam	 *    then later we can add this guy to add paran's to make it
450185377Ssam	 *    mathimatically correct... i.e instead of 1 + 2 * 3 we
451185377Ssam	 *    would translate it into 1 + ( 2 * 3).
452185377Ssam	 */
453185377Ssam	open_par = close_par = 0;
454185377Ssam	siz = strlen(str);
455185377Ssam	/* No trailing newline please */
456185377Ssam	if (str[(siz-1)] == '\n') {
457185377Ssam		str[(siz-1)] = 0;
458185377Ssam		siz--;
459185377Ssam	}
460188974Ssam	for(i=0; i<siz; i++) {
461188974Ssam		if (str[i] == '(') {
462185377Ssam			open_par++;
463185377Ssam		} else if (str[i] == ')') {
464185377Ssam			close_par++;
465185377Ssam		}
466185377Ssam	}
467185377Ssam	if (open_par != close_par) {
468185377Ssam		printf("Invalid expression '%s' %d open paren's and %d close?\n",
469185377Ssam		       str, open_par, close_par);
470185377Ssam		exit(-1);
471219419Sadrian	}
472185377Ssam	for(i=0; i<siz; i++) {
473185377Ssam		if (str[i] == '(') {
474185377Ssam			at = alloc_and_hook_expr(&exp, &last);
475185377Ssam			at->type = TYPE_PARN_OPEN;
476185377Ssam		} else if (str[i] == ')') {
477185377Ssam			at = alloc_and_hook_expr(&exp, &last);
478185377Ssam			at->type = TYPE_PARN_CLOSE;
479185377Ssam		} else if (str[i] == ' ') {
480185377Ssam			/* Extra blank */
481185377Ssam			continue;
482185377Ssam		} else if (str[i] == '\t') {
483185377Ssam			/* Extra tab */
484185377Ssam			continue;
485185377Ssam		} else if (str[i] == '+') {
486185377Ssam			at = alloc_and_hook_expr(&exp, &last);
487185377Ssam			at->type = TYPE_OP_PLUS;
488185377Ssam		} else if (str[i] == '-') {
489185377Ssam			at = alloc_and_hook_expr(&exp, &last);
490185377Ssam			at->type = TYPE_OP_MINUS;
491185377Ssam		} else if (str[i] == '/') {
492185377Ssam			at = alloc_and_hook_expr(&exp, &last);
493185377Ssam			at->type = TYPE_OP_DIVIDE;
494185377Ssam		} else if (str[i] == '*') {
495185377Ssam			at = alloc_and_hook_expr(&exp, &last);
496185377Ssam			at->type = TYPE_OP_MULT;
497185377Ssam		} else {
498185377Ssam			/* Its a value or PMC constant */
499185377Ssam			at = alloc_and_hook_expr(&exp, &last);
500185377Ssam			if (isdigit(str[i]) || (str[i] == '.')) {
501185377Ssam				at->type = TYPE_VALUE_CON;
502185377Ssam			} else {
503185377Ssam				at->type = TYPE_VALUE_PMC;
504185377Ssam			}
505185377Ssam			x = 0;
506185377Ssam			while ((str[i] != ' ') &&
507185377Ssam			       (str[i] != '\t') &&
508185377Ssam			       (str[i] != 0) &&
509185377Ssam			       (str[i] != ')') &&
510185377Ssam			       (str[i] != '(')) {
511185377Ssam				/* We collect the constant until a space or tab */
512222644Sadrian				at->name[x] = str[i];
513222644Sadrian				i++;
514185377Ssam				x++;
515185377Ssam				if (x >=(sizeof(at->name)-1)) {
516185377Ssam					printf("Value/Constant too long %d max:%d\n",
517185377Ssam					       (int)x, (int)(sizeof(at->name)-1));
518185377Ssam					exit(-3);
519185377Ssam				}
520185377Ssam			}
521185377Ssam			if (str[i] != 0) {
522185377Ssam				/* Need to back up and see the last char since
523185377Ssam				 * the for will increment the loop.
524185377Ssam				 */
525185377Ssam				i--;
526185377Ssam			}
527185377Ssam			/* Now we have pulled the string, set it up */
528185377Ssam			if (at->type == TYPE_VALUE_CON) {
529185377Ssam				at->state = STATE_FILLED;
530185377Ssam				at->value = strtod(at->name, NULL);
531185377Ssam			} else {
532185377Ssam				pmc_name_set(at);
533185377Ssam			}
534185377Ssam		}
535185377Ssam	}
536185377Ssam	/* Now lets validate its a workable expression */
537185377Ssam	if (validate_expr(exp, 0, 0, 0, &op_cnt)) {
538185377Ssam		printf("Invalid expression\n");
539187831Ssam		exit(-4);
540187831Ssam	}
541187831Ssam	set_math_precidence(&exp, exp, NULL);
542187831Ssam	return (exp);
543185377Ssam}
544185377Ssam
545185377Ssam
546187831Ssam
547187831Ssamstatic struct expression *
548187831Ssamgather_exp_to_paren_close(struct expression *exp, double *val_fill)
549187831Ssam{
550187831Ssam	/*
551187831Ssam	 * I have been given ( ???
552187831Ssam	 * so I could see either
553187831Ssam	 * (
554187831Ssam	 * or
555185377Ssam	 * Val Op
556185377Ssam	 *
557185377Ssam	 */
558187831Ssam	struct expression *lastproc;
559187831Ssam	double val;
560185377Ssam
561187831Ssam	if (exp->type == TYPE_PARN_OPEN) {
562185377Ssam		lastproc = gather_exp_to_paren_close(exp->next, &val);
563185377Ssam		*val_fill = val;
564187831Ssam	} else {
565185377Ssam		*val_fill = run_expr(exp, 0, &lastproc);
566185377Ssam	}
567185380Ssam	return(lastproc);
568185377Ssam}
569185377Ssam
570185377Ssam
571185377Ssamdouble
572185377Ssamrun_expr(struct expression *exp, int initial_call, struct expression **lastone)
573185377Ssam{
574185377Ssam	/*
575185377Ssam	 * We expect to find either
576185377Ssam	 * a) A Open Paren
577185377Ssam	 * or
578185377Ssam	 * b) Val-> Op -> Val
579185377Ssam	 * or
580185377Ssam	 * c) Val-> Op -> Open Paren
581185377Ssam	 */
582185377Ssam	double val1, val2, res;
583185377Ssam	struct expression *op, *other_half, *rest;
584185377Ssam
585185377Ssam	if (exp->type == TYPE_PARN_OPEN) {
586185377Ssam		op = gather_exp_to_paren_close(exp->next, &val1);
587185377Ssam	} else if(exp->type == TYPE_VALUE_CON) {
588185377Ssam		val1 = exp->value;
589185377Ssam		op = exp->next;
590185377Ssam	} else if (exp->type ==  TYPE_VALUE_PMC) {
591185377Ssam		val1 = exp->value;
592185377Ssam		op = exp->next;
593185377Ssam	} else {
594185377Ssam		printf("Illegal value in %s huh?\n", __FUNCTION__);
595185377Ssam		exit(-1);
596185377Ssam	}
597185377Ssam	if (op == NULL) {
598185377Ssam		return (val1);
599185377Ssam	}
600185377Ssammore_to_do:
601217621Sadrian	other_half = op->next;
602217621Sadrian	if (other_half->type == TYPE_PARN_OPEN) {
603185377Ssam		rest = gather_exp_to_paren_close(other_half->next, &val2);
604185377Ssam	} else if(other_half->type == TYPE_VALUE_CON) {
605185377Ssam		val2 = other_half->value;
606185377Ssam		rest = other_half->next;
607185377Ssam	} else if (other_half->type ==  TYPE_VALUE_PMC) {
608185377Ssam		val2 = other_half->value;
609185377Ssam		rest = other_half->next;
610185377Ssam	} else {
611185377Ssam		printf("Illegal2 value in %s huh?\n", __FUNCTION__);
612185377Ssam		exit(-1);
613185377Ssam	}
614185377Ssam	switch(op->type) {
615185377Ssam	case TYPE_OP_PLUS:
616185377Ssam		res = val1 + val2;
617185377Ssam		break;
618217684Sadrian	case TYPE_OP_MINUS:
619187831Ssam		res = val1 - val2;
620217684Sadrian		break;
621187831Ssam	case TYPE_OP_MULT:
622185377Ssam		res = val1 * val2;
623211206Sadrian		break;
624211206Sadrian	case TYPE_OP_DIVIDE:
625211206Sadrian		if (val2 != 0.0)
626222584Sadrian			res = val1 / val2;
627222584Sadrian		else {
628222815Sadrian			printf("Division by zero averted\n");
629222815Sadrian			res = 1.0;
630222815Sadrian		}
631224709Sadrian		break;
632230791Sadrian	default:
633211206Sadrian		printf("Op is not an operator -- its %d\n",
634185377Ssam		       op->type);
635		exit(-1);
636		break;
637	}
638	if (rest == NULL) {
639		if (lastone) {
640			*lastone = NULL;
641		}
642		return (res);
643	}
644	if ((rest->type == TYPE_PARN_CLOSE) && (initial_call == 0)) {
645		if (lastone) {
646			*lastone = rest->next;
647		}
648		return(res);
649	}
650	/* There is more, as in
651	 * a + b + c
652	 * where we just did a + b
653	 * so now it becomes val1 is set to res and
654	 * we need to proceed with the rest of it.
655	 */
656	val1 = res;
657	op = rest;
658	if ((op->type != TYPE_OP_PLUS) &&
659	    (op->type != TYPE_OP_MULT) &&
660	    (op->type != TYPE_OP_MINUS) &&
661	    (op->type != TYPE_OP_DIVIDE)) {
662		printf("%s ending on type:%d not an op??\n", __FUNCTION__, op->type);
663		return(res);
664	}
665	if (op)
666		goto more_to_do;
667	return (res);
668}
669
670#ifdef STAND_ALONE_TESTING
671
672static double
673calc_expr(struct expression *exp)
674{
675	struct expression *at;
676	double xx;
677
678	/* First clear PMC's setting */
679	for(at = exp; at != NULL; at = at->next) {
680		if (at->type == TYPE_VALUE_PMC) {
681			at->state = STATE_UNSET;
682		}
683	}
684	/* Now for all pmc's make up values .. here is where I would pull them */
685	for(at = exp; at != NULL; at = at->next) {
686		if (at->type == TYPE_VALUE_PMC) {
687			at->value = (random() * 1.0);
688			at->state = STATE_FILLED;
689			if (at->value == 0.0) {
690				/* So we don't have div by 0 */
691				at->value = 1.0;
692			}
693		}
694	}
695	/* Now lets calculate the expression */
696	print_exp(exp);
697	xx = run_expr(exp, 1, NULL);
698	printf("Answer is %f\n", xx);
699	return(xx);
700}
701
702
703int
704main(int argc, char **argv)
705{
706	struct expression *exp;
707	if (argc < 2) {
708		printf("Use %s expression\n", argv[0]);
709		return(-1);
710	}
711	exp = parse_expression(argv[1]);
712	printf("Now the calc\n");
713	calc_expr(exp);
714	return(0);
715}
716
717#endif
718