xref: /titanic_44/usr/src/cmd/fm/modules/common/eversholt/eval.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * eval.c -- constraint evaluation module
27  *
28  * this module evaluates constraints.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include "alloc.h"
38 #include "out.h"
39 #include "stable.h"
40 #include "literals.h"
41 #include "lut.h"
42 #include "tree.h"
43 #include "ptree.h"
44 #include "itree.h"
45 #include "eval.h"
46 #include "config.h"
47 #include "platform.h"
48 
49 
50 static struct node *eval_dup(struct node *np, struct lut *ex,
51 			    struct node *epnames[]);
52 
53 /*
54  * begins_with -- return true if rhs path begins with everything in lhs path
55  */
56 static int
57 begins_with(struct node *lhs, struct node *rhs)
58 {
59 	int lnum;
60 	int rnum;
61 
62 	if (lhs == NULL)
63 		return (1);	/* yep -- it all matched */
64 
65 	if (rhs == NULL)
66 		return (0);	/* nope, ran out of rhs first */
67 
68 	ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str);
69 	ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str);
70 
71 	if (lhs->u.name.s != rhs->u.name.s)
72 		return (0);	/* nope, different component names */
73 
74 	if (lhs->u.name.child && lhs->u.name.child->t == T_NUM)
75 		lnum = (int)lhs->u.name.child->u.ull;
76 	else
77 		out(O_DIE, "begins_with: unexpected lhs child");
78 
79 	if (rhs->u.name.child && rhs->u.name.child->t == T_NUM)
80 		rnum = (int)rhs->u.name.child->u.ull;
81 	else
82 		out(O_DIE, "begins_with: unexpected rhs child");
83 
84 	if (lnum != rnum)
85 		return (0);	/* nope, instance numbers were different */
86 
87 	return (begins_with(lhs->u.name.next, rhs->u.name.next));
88 }
89 
90 /*
91  * evaluate a variety of functions and place result in valuep.  return 1 if
92  * function evaluation was successful; 0 if otherwise (e.g., the case of an
93  * invalid argument to the function)
94  */
95 /*ARGSUSED*/
96 static int
97 eval_func(struct node *funcnp, struct lut *ex, struct node *epnames[],
98     struct node *np, struct lut **globals,
99     struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep)
100 {
101 	const char *funcname = funcnp->u.func.s;
102 
103 	if (funcname == L_within) {
104 		/* within()'s are not really constraints -- always true */
105 		valuep->t = UINT64;
106 		valuep->v = 1;
107 		return (1);
108 	} else if (funcname == L_is_under) {
109 		struct node *lhs;
110 		struct node *rhs;
111 
112 		if (np->u.expr.left->t == T_NAME)
113 			lhs = np->u.expr.left;
114 		else if (np->u.expr.left->u.func.s == L_fru)
115 			lhs = eval_fru(np->u.expr.left->u.func.arglist);
116 		else if (np->u.expr.left->u.func.s == L_asru)
117 			lhs = eval_asru(np->u.expr.left->u.func.arglist);
118 		else
119 			out(O_DIE, "is_under: unexpected lhs type: %s",
120 			    ptree_nodetype2str(np->u.expr.left->t));
121 
122 		if (np->u.expr.right->t == T_NAME)
123 			rhs = np->u.expr.right;
124 		else if (np->u.expr.right->u.func.s == L_fru)
125 			rhs = eval_fru(np->u.expr.right->u.func.arglist);
126 		else if (np->u.expr.right->u.func.s == L_asru)
127 			rhs = eval_asru(np->u.expr.right->u.func.arglist);
128 		else
129 			out(O_DIE, "is_under: unexpected rhs type: %s",
130 			    ptree_nodetype2str(np->u.expr.right->t));
131 
132 		/* eval_dup will expand wildcards, iterators, etc... */
133 		lhs = eval_dup(lhs, ex, epnames);
134 		rhs = eval_dup(rhs, ex, epnames);
135 		valuep->t = UINT64;
136 		valuep->v = begins_with(lhs, rhs);
137 
138 		out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under(");
139 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs);
140 		out(O_ALTFP|O_VERB2|O_NONL, ",");
141 		ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs);
142 		out(O_ALTFP|O_VERB2, ") returned %d", (int)valuep->v);
143 
144 		tree_free(lhs);
145 		tree_free(rhs);
146 
147 		return (1);
148 	}
149 
150 	if (try)
151 		return (0);
152 
153 	if (funcname == L_fru) {
154 		valuep->t = NODEPTR;
155 		valuep->v = (unsigned long long)eval_fru(np);
156 		return (1);
157 	} else if (funcname == L_asru) {
158 		valuep->t = NODEPTR;
159 		valuep->v = (unsigned long long)eval_asru(np);
160 		return (1);
161 	} else if (funcname == L_call) {
162 		return (! platform_call(np, globals, croot, arrowp, valuep));
163 	} else if (funcname == L_is_connected) {
164 		return (! config_is_connected(np, croot, valuep));
165 	} else if (funcname == L_is_on) {
166 		return (! config_is_on(np, croot, valuep));
167 	} else if (funcname == L_is_present) {
168 		return (! config_is_present(np, croot, valuep));
169 	} else if (funcname == L_is_type) {
170 		return (! config_is_type(np, croot, valuep));
171 	} else if (funcname == L_confprop) {
172 		return (! config_confprop(np, croot, valuep));
173 	} else if (funcname == L_envprop) {
174 		outfl(O_DIE, np->file, np->line,
175 		    "eval_func: %s not yet supported", funcname);
176 	} else if (funcname == L_payloadprop) {
177 		outfl(O_ALTFP|O_VERB|O_NONL, np->file, np->line,
178 		    "payloadprop(\"%s\") ", np->u.quote.s);
179 		if (funcnp->u.func.cachedval != NULL) {
180 			*valuep = *(struct evalue *)(funcnp->u.func.cachedval);
181 			out(O_ALTFP|O_VERB, "cached: %llu", valuep->v);
182 			return (1);
183 		} else if (platform_payloadprop(np, valuep)) {
184 			/* platform_payloadprop() returned false, pass it on */
185 			out(O_ALTFP|O_VERB, "failed.");
186 			return (0);
187 		} else {
188 			/* got back true, cache the value */
189 			funcnp->u.func.cachedval =
190 			    MALLOC(sizeof (struct evalue));
191 			*(struct evalue *)(funcnp->u.func.cachedval) =
192 			    *valuep;
193 			out(O_ALTFP|O_VERB, "returned: %llu", valuep->v);
194 			return (1);
195 		}
196 	} else
197 		outfl(O_DIE, np->file, np->line,
198 		    "eval_func: unexpected func: %s", funcname);
199 	/*NOTREACHED*/
200 }
201 
202 static struct node *
203 eval_wildcardedname(struct node *np, struct lut *ex, struct node *epnames[])
204 {
205 	struct node *npstart, *npend, *npref, *newnp;
206 	struct node *np1, *np2, *retp;
207 	int i;
208 
209 	if (epnames == NULL || epnames[0] == NULL)
210 		return (NULL);
211 
212 	for (i = 0; epnames[i] != NULL; i++) {
213 		if (tree_namecmp(np, epnames[i]) == 0)
214 			return (NULL);
215 	}
216 
217 	/*
218 	 * get to this point if np does not match any of the entries in
219 	 * epnames.  check if np is a path that must preceded by a wildcard
220 	 * portion.  for this case we must first determine which epnames[]
221 	 * entry should be used for wildcarding.
222 	 */
223 	npstart = NULL;
224 	for (i = 0; epnames[i] != NULL; i++) {
225 		for (npref = epnames[i]; npref; npref = npref->u.name.next) {
226 			if (npref->u.name.s == np->u.name.s) {
227 				for (np1 = npref, np2 = np;
228 				    np1 != NULL && np2 != NULL;
229 				    np1 = np1->u.name.next,
230 					    np2 = np2->u.name.next) {
231 					if (np1->u.name.s != np2->u.name.s)
232 						break;
233 				}
234 				if (np2 == NULL) {
235 					npstart = epnames[i];
236 					npend = npref;
237 					if (np1 == NULL)
238 						break;
239 				}
240 			}
241 		}
242 
243 		if (npstart != NULL)
244 			break;
245 	}
246 
247 	if (npstart == NULL) {
248 		/* no match; np is not a path to be wildcarded */
249 		return (NULL);
250 	}
251 
252 	/*
253 	 * dup (npstart -- npend) which is the wildcarded portion.  all
254 	 * children should be T_NUMs.
255 	 */
256 	retp = NULL;
257 	for (npref = npstart;
258 	    ! (npref == NULL || npref == npend);
259 	    npref = npref->u.name.next) {
260 		newnp = newnode(T_NAME, np->file, np->line);
261 
262 		newnp->u.name.t = npref->u.name.t;
263 		newnp->u.name.s = npref->u.name.s;
264 		newnp->u.name.last = newnp;
265 		newnp->u.name.it = npref->u.name.it;
266 		newnp->u.name.cp = npref->u.name.cp;
267 
268 		ASSERT(npref->u.name.child != NULL);
269 		ASSERT(npref->u.name.child->t == T_NUM);
270 		newnp->u.name.child = newnode(T_NUM, np->file, np->line);
271 		newnp->u.name.child->u.ull = npref->u.name.child->u.ull;
272 
273 		if (retp == NULL) {
274 			retp = newnp;
275 		} else {
276 			retp->u.name.last->u.name.next = newnp;
277 			retp->u.name.last = newnp;
278 		}
279 	}
280 
281 	ASSERT(retp != NULL);
282 
283 	/* now append the nonwildcarded portion */
284 	retp = tree_name_append(retp, eval_dup(np, ex, NULL));
285 
286 	return (retp);
287 }
288 
289 static struct node *
290 eval_dup(struct node *np, struct lut *ex, struct node *epnames[])
291 {
292 	struct node *newnp;
293 
294 	if (np == NULL)
295 		return (NULL);
296 
297 	switch (np->t) {
298 	case T_GLOBID:
299 		return (tree_globid(np->u.globid.s, np->file, np->line));
300 
301 	case T_ASSIGN:
302 	case T_CONDIF:
303 	case T_CONDELSE:
304 	case T_NE:
305 	case T_EQ:
306 	case T_LT:
307 	case T_LE:
308 	case T_GT:
309 	case T_GE:
310 	case T_BITAND:
311 	case T_BITOR:
312 	case T_BITXOR:
313 	case T_BITNOT:
314 	case T_LSHIFT:
315 	case T_RSHIFT:
316 	case T_LIST:
317 	case T_AND:
318 	case T_OR:
319 	case T_NOT:
320 	case T_ADD:
321 	case T_SUB:
322 	case T_MUL:
323 	case T_DIV:
324 	case T_MOD:
325 		return (tree_expr(np->t,
326 				    eval_dup(np->u.expr.left, ex, epnames),
327 				    eval_dup(np->u.expr.right, ex, epnames)));
328 
329 	case T_NAME: {
330 		struct iterinfo *iterinfop;
331 		struct node *newchild = NULL;
332 
333 		iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
334 		if (iterinfop != NULL) {
335 			/* explicit iterator; not part of pathname */
336 			newnp = newnode(T_NUM, np->file, np->line);
337 			newnp->u.ull = iterinfop->num;
338 			return (newnp);
339 		}
340 
341 		/* see if np is a path with wildcard portion */
342 		newnp = eval_wildcardedname(np, ex, epnames);
343 		if (newnp != NULL)
344 			return (newnp);
345 
346 		/* turn off wildcarding for child */
347 		newchild = eval_dup(np->u.name.child, ex, NULL);
348 
349 		if (newchild != NULL) {
350 			if (newchild->t != T_NUM) {
351 				/*
352 				 * not a number, eh?  we must resolve this
353 				 * to a number.
354 				 */
355 				struct evalue value;
356 
357 				if (eval_expr(newchild, ex, epnames,
358 				    NULL, NULL, NULL, 1, &value) == 0 ||
359 				    value.t != UINT64) {
360 					outfl(O_DIE, np->file, np->line,
361 					    "eval_dup: could not resolve "
362 					    "iterator of %s", np->u.name.s);
363 				}
364 
365 				tree_free(newchild);
366 				newchild = newnode(T_NUM, np->file, np->line);
367 				newchild->u.ull = value.v;
368 			}
369 
370 			newnp = newnode(np->t, np->file, np->line);
371 			newnp->u.name.s = np->u.name.s;
372 			newnp->u.name.it = np->u.name.it;
373 			newnp->u.name.cp = np->u.name.cp;
374 
375 			newnp->u.name.last = newnp;
376 			newnp->u.name.child = newchild;
377 
378 			if (np->u.name.next != NULL) {
379 				/* turn off wildcarding for next */
380 				return (tree_name_append(newnp,
381 					eval_dup(np->u.name.next, ex, NULL)));
382 			} else {
383 				return (newnp);
384 			}
385 		} else {
386 			outfl(O_DIE, np->file, np->line,
387 			    "eval_dup: internal error: \"%s\" is neither "
388 			    "an iterator nor a pathname", np->u.name.s);
389 		}
390 		/*NOTREACHED*/
391 		break;
392 	}
393 
394 	case T_FUNC:
395 		return (tree_func(np->u.func.s,
396 		    eval_dup(np->u.func.arglist, ex, epnames),
397 		    np->file, np->line));
398 
399 	case T_QUOTE:
400 		newnp = newnode(T_QUOTE, np->file, np->line);
401 		newnp->u.quote.s = np->u.quote.s;
402 		return (newnp);
403 
404 	case T_NUM:
405 		newnp = newnode(T_NUM, np->file, np->line);
406 		newnp->u.ull = np->u.ull;
407 		return (newnp);
408 
409 	default:
410 		outfl(O_DIE, np->file, np->line,
411 		    "eval_dup: unexpected node type: %s",
412 		    ptree_nodetype2str(np->t));
413 	}
414 	/*NOTREACHED*/
415 }
416 
417 /*
418  * eval_potential -- see if constraint is potentially true
419  *
420  * this function is used at instance tree creation time to see if
421  * any constraints are already known to be false.  if this function
422  * returns false, then the constraint will always be false and there's
423  * no need to include the propagation arrow in the instance tree.
424  *
425  * if this routine returns true, either the constraint is known to
426  * be always true (so there's no point in attaching the constraint
427  * to the propagation arrow in the instance tree), or the constraint
428  * contains "deferred" expressions like global variables or poller calls
429  * and so it must be evaluated during calls to fme_eval().  in this last
430  * case, where a constraint needs to be attached to the propagation arrow
431  * in the instance tree, this routine returns a newly created constraint
432  * in *newc where all the non-deferred things have been filled in.
433  *
434  * so in summary:
435  *
436  *	return of false: constraint can never be true, *newc will be NULL.
437  *
438  *	return of true with *newc unchanged: constraint will always be true.
439  *
440  *	return of true with *newc changed: use new constraint in *newc.
441  *
442  * the lookup table for all explicit iterators, ex, is passed in.
443  *
444  * *newc can either be NULL on entry, or if can contain constraints from
445  * previous calls to eval_potential() (i.e. for building up an instance
446  * tree constraint from several potential constraints).  if *newc already
447  * contains constraints, anything added to it will be joined by adding
448  * a T_AND node at the top of *newc.
449  */
450 int
451 eval_potential(struct node *np, struct lut *ex, struct node *epnames[],
452 	    struct node **newc)
453 {
454 	struct node *newnp;
455 	struct evalue value;
456 
457 	if (eval_expr(np, ex, epnames, NULL, NULL, NULL, 1, &value) == 0) {
458 		/*
459 		 * couldn't eval expression because
460 		 * it contains deferred items.  make
461 		 * a duplicate expression with all the
462 		 * non-deferred items expanded.
463 		 */
464 		newnp = eval_dup(np, ex, epnames);
465 
466 		if (*newc == NULL) {
467 			/*
468 			 * constraint is potentially true if deferred
469 			 * expression in newnp is true.  *newc was NULL
470 			 * so new constraint is just the one in newnp.
471 			 */
472 			*newc = newnp;
473 			return (1);
474 		} else {
475 			/*
476 			 * constraint is potentially true if deferred
477 			 * expression in newnp is true.  *newc already
478 			 * contained a constraint so add an AND with the
479 			 * constraint in newnp.
480 			 */
481 			*newc = tree_expr(T_AND, *newc, newnp);
482 			return (1);
483 		}
484 	} else if (value.t == UNDEFINED) {
485 		/* constraint can never be true */
486 		return (0);
487 	} else if (value.t == UINT64 && value.v == 0) {
488 		/* constraint can never be true */
489 		return (0);
490 	} else {
491 		/* constraint is always true (nothing deferred to eval) */
492 		return (1);
493 	}
494 }
495 
496 static int
497 check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype,
498 		struct node *np)
499 {
500 	if (dtype != UNDEFINED && lp->t != dtype) {
501 		outfl(O_OK, np->file, np->line,
502 			"invalid datatype of argument for operation %s",
503 			ptree_nodetype2str(np->t));
504 		return (1);
505 	}
506 
507 	if (rp != NULL && lp->t != rp->t) {
508 		outfl(O_OK, np->file, np->line,
509 			"mismatch in datatype of arguments for operation %s",
510 			ptree_nodetype2str(np->t));
511 		return (1);
512 	}
513 
514 	return (0);
515 }
516 
517 /*
518  * eval_expr -- evaluate expression into *valuep
519  *
520  * the meaning of the return value depends on the input value of try.
521  *
522  * for try == 1: if any deferred items are encounted, bail out and return
523  * false.  returns true if we made it through entire expression without
524  * hitting any deferred items.
525  *
526  * for try == 0: return true if all operations were performed successfully.
527  * return false if otherwise.  for example, any of the following conditions
528  * will result in a false return value:
529  *   - attempted use of an uninitialized global variable
530  *   - failure in function evaluation
531  *   - illegal arithmetic operation (argument out of range)
532  */
533 int
534 eval_expr(struct node *np, struct lut *ex, struct node *epnames[],
535 	struct lut **globals, struct config *croot, struct arrow *arrowp,
536 	int try, struct evalue *valuep)
537 {
538 	struct evalue *gval;
539 	struct evalue lval;
540 	struct evalue rval;
541 
542 	if (np == NULL) {
543 		valuep->t = UINT64;
544 		valuep->v = 1;	/* no constraint means "true" */
545 		return (1);
546 	}
547 
548 	valuep->t = UNDEFINED;
549 
550 	switch (np->t) {
551 	case T_GLOBID:
552 		if (try)
553 			return (0);
554 
555 		/*
556 		 * only handle case of getting (and not setting) the value
557 		 * of a global variable
558 		 */
559 		gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL);
560 		if (gval == NULL) {
561 			valuep->t = UNDEFINED;
562 			return (0);
563 		} else {
564 			valuep->t = gval->t;
565 			valuep->v = gval->v;
566 			return (1);
567 		}
568 
569 	case T_ASSIGN:
570 		if (try)
571 			return (0);
572 
573 		/*
574 		 * first evaluate rhs, then try to store value in lhs which
575 		 * should be a global variable
576 		 */
577 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
578 			    arrowp, try, &rval))
579 			return (0);
580 
581 		ASSERT(np->u.expr.left->t == T_GLOBID);
582 		gval = lut_lookup(*globals,
583 				(void *)np->u.expr.left->u.globid.s, NULL);
584 
585 		if (gval == NULL) {
586 			gval = MALLOC(sizeof (*gval));
587 			*globals = lut_add(*globals,
588 					(void *) np->u.expr.left->u.globid.s,
589 					gval, NULL);
590 		}
591 
592 		gval->t = rval.t;
593 		gval->v = rval.v;
594 		valuep->t = rval.t;
595 		valuep->v = rval.v;
596 		return (1);
597 
598 	case T_EQ:
599 #define	IMPLICIT_ASSIGN_IN_EQ
600 #ifdef IMPLICIT_ASSIGN_IN_EQ
601 		/*
602 		 * if lhs is an uninitialized global variable, perform
603 		 * an assignment.
604 		 *
605 		 * one insidious side effect of implicit assignment is
606 		 * that the "==" operator does not return a Boolean if
607 		 * implicit assignment was performed.
608 		 */
609 		if (try == 0 &&
610 		    np->u.expr.left->t == T_GLOBID &&
611 		    (gval = lut_lookup(*globals,
612 			(void *)np->u.expr.left->u.globid.s, NULL)) == NULL) {
613 			if (!eval_expr(np->u.expr.right, ex, epnames, globals,
614 					croot, arrowp, try, &rval))
615 				return (0);
616 
617 			gval = MALLOC(sizeof (*gval));
618 			*globals = lut_add(*globals,
619 					(void *) np->u.expr.left->u.globid.s,
620 					gval, NULL);
621 
622 			gval->t = rval.t;
623 			gval->v = rval.v;
624 			valuep->t = rval.t;
625 			valuep->v = rval.v;
626 			return (1);
627 		}
628 #endif  /* IMPLICIT_ASSIGN_IN_EQ */
629 
630 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
631 				arrowp, try, &lval))
632 			return (0);
633 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
634 				arrowp, try, &rval))
635 			return (0);
636 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
637 			return (0);
638 
639 		valuep->t = UINT64;
640 		valuep->v = (lval.v == rval.v);
641 		return (1);
642 
643 	case T_LT:
644 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
645 				arrowp, try, &lval))
646 			return (0);
647 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
648 				arrowp, try, &rval))
649 			return (0);
650 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
651 			return (0);
652 
653 		valuep->t = UINT64;
654 		valuep->v = (lval.v < rval.v);
655 		return (1);
656 
657 	case T_LE:
658 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
659 				arrowp, try, &lval))
660 			return (0);
661 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
662 				arrowp, try, &rval))
663 			return (0);
664 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
665 			return (0);
666 
667 		valuep->t = UINT64;
668 		valuep->v = (lval.v <= rval.v);
669 		return (1);
670 
671 	case T_GT:
672 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
673 				arrowp, try, &lval))
674 			return (0);
675 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
676 				arrowp, try, &rval))
677 			return (0);
678 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
679 			return (0);
680 
681 		valuep->t = UINT64;
682 		valuep->v = (lval.v > rval.v);
683 		return (1);
684 
685 	case T_GE:
686 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
687 				arrowp, try, &lval))
688 			return (0);
689 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
690 				arrowp, try, &rval))
691 			return (0);
692 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
693 			return (0);
694 
695 		valuep->t = UINT64;
696 		valuep->v = (lval.v >= rval.v);
697 		return (1);
698 
699 	case T_BITAND:
700 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
701 				arrowp, try, &lval))
702 			return (0);
703 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
704 				arrowp, try, &rval))
705 			return (0);
706 		if (check_expr_args(&lval, &rval, UINT64, np))
707 			return (0);
708 
709 		valuep->t = lval.t;
710 		valuep->v = (lval.v & rval.v);
711 		return (1);
712 
713 	case T_BITOR:
714 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
715 				arrowp, try, &lval))
716 			return (0);
717 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
718 				arrowp, try, &rval))
719 			return (0);
720 		if (check_expr_args(&lval, &rval, UINT64, np))
721 			return (0);
722 
723 		valuep->t = lval.t;
724 		valuep->v = (lval.v | rval.v);
725 		return (1);
726 
727 	case T_BITXOR:
728 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
729 				arrowp, try, &lval))
730 			return (0);
731 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
732 				arrowp, try, &rval))
733 			return (0);
734 		if (check_expr_args(&lval, &rval, UINT64, np))
735 			return (0);
736 
737 		valuep->t = lval.t;
738 		valuep->v = (lval.v ^ rval.v);
739 		return (1);
740 
741 	case T_BITNOT:
742 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
743 				arrowp, try, &lval))
744 			return (0);
745 		ASSERT(np->u.expr.right == NULL);
746 		if (check_expr_args(&lval, NULL, UINT64, np))
747 			return (0);
748 
749 		valuep->t = UINT64;
750 		valuep->v = ~ lval.v;
751 		return (1);
752 
753 	case T_LSHIFT:
754 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
755 				arrowp, try, &lval))
756 			return (0);
757 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
758 				arrowp, try, &rval))
759 			return (0);
760 		if (check_expr_args(&lval, &rval, UINT64, np))
761 			return (0);
762 
763 		valuep->t = UINT64;
764 		valuep->v = (lval.v << rval.v);
765 		return (1);
766 
767 	case T_RSHIFT:
768 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
769 				arrowp, try, &lval))
770 			return (0);
771 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
772 				arrowp, try, &rval))
773 			return (0);
774 		if (check_expr_args(&lval, &rval, UINT64, np))
775 			return (0);
776 
777 		valuep->t = UINT64;
778 		valuep->v = (lval.v >> rval.v);
779 		return (1);
780 
781 	case T_CONDIF: {
782 		struct node *retnp;
783 		int dotrue = 0;
784 
785 		/*
786 		 * evaluate
787 		 *	expression ? stmtA [ : stmtB ]
788 		 *
789 		 * first see if expression is true or false, then determine
790 		 * if stmtA (or stmtB, if it exists) should be evaluated.
791 		 *
792 		 * "dotrue = 1" means stmtA should be evaluated.
793 		 */
794 		if (eval_expr(np->u.expr.left, ex, epnames, globals, croot,
795 				arrowp, try, &lval) &&
796 		    lval.t != UNDEFINED && lval.v != 0)
797 			dotrue = 1;
798 
799 		ASSERT(np->u.expr.right != NULL);
800 		if (np->u.expr.right->t == T_CONDELSE) {
801 			if (dotrue)
802 				retnp = np->u.expr.right->u.expr.left;
803 			else
804 				retnp = np->u.expr.right->u.expr.right;
805 		} else {
806 			/* no ELSE clause */
807 			if (dotrue)
808 				retnp = np->u.expr.right;
809 			else {
810 				valuep->t = UINT64;
811 				valuep->v = 0;
812 				return (0);
813 			}
814 		}
815 
816 		if (!eval_expr(retnp, ex, epnames, globals, croot,
817 			    arrowp, try, valuep))
818 			return (0);
819 		return (1);
820 	}
821 
822 	case T_CONDELSE:
823 		/*
824 		 * shouldn't get here, since T_CONDELSE is supposed to be
825 		 * evaluated as part of T_CONDIF
826 		 */
827 		out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s",
828 		    ptree_nodetype2str(np->t));
829 		return (0);
830 
831 	case T_NE:
832 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
833 				arrowp, try, &lval))
834 			return (0);
835 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
836 				arrowp, try, &rval))
837 			return (0);
838 		if (check_expr_args(&lval, &rval, UNDEFINED, np))
839 			return (0);
840 
841 		valuep->t = UINT64;
842 		valuep->v = (lval.v != rval.v);
843 		return (1);
844 
845 	case T_LIST:
846 	case T_AND:
847 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
848 				arrowp, try, valuep))
849 			return (0);
850 		if (valuep->v == 0) {
851 			valuep->t = UINT64;
852 			return (1);
853 		}
854 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
855 				arrowp, try, valuep))
856 			return (0);
857 		valuep->t = UINT64;
858 		valuep->v = valuep->v == 0 ? 0 : 1;
859 		return (1);
860 
861 	case T_OR:
862 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
863 				arrowp, try, valuep))
864 			return (0);
865 		if (valuep->v != 0) {
866 			valuep->t = UINT64;
867 			valuep->v = 1;
868 			return (1);
869 		}
870 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
871 				arrowp, try, valuep))
872 			return (0);
873 		valuep->t = UINT64;
874 		valuep->v = valuep->v == 0 ? 0 : 1;
875 		return (1);
876 
877 	case T_NOT:
878 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
879 				arrowp, try, valuep))
880 			return (0);
881 		valuep->t = UINT64;
882 		valuep->v = ! valuep->v;
883 		return (1);
884 
885 	case T_ADD:
886 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
887 				arrowp, try, &lval))
888 			return (0);
889 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
890 				arrowp, try, &rval))
891 			return (0);
892 		if (check_expr_args(&lval, &rval, UINT64, np))
893 			return (0);
894 
895 		valuep->t = lval.t;
896 		valuep->v = lval.v + rval.v;
897 		return (1);
898 
899 	case T_SUB:
900 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
901 				arrowp, try, &lval))
902 			return (0);
903 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
904 				arrowp, try, &rval))
905 			return (0);
906 		if (check_expr_args(&lval, &rval, UINT64, np))
907 			return (0);
908 
909 		/* since valuep is unsigned, return false if lval.v < rval.v */
910 		if (lval.v < rval.v) {
911 			out(O_ERR, "eval_expr: T_SUB result is out of range");
912 			valuep->t = UNDEFINED;
913 			return (0);
914 		}
915 
916 		valuep->t = lval.t;
917 		valuep->v = lval.v - rval.v;
918 		return (1);
919 
920 	case T_MUL:
921 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
922 				arrowp, try, &lval))
923 			return (0);
924 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
925 				arrowp, try, &rval))
926 			return (0);
927 		if (check_expr_args(&lval, &rval, UINT64, np))
928 			return (0);
929 
930 		valuep->t = lval.t;
931 		valuep->v = lval.v * rval.v;
932 		return (1);
933 
934 	case T_DIV:
935 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
936 				arrowp, try, &lval))
937 			return (0);
938 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
939 				arrowp, try, &rval))
940 			return (0);
941 		if (check_expr_args(&lval, &rval, UINT64, np))
942 			return (0);
943 
944 		/* return false if dividing by zero */
945 		if (rval.v == 0) {
946 			out(O_ERR, "eval_expr: T_DIV division by zero");
947 			valuep->t = UNDEFINED;
948 			return (0);
949 		}
950 
951 		valuep->t = lval.t;
952 		valuep->v = lval.v / rval.v;
953 		return (1);
954 
955 	case T_MOD:
956 		if (!eval_expr(np->u.expr.left, ex, epnames, globals, croot,
957 				arrowp, try, &lval))
958 			return (0);
959 		if (!eval_expr(np->u.expr.right, ex, epnames, globals, croot,
960 				arrowp, try, &rval))
961 			return (0);
962 		if (check_expr_args(&lval, &rval, UINT64, np))
963 			return (0);
964 
965 		/* return false if dividing by zero */
966 		if (rval.v == 0) {
967 			out(O_ERR, "eval_expr: T_MOD division by zero");
968 			valuep->t = UNDEFINED;
969 			return (0);
970 		}
971 
972 		valuep->t = lval.t;
973 		valuep->v = lval.v % rval.v;
974 		return (1);
975 
976 	case T_NAME:
977 		if (try) {
978 			struct iterinfo *iterinfop;
979 
980 			/*
981 			 * at itree_create() time, we can expand simple
982 			 * iterators.  anything else we'll punt on.
983 			 */
984 			iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL);
985 			if (iterinfop != NULL) {
986 				/* explicit iterator; not part of pathname */
987 				valuep->t = UINT64;
988 				valuep->v = (unsigned long long)iterinfop->num;
989 				return (1);
990 			}
991 			return (0);
992 		}
993 
994 		/* return address of struct node */
995 		valuep->t = NODEPTR;
996 		valuep->v = (unsigned long long)np;
997 		return (1);
998 
999 	case T_QUOTE:
1000 		valuep->t = STRING;
1001 		valuep->v = (unsigned long long)np->u.quote.s;
1002 		return (1);
1003 
1004 	case T_FUNC:
1005 		return (eval_func(np, ex, epnames, np->u.func.arglist,
1006 				globals, croot, arrowp, try, valuep));
1007 
1008 	case T_NUM:
1009 		valuep->t = UINT64;
1010 		valuep->v = np->u.ull;
1011 		return (1);
1012 
1013 	default:
1014 		outfl(O_DIE, np->file, np->line,
1015 		    "eval_expr: unexpected node type: %s",
1016 		    ptree_nodetype2str(np->t));
1017 	}
1018 	/*NOTREACHED*/
1019 }
1020 
1021 /*
1022  * eval_fru() and eval_asru() don't do much, but are called from a number
1023  * of places.
1024  */
1025 struct node *
1026 eval_fru(struct node *np)
1027 {
1028 	ASSERT(np->t == T_NAME);
1029 	return (np);
1030 }
1031 
1032 struct node *
1033 eval_asru(struct node *np)
1034 {
1035 	ASSERT(np->t == T_NAME);
1036 	return (np);
1037 }
1038