xref: /titanic_50/usr/src/cmd/fm/eversholt/common/tree.c (revision 8b464eb836173b92f2b7a65623cd06c8c3c59289)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * tree.c -- routines for manipulating the prop tree
26  *
27  * the actions in escparse.y call these routines to construct
28  * the parse tree.  these routines, in turn, call the check_X()
29  * routines for semantic checking.
30  */
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <strings.h>
38 #include <alloca.h>
39 #include "alloc.h"
40 #include "out.h"
41 #include "stats.h"
42 #include "stable.h"
43 #include "literals.h"
44 #include "lut.h"
45 #include "esclex.h"
46 #include "tree.h"
47 #include "check.h"
48 #include "ptree.h"
49 
50 static struct node *Root;
51 
52 static char *Newname;
53 
54 static struct stats *Faultcount;
55 static struct stats *Upsetcount;
56 static struct stats *Defectcount;
57 static struct stats *Errorcount;
58 static struct stats *Ereportcount;
59 static struct stats *SERDcount;
60 static struct stats *STATcount;
61 static struct stats *ASRUcount;
62 static struct stats *FRUcount;
63 static struct stats *Configcount;
64 static struct stats *Propcount;
65 static struct stats *Maskcount;
66 static struct stats *Nodecount;
67 static struct stats *Namecount;
68 static struct stats *Nodesize;
69 
70 void
71 tree_init(void)
72 {
73 	Faultcount = stats_new_counter("parser.fault", "fault decls", 1);
74 	Upsetcount = stats_new_counter("parser.upset", "upset decls", 1);
75 	Defectcount = stats_new_counter("parser.defect", "defect decls", 1);
76 	Errorcount = stats_new_counter("parser.error", "error decls", 1);
77 	Ereportcount = stats_new_counter("parser.ereport", "ereport decls", 1);
78 	SERDcount = stats_new_counter("parser.SERD", "SERD engine decls", 1);
79 	STATcount = stats_new_counter("parser.STAT", "STAT engine decls", 1);
80 	ASRUcount = stats_new_counter("parser.ASRU", "ASRU decls", 1);
81 	FRUcount = stats_new_counter("parser.FRU", "FRU decls", 1);
82 	Configcount = stats_new_counter("parser.config", "config stmts", 1);
83 	Propcount = stats_new_counter("parser.prop", "prop stmts", 1);
84 	Maskcount = stats_new_counter("parser.mask", "mask stmts", 1);
85 	Nodecount = stats_new_counter("parser.node", "nodes created", 1);
86 	Namecount = stats_new_counter("parser.name", "names created", 1);
87 	Nodesize =
88 	    stats_new_counter("parser.nodesize", "sizeof(struct node)", 1);
89 	stats_counter_add(Nodesize, sizeof (struct node));
90 }
91 
92 void
93 tree_fini(void)
94 {
95 	stats_delete(Faultcount);
96 	stats_delete(Upsetcount);
97 	stats_delete(Defectcount);
98 	stats_delete(Errorcount);
99 	stats_delete(Ereportcount);
100 	stats_delete(SERDcount);
101 	stats_delete(STATcount);
102 	stats_delete(ASRUcount);
103 	stats_delete(FRUcount);
104 	stats_delete(Configcount);
105 	stats_delete(Propcount);
106 	stats_delete(Maskcount);
107 	stats_delete(Nodecount);
108 	stats_delete(Namecount);
109 	stats_delete(Nodesize);
110 
111 	/* free entire parse tree */
112 	tree_free(Root);
113 
114 	/* free up the luts we keep for decls */
115 	lut_free(Faults, NULL, NULL);
116 	Faults = NULL;
117 	lut_free(Upsets, NULL, NULL);
118 	Upsets = NULL;
119 	lut_free(Defects, NULL, NULL);
120 	Defects = NULL;
121 	lut_free(Errors, NULL, NULL);
122 	Errors = NULL;
123 	lut_free(Ereports, NULL, NULL);
124 	Ereports = NULL;
125 	lut_free(Ereportenames, NULL, NULL);
126 	Ereportenames = NULL;
127 	lut_free(SERDs, NULL, NULL);
128 	SERDs = NULL;
129 	lut_free(STATs, NULL, NULL);
130 	STATs = NULL;
131 	lut_free(ASRUs, NULL, NULL);
132 	ASRUs = NULL;
133 	lut_free(FRUs, NULL, NULL);
134 	FRUs = NULL;
135 	lut_free(Configs, NULL, NULL);
136 	Configs = NULL;
137 
138 	Props = Lastprops = NULL;
139 	Masks = Lastmasks = NULL;
140 	Problems = Lastproblems = NULL;
141 
142 	if (Newname != NULL) {
143 		FREE(Newname);
144 		Newname = NULL;
145 	}
146 }
147 
148 struct node *
149 newnode(enum nodetype t, const char *file, int line)
150 {
151 	struct node *ret = MALLOC(sizeof (*ret));
152 
153 	stats_counter_bump(Nodecount);
154 	bzero(ret, sizeof (*ret));
155 	ret->t = t;
156 	ret->file = (file == NULL) ? "<nofile>" : file;
157 	ret->line = line;
158 
159 	return (ret);
160 }
161 
162 /*ARGSUSED*/
163 void
164 tree_free(struct node *root)
165 {
166 	if (root == NULL)
167 		return;
168 
169 	switch (root->t) {
170 	case T_NAME:
171 		tree_free(root->u.name.child);
172 		tree_free(root->u.name.next);
173 		break;
174 	case T_FUNC:
175 		tree_free(root->u.func.arglist);
176 		break;
177 	case T_AND:
178 	case T_OR:
179 	case T_EQ:
180 	case T_NE:
181 	case T_ADD:
182 	case T_DIV:
183 	case T_MOD:
184 	case T_MUL:
185 	case T_SUB:
186 	case T_LT:
187 	case T_LE:
188 	case T_GT:
189 	case T_GE:
190 	case T_BITAND:
191 	case T_BITOR:
192 	case T_BITXOR:
193 	case T_BITNOT:
194 	case T_LSHIFT:
195 	case T_RSHIFT:
196 	case T_NVPAIR:
197 	case T_ASSIGN:
198 	case T_CONDIF:
199 	case T_CONDELSE:
200 	case T_LIST:
201 		tree_free(root->u.expr.left);
202 		tree_free(root->u.expr.right);
203 		break;
204 	case T_EVENT:
205 		tree_free(root->u.event.ename);
206 		tree_free(root->u.event.epname);
207 		tree_free(root->u.event.eexprlist);
208 		break;
209 	case T_NOT:
210 		tree_free(root->u.expr.left);
211 		break;
212 	case T_ARROW:
213 		tree_free(root->u.arrow.lhs);
214 		tree_free(root->u.arrow.nnp);
215 		tree_free(root->u.arrow.knp);
216 		tree_free(root->u.arrow.rhs);
217 		break;
218 	case T_PROP:
219 	case T_MASK:
220 		tree_free(root->u.stmt.np);
221 		break;
222 	case T_FAULT:
223 	case T_UPSET:
224 	case T_DEFECT:
225 	case T_ERROR:
226 	case T_EREPORT:
227 	case T_ASRU:
228 	case T_FRU:
229 	case T_SERD:
230 	case T_STAT:
231 	case T_CONFIG:
232 		tree_free(root->u.stmt.np);
233 		if (root->u.stmt.nvpairs)
234 			tree_free(root->u.stmt.nvpairs);
235 		if (root->u.stmt.lutp)
236 			lut_free(root->u.stmt.lutp, NULL, NULL);
237 		break;
238 	case T_TIMEVAL:
239 	case T_NUM:
240 	case T_QUOTE:
241 	case T_GLOBID:
242 	case T_NOTHING:
243 		break;
244 	default:
245 		out(O_DIE,
246 		    "internal error: tree_free unexpected nodetype: %d",
247 		    root->t);
248 		/*NOTREACHED*/
249 	}
250 	bzero(root, sizeof (*root));
251 	FREE(root);
252 }
253 
254 static int
255 tree_treecmp(struct node *np1, struct node *np2, enum nodetype t,
256 	    lut_cmp cmp_func)
257 {
258 	if (np1 == NULL || np2 == NULL)
259 		return (0);
260 
261 	if (np1->t != np2->t)
262 		return (1);
263 
264 	ASSERT(cmp_func != NULL);
265 
266 	if (np1->t == t)
267 		return ((*cmp_func)(np1, np2));
268 
269 	switch (np1->t) {
270 	case T_NAME:
271 		if (tree_treecmp(np1->u.name.child, np2->u.name.child, t,
272 				cmp_func))
273 			return (1);
274 		return (tree_treecmp(np1->u.name.next, np2->u.name.next, t,
275 				    cmp_func));
276 		/*NOTREACHED*/
277 		break;
278 	case T_FUNC:
279 		return (tree_treecmp(np1->u.func.arglist, np2->u.func.arglist,
280 				    t, cmp_func));
281 		/*NOTREACHED*/
282 		break;
283 	case T_AND:
284 	case T_OR:
285 	case T_EQ:
286 	case T_NE:
287 	case T_ADD:
288 	case T_DIV:
289 	case T_MOD:
290 	case T_MUL:
291 	case T_SUB:
292 	case T_LT:
293 	case T_LE:
294 	case T_GT:
295 	case T_GE:
296 	case T_BITAND:
297 	case T_BITOR:
298 	case T_BITXOR:
299 	case T_BITNOT:
300 	case T_LSHIFT:
301 	case T_RSHIFT:
302 	case T_NVPAIR:
303 	case T_ASSIGN:
304 	case T_CONDIF:
305 	case T_CONDELSE:
306 	case T_LIST:
307 		if (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t,
308 				cmp_func))
309 			return (1);
310 		return (tree_treecmp(np1->u.expr.right, np2->u.expr.right, t,
311 				    cmp_func));
312 		/*NOTREACHED*/
313 		break;
314 	case T_EVENT:
315 		if (tree_treecmp(np1->u.event.ename, np2->u.event.ename, t,
316 				cmp_func))
317 			return (1);
318 		if (tree_treecmp(np1->u.event.epname, np2->u.event.epname, t,
319 				cmp_func))
320 			return (1);
321 		return (tree_treecmp(np1->u.event.eexprlist,
322 				    np2->u.event.eexprlist, t, cmp_func));
323 		/*NOTREACHED*/
324 		break;
325 	case T_NOT:
326 		return (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t,
327 				    cmp_func));
328 		/*NOTREACHED*/
329 		break;
330 	case T_ARROW:
331 		if (tree_treecmp(np1->u.arrow.lhs, np2->u.arrow.lhs, t,
332 				cmp_func))
333 			return (1);
334 		if (tree_treecmp(np1->u.arrow.nnp, np2->u.arrow.nnp, t,
335 				cmp_func))
336 			return (1);
337 		if (tree_treecmp(np1->u.arrow.knp, np2->u.arrow.knp, t,
338 				cmp_func))
339 			return (1);
340 		return (tree_treecmp(np1->u.arrow.rhs, np2->u.arrow.rhs, t,
341 				    cmp_func));
342 		/*NOTREACHED*/
343 		break;
344 	case T_PROP:
345 	case T_MASK:
346 		return (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t,
347 				    cmp_func));
348 		/*NOTREACHED*/
349 		break;
350 	case T_FAULT:
351 	case T_UPSET:
352 	case T_DEFECT:
353 	case T_ERROR:
354 	case T_EREPORT:
355 	case T_ASRU:
356 	case T_FRU:
357 	case T_SERD:
358 	case T_STAT:
359 		if (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, cmp_func))
360 			return (1);
361 		return (tree_treecmp(np1->u.stmt.nvpairs, np2->u.stmt.nvpairs,
362 				    t, cmp_func));
363 		/*NOTREACHED*/
364 		break;
365 	case T_TIMEVAL:
366 	case T_NUM:
367 	case T_QUOTE:
368 	case T_GLOBID:
369 	case T_NOTHING:
370 		break;
371 	default:
372 		out(O_DIE,
373 		    "internal error: tree_treecmp unexpected nodetype: %d",
374 		    np1->t);
375 		/*NOTREACHED*/
376 		break;
377 	}
378 
379 	return (0);
380 }
381 
382 struct node *
383 tree_root(struct node *np)
384 {
385 	if (np)
386 		Root = np;
387 	return (Root);
388 }
389 
390 struct node *
391 tree_nothing(void)
392 {
393 	return (newnode(T_NOTHING, L_nofile, 0));
394 }
395 
396 struct node *
397 tree_expr(enum nodetype t, struct node *left, struct node *right)
398 {
399 	struct node *ret;
400 
401 	ASSERTinfo(left != NULL || right != NULL, ptree_nodetype2str(t));
402 
403 	ret = newnode(t,
404 	    (left) ? left->file : right->file,
405 	    (left) ? left->line : right->line);
406 
407 	ret->u.expr.left = left;
408 	ret->u.expr.right = right;
409 
410 	check_expr(ret);
411 
412 	return (ret);
413 }
414 
415 /*
416  * ename_compress -- convert event class name in to more space-efficient form
417  *
418  * this routine is called after the parser has completed an "ename", which
419  * is that part of an event that contains the class name (like ereport.x.y.z).
420  * after this routine gets done with the ename, two things are true:
421  *   1. the ename uses only a single struct node
422  *   2. ename->u.name.s contains the *complete* class name, dots and all,
423  *      entered into the string table.
424  *
425  * so in addition to saving space by using fewer struct nodes, this routine
426  * allows consumers of the fault tree to assume the ename is a single
427  * string, rather than a linked list of strings.
428  */
429 static struct node *
430 ename_compress(struct node *ename)
431 {
432 	char *buf;
433 	char *cp;
434 	int len = 0;
435 	struct node *np;
436 
437 	if (ename == NULL)
438 		return (ename);
439 
440 	ASSERT(ename->t == T_NAME);
441 
442 	if (ename->u.name.next == NULL)
443 		return (ename);	/* no compression to be applied here */
444 
445 	for (np = ename; np != NULL; np = np->u.name.next) {
446 		ASSERT(np->t == T_NAME);
447 		len++;	/* room for '.' and final '\0' */
448 		len += strlen(np->u.name.s);
449 	}
450 	cp = buf = alloca(len);
451 	for (np = ename; np != NULL; np = np->u.name.next) {
452 		ASSERT(np->t == T_NAME);
453 		if (np != ename)
454 			*cp++ = '.';
455 		(void) strcpy(cp, np->u.name.s);
456 		cp += strlen(cp);
457 	}
458 
459 	ename->u.name.s = stable(buf);
460 	tree_free(ename->u.name.next);
461 	ename->u.name.next = NULL;
462 	ename->u.name.last = ename;
463 	return (ename);
464 }
465 
466 struct node *
467 tree_event(struct node *ename, struct node *epname, struct node *eexprlist)
468 {
469 	struct node *ret;
470 
471 	ASSERT(ename != NULL);
472 
473 	ret = newnode(T_EVENT, ename->file, ename->line);
474 
475 	ret->u.event.ename = ename_compress(ename);
476 	ret->u.event.epname = epname;
477 	ret->u.event.eexprlist = eexprlist;
478 
479 	check_event(ret);
480 
481 	return (ret);
482 }
483 
484 struct node *
485 tree_name(const char *s, enum itertype it, const char *file, int line)
486 {
487 	struct node *ret = newnode(T_NAME, file, line);
488 
489 	ASSERT(s != NULL);
490 
491 	stats_counter_bump(Namecount);
492 	ret->u.name.t = N_UNSPEC;
493 	ret->u.name.s = stable(s);
494 	ret->u.name.it = it;
495 	ret->u.name.last = ret;
496 
497 	if (it == IT_ENAME) {
498 		/* PHASE2, possible optimization: convert to table driven */
499 		if (s == L_fault)
500 			ret->u.name.t = N_FAULT;
501 		else if (s == L_upset)
502 			ret->u.name.t = N_UPSET;
503 		else if (s == L_defect)
504 			ret->u.name.t = N_DEFECT;
505 		else if (s == L_error)
506 			ret->u.name.t = N_ERROR;
507 		else if (s == L_ereport)
508 			ret->u.name.t = N_EREPORT;
509 		else if (s == L_serd)
510 			ret->u.name.t = N_SERD;
511 		else if (s == L_stat)
512 			ret->u.name.t = N_STAT;
513 		else
514 			outfl(O_ERR, file, line, "unknown class: %s", s);
515 	}
516 	return (ret);
517 }
518 
519 struct node *
520 tree_iname(const char *s, const char *file, int line)
521 {
522 	struct node *ret;
523 	char *ss;
524 	char *ptr;
525 
526 	ASSERT(s != NULL && *s != '\0');
527 
528 	ss = STRDUP(s);
529 
530 	ptr = &ss[strlen(ss) - 1];
531 	if (!isdigit(*ptr)) {
532 		outfl(O_ERR, file, line,
533 		    "instanced name expected (i.e. \"x0/y1\")");
534 		FREE(ss);
535 		return (tree_name(s, IT_NONE, file, line));
536 	}
537 	while (ptr > ss && isdigit(*(ptr - 1)))
538 		ptr--;
539 
540 	ret = newnode(T_NAME, file, line);
541 	stats_counter_bump(Namecount);
542 	ret->u.name.child = tree_num(ptr, file, line);
543 	*ptr = '\0';
544 	ret->u.name.t = N_UNSPEC;
545 	ret->u.name.s = stable(ss);
546 	ret->u.name.it = IT_NONE;
547 	ret->u.name.last = ret;
548 	FREE(ss);
549 
550 	return (ret);
551 }
552 
553 struct node *
554 tree_globid(const char *s, const char *file, int line)
555 {
556 	struct node *ret = newnode(T_GLOBID, file, line);
557 
558 	ASSERT(s != NULL);
559 
560 	ret->u.globid.s = stable(s);
561 
562 	return (ret);
563 }
564 
565 struct node *
566 tree_name_append(struct node *np1, struct node *np2)
567 {
568 	ASSERT(np1 != NULL && np2 != NULL);
569 
570 	if (np1->t != T_NAME)
571 		outfl(O_DIE, np1->file, np1->line,
572 		    "tree_name_append: internal error (np1 type %d)", np1->t);
573 	if (np2->t != T_NAME)
574 		outfl(O_DIE, np2->file, np2->line,
575 		    "tree_name_append: internal error (np2 type %d)", np2->t);
576 
577 	ASSERT(np1->u.name.last != NULL);
578 
579 	np1->u.name.last->u.name.next = np2;
580 	np1->u.name.last = np2;
581 	return (np1);
582 }
583 
584 /*
585  * tree_name_repairdash -- repair a class name that contained a dash
586  *
587  * this routine is called by the parser when a dash is encountered
588  * in a class name.  the event protocol allows the dashes but our
589  * lexer considers them a separate token (arithmetic minus).  an extra
590  * rule in the parser catches this case and calls this routine to fixup
591  * the last component of the class name (so far) by constructing the
592  * new stable entry for a name including the dash.
593  */
594 struct node *
595 tree_name_repairdash(struct node *np, const char *s)
596 {
597 	int len;
598 	char *buf;
599 
600 	ASSERT(np != NULL && s != NULL);
601 
602 	if (np->t != T_NAME)
603 		outfl(O_DIE, np->file, np->line,
604 		    "tree_name_repairdash: internal error (np type %d)",
605 		    np->t);
606 
607 	ASSERT(np->u.name.last != NULL);
608 
609 	len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1;
610 	buf = MALLOC(len);
611 	(void) snprintf(buf, len, "%s-%s", np->u.name.last->u.name.s, s);
612 	np->u.name.last->u.name.s = stable(buf);
613 	FREE(buf);
614 	return (np);
615 }
616 
617 struct node *
618 tree_name_repairdash2(const char *s, struct node *np)
619 {
620 	int len;
621 	char *buf;
622 
623 	ASSERT(np != NULL && s != NULL);
624 
625 	if (np->t != T_NAME)
626 		outfl(O_DIE, np->file, np->line,
627 		    "tree_name_repairdash: internal error (np type %d)",
628 		    np->t);
629 
630 	ASSERT(np->u.name.last != NULL);
631 
632 	len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1;
633 	buf = MALLOC(len);
634 	(void) snprintf(buf, len, "%s-%s", s, np->u.name.last->u.name.s);
635 	np->u.name.last->u.name.s = stable(buf);
636 	FREE(buf);
637 	return (np);
638 }
639 
640 struct node *
641 tree_name_iterator(struct node *np1, struct node *np2)
642 {
643 	ASSERT(np1 != NULL);
644 	ASSERT(np2 != NULL);
645 	ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t));
646 
647 	np1->u.name.child = np2;
648 
649 	check_name_iterator(np1);
650 
651 	return (np1);
652 }
653 
654 struct node *
655 tree_timeval(const char *s, const char *suffix, const char *file, int line)
656 {
657 	struct node *ret = newnode(T_TIMEVAL, file, line);
658 	const unsigned long long *ullp;
659 
660 	ASSERT(s != NULL);
661 	ASSERT(suffix != NULL);
662 
663 	if ((ullp = lex_s2ullp_lut_lookup(Timesuffixlut, suffix)) == NULL) {
664 		outfl(O_ERR, file, line,
665 		    "unrecognized number suffix: %s", suffix);
666 		/* still construct a valid timeval node so parsing continues */
667 		ret->u.ull = 1;
668 	} else {
669 		ret->u.ull = (unsigned long long)strtoul(s, NULL, 0) * *ullp;
670 	}
671 
672 	return (ret);
673 }
674 
675 struct node *
676 tree_num(const char *s, const char *file, int line)
677 {
678 	struct node *ret = newnode(T_NUM, file, line);
679 
680 	ret->u.ull = (unsigned long long)strtoul(s, NULL, 0);
681 	return (ret);
682 }
683 
684 struct node *
685 tree_quote(const char *s, const char *file, int line)
686 {
687 	struct node *ret = newnode(T_QUOTE, file, line);
688 
689 	ret->u.quote.s = stable(s);
690 	return (ret);
691 }
692 
693 struct node *
694 tree_func(const char *s, struct node *np, const char *file, int line)
695 {
696 	struct node *ret = newnode(T_FUNC, file, line);
697 
698 	ret->u.func.s = s;
699 	ret->u.func.arglist = np;
700 
701 	check_func(ret);
702 
703 	return (ret);
704 }
705 
706 /*
707  * given a list from a prop or mask statement or a function argument,
708  * convert all iterators to explicit iterators by inventing appropriate
709  * iterator names.
710  */
711 static void
712 make_explicit(struct node *np, int eventonly)
713 {
714 	struct node *pnp;	/* component of pathname */
715 	struct node *pnp2;
716 	int count;
717 	static size_t namesz;
718 
719 	if (Newname == NULL) {
720 		namesz = 200;
721 		Newname = MALLOC(namesz);
722 	}
723 
724 	if (np == NULL)
725 		return;		/* all done */
726 
727 	switch (np->t) {
728 		case T_ASSIGN:
729 		case T_CONDIF:
730 		case T_CONDELSE:
731 		case T_NE:
732 		case T_EQ:
733 		case T_LT:
734 		case T_LE:
735 		case T_GT:
736 		case T_GE:
737 		case T_BITAND:
738 		case T_BITOR:
739 		case T_BITXOR:
740 		case T_BITNOT:
741 		case T_LSHIFT:
742 		case T_RSHIFT:
743 		case T_LIST:
744 		case T_AND:
745 		case T_OR:
746 		case T_NOT:
747 		case T_ADD:
748 		case T_SUB:
749 		case T_MUL:
750 		case T_DIV:
751 		case T_MOD:
752 			make_explicit(np->u.expr.left, eventonly);
753 			make_explicit(np->u.expr.right, eventonly);
754 			break;
755 
756 		case T_EVENT:
757 			make_explicit(np->u.event.epname, 0);
758 			make_explicit(np->u.event.eexprlist, 1);
759 			break;
760 
761 		case T_FUNC:
762 			make_explicit(np->u.func.arglist, eventonly);
763 			break;
764 
765 		case T_NAME:
766 			if (eventonly)
767 				return;
768 			for (pnp = np; pnp != NULL; pnp = pnp->u.name.next)
769 				if (pnp->u.name.child == NULL) {
770 					/*
771 					 * found implicit iterator.  convert
772 					 * it to an explicit iterator by
773 					 * using the name of the component
774 					 * appended with '#' and the number
775 					 * of times we've seen this same
776 					 * component name in this path so far.
777 					 */
778 					count = 0;
779 					for (pnp2 = np; pnp2 != NULL;
780 					    pnp2 = pnp2->u.name.next)
781 						if (pnp2 == pnp)
782 							break;
783 						else if (pnp2->u.name.s ==
784 						    pnp->u.name.s)
785 							count++;
786 
787 					if (namesz < strlen(pnp->u.name.s) +
788 					    100) {
789 						namesz = strlen(pnp->u.name.s) +
790 						    100;
791 						FREE(Newname);
792 						Newname = MALLOC(namesz);
793 					}
794 					/*
795 					 * made up interator name is:
796 					 *	name#ordinal
797 					 * or
798 					 *	name##ordinal
799 					 * the first one is used for vertical
800 					 * expansion, the second for horizontal.
801 					 * either way, the '#' embedded in
802 					 * the name makes it impossible to
803 					 * collide with an actual iterator
804 					 * given to us in the eversholt file.
805 					 */
806 					(void) snprintf(Newname, namesz,
807 					    "%s#%s%d", pnp->u.name.s,
808 					    (pnp->u.name.it == IT_HORIZONTAL) ?
809 					    "#" : "", count);
810 
811 					pnp->u.name.child = tree_name(Newname,
812 					    IT_NONE, pnp->file, pnp->line);
813 					pnp->u.name.childgen = 1;
814 				}
815 			break;
816 	}
817 }
818 
819 struct node *
820 tree_pname(struct node *np)
821 {
822 	make_explicit(np, 0);
823 	return (np);
824 }
825 
826 struct node *
827 tree_arrow(struct node *lhs, struct node *nnp, struct node *knp,
828     struct node *rhs)
829 {
830 	struct node *ret;
831 
832 	ASSERT(lhs != NULL || rhs != NULL);
833 
834 	ret = newnode(T_ARROW,
835 	    (lhs) ? lhs->file : rhs->file,
836 	    (lhs) ? lhs->line : rhs->line);
837 
838 	ret->u.arrow.lhs = lhs;
839 	ret->u.arrow.nnp = nnp;
840 	ret->u.arrow.knp = knp;
841 	ret->u.arrow.rhs = rhs;
842 
843 	make_explicit(lhs, 0);
844 	make_explicit(rhs, 0);
845 
846 	check_arrow(ret);
847 
848 	return (ret);
849 }
850 
851 static struct lut *
852 nvpair2lut(struct node *np, struct lut *lutp, enum nodetype t)
853 {
854 	if (np) {
855 		if (np->t == T_NVPAIR) {
856 			ASSERTeq(np->u.expr.left->t, T_NAME,
857 			    ptree_nodetype2str);
858 			check_stmt_allowed_properties(t, np, lutp);
859 			lutp = tree_s2np_lut_add(lutp,
860 			    np->u.expr.left->u.name.s, np->u.expr.right);
861 		} else if (np->t == T_LIST) {
862 			lutp = nvpair2lut(np->u.expr.left, lutp, t);
863 			lutp = nvpair2lut(np->u.expr.right, lutp, t);
864 		} else
865 			outfl(O_DIE, np->file, np->line,
866 			    "internal error: nvpair2lut type %s",
867 			    ptree_nodetype2str(np->t));
868 	}
869 
870 	return (lutp);
871 }
872 
873 struct lut *
874 tree_s2np_lut_add(struct lut *root, const char *s, struct node *np)
875 {
876 	return (lut_add(root, (void *)s, (void *)np, NULL));
877 }
878 
879 struct node *
880 tree_s2np_lut_lookup(struct lut *root, const char *s)
881 {
882 	return (struct node *)lut_lookup(root, (void *)s, NULL);
883 }
884 
885 struct lut *
886 tree_name2np_lut_add(struct lut *root, struct node *namep, struct node *np)
887 {
888 	return (lut_add(root, (void *)namep, (void *)np,
889 	    (lut_cmp)tree_namecmp));
890 }
891 
892 struct node *
893 tree_name2np_lut_lookup(struct lut *root, struct node *namep)
894 {
895 	return (struct node *)
896 	    lut_lookup(root, (void *)namep, (lut_cmp)tree_namecmp);
897 }
898 
899 struct node *
900 tree_name2np_lut_lookup_name(struct lut *root, struct node *namep)
901 {
902 	return (struct node *)
903 	    lut_lookup_lhs(root, (void *)namep, (lut_cmp)tree_namecmp);
904 }
905 
906 struct lut *
907 tree_event2np_lut_add(struct lut *root, struct node *enp, struct node *np)
908 {
909 	return (lut_add(root, (void *)enp, (void *)np, (lut_cmp)tree_eventcmp));
910 }
911 
912 struct node *
913 tree_event2np_lut_lookup(struct lut *root, struct node *enp)
914 {
915 	return ((struct node *)
916 	    lut_lookup(root, (void *)enp, (lut_cmp)tree_eventcmp));
917 }
918 
919 struct node *
920 tree_event2np_lut_lookup_event(struct lut *root, struct node *enp)
921 {
922 	return ((struct node *)
923 	    lut_lookup_lhs(root, (void *)enp, (lut_cmp)tree_eventcmp));
924 }
925 
926 static struct node *
927 dodecl(enum nodetype t, const char *file, int line,
928     struct node *np, struct node *nvpairs, struct lut **lutpp,
929     struct stats *countp, int justpath)
930 {
931 	struct node *ret;
932 	struct node *decl;
933 
934 	/* allocate parse tree node */
935 	ret = newnode(t, file, line);
936 	ret->u.stmt.np = np;
937 	ret->u.stmt.nvpairs = nvpairs;
938 
939 	/*
940 	 * the global lut pointed to by lutpp (Faults, Defects, Upsets,
941 	 * Errors, Ereports, Serds, FRUs, or ASRUs) keeps the first decl.
942 	 * if this isn't the first declr, we merge the
943 	 * nvpairs into the first decl so we have a
944 	 * merged table to look up properties from.
945 	 * if this is the first time we've seen this fault,
946 	 * we add it to the global lut and start lutp
947 	 * off with any nvpairs from this declaration statement.
948 	 */
949 	if (justpath && (decl = tree_name2np_lut_lookup(*lutpp, np)) == NULL) {
950 		/* this is the first time name is declared */
951 		stats_counter_bump(countp);
952 		*lutpp = tree_name2np_lut_add(*lutpp, np, ret);
953 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t);
954 	} else if (!justpath &&
955 	    (decl = tree_event2np_lut_lookup(*lutpp, np)) == NULL) {
956 		/* this is the first time event is declared */
957 		stats_counter_bump(countp);
958 		*lutpp = tree_event2np_lut_add(*lutpp, np, ret);
959 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t);
960 	} else {
961 		/* was declared before, just add new nvpairs to its lutp */
962 		decl->u.stmt.lutp = nvpair2lut(nvpairs, decl->u.stmt.lutp, t);
963 	}
964 
965 	return (ret);
966 }
967 
968 /*ARGSUSED*/
969 static void
970 update_serd_refstmt(void *lhs, void *rhs, void *arg)
971 {
972 	struct node *serd;
973 
974 	ASSERT(rhs != NULL);
975 
976 	serd = tree_s2np_lut_lookup(((struct node *)rhs)->u.stmt.lutp,
977 				    L_engine);
978 	if (serd == NULL)
979 		return;
980 
981 	ASSERT(serd->t == T_EVENT);
982 	if (arg != NULL && tree_eventcmp(serd, (struct node *)arg) != 0)
983 		return;
984 
985 	serd = tree_event2np_lut_lookup(SERDs, serd);
986 	if (serd != NULL)
987 		serd->u.stmt.flags |= STMT_REF;
988 }
989 
990 struct node *
991 tree_decl(enum nodetype t, struct node *np, struct node *nvpairs,
992     const char *file, int line)
993 {
994 	struct node *decl;
995 	struct node *ret;
996 
997 	ASSERT(np != NULL);
998 
999 	check_type_iterator(np);
1000 
1001 	switch (t) {
1002 	case T_EVENT:
1003 		/* determine the type of event being declared */
1004 		ASSERT(np->u.event.ename->t == T_NAME);
1005 		switch (np->u.event.ename->u.name.t) {
1006 		case N_FAULT:
1007 			ret = dodecl(T_FAULT, file, line, np, nvpairs,
1008 			    &Faults, Faultcount, 0);
1009 			break;
1010 
1011 		case N_UPSET:
1012 			ret = dodecl(T_UPSET, file, line, np, nvpairs,
1013 			    &Upsets, Upsetcount, 0);
1014 
1015 			/* increment serd statement reference */
1016 			decl = tree_event2np_lut_lookup(Upsets, np);
1017 			update_serd_refstmt(NULL, decl, NULL);
1018 			break;
1019 
1020 		case N_DEFECT:
1021 			ret = dodecl(T_DEFECT, file, line, np, nvpairs,
1022 			    &Defects, Defectcount, 0);
1023 			break;
1024 
1025 		case N_ERROR:
1026 			ret = dodecl(T_ERROR, file, line, np, nvpairs,
1027 			    &Errors, Errorcount, 0);
1028 			break;
1029 
1030 		case N_EREPORT:
1031 			ret = dodecl(T_EREPORT, file, line, np, nvpairs,
1032 			    &Ereports, Ereportcount, 0);
1033 			/*
1034 			 * keep a lut of just the enames, so that the DE
1035 			 * can subscribe to a uniqified list of event
1036 			 * classes.
1037 			 */
1038 			Ereportenames =
1039 			    tree_name2np_lut_add(Ereportenames,
1040 			    np->u.event.ename, np);
1041 			break;
1042 
1043 		default:
1044 			outfl(O_ERR, file, line,
1045 			    "tree_decl: internal error, event name type %s",
1046 			    ptree_nametype2str(np->u.event.ename->u.name.t));
1047 		}
1048 		break;
1049 
1050 	case T_ENGINE:
1051 		/* determine the type of engine being declared */
1052 		ASSERT(np->u.event.ename->t == T_NAME);
1053 		switch (np->u.event.ename->u.name.t) {
1054 		case N_SERD:
1055 			ret = dodecl(T_SERD, file, line, np, nvpairs,
1056 			    &SERDs, SERDcount, 0);
1057 			lut_walk(Upsets, update_serd_refstmt, np);
1058 			break;
1059 
1060 		case N_STAT:
1061 			ret = dodecl(T_STAT, file, line, np, nvpairs,
1062 			    &STATs, STATcount, 0);
1063 			break;
1064 
1065 		default:
1066 			outfl(O_ERR, file, line,
1067 			    "tree_decl: internal error, engine name type %s",
1068 			    ptree_nametype2str(np->u.event.ename->u.name.t));
1069 		}
1070 		break;
1071 	case T_ASRU:
1072 		ret = dodecl(T_ASRU, file, line, np, nvpairs,
1073 		    &ASRUs, ASRUcount, 1);
1074 		break;
1075 
1076 	case T_FRU:
1077 		ret = dodecl(T_FRU, file, line, np, nvpairs,
1078 		    &FRUs, FRUcount, 1);
1079 		break;
1080 
1081 	case T_CONFIG:
1082 		/*
1083 		 * config statements are different from above: they
1084 		 * are not merged at all (until the configuration cache
1085 		 * code does its own style of merging.  and the properties
1086 		 * are a free-for-all -- we don't check for allowed or
1087 		 * required config properties.
1088 		 */
1089 		ret = newnode(T_CONFIG, file, line);
1090 		ret->u.stmt.np = np;
1091 		ret->u.stmt.nvpairs = nvpairs;
1092 		ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, T_CONFIG);
1093 
1094 		if (lut_lookup(Configs, np, (lut_cmp)tree_namecmp) == NULL)
1095 			stats_counter_bump(Configcount);
1096 
1097 		Configs = lut_add(Configs, (void *)np, (void *)ret, NULL);
1098 		break;
1099 
1100 	default:
1101 		out(O_DIE, "tree_decl: internal error, type %s",
1102 		    ptree_nodetype2str(t));
1103 	}
1104 
1105 	return (ret);
1106 }
1107 
1108 /* keep backpointers in arrows to the prop they belong to (used for scoping) */
1109 static void
1110 set_arrow_prop(struct node *prop, struct node *np)
1111 {
1112 	if (np == NULL)
1113 		return;
1114 
1115 	if (np->t == T_ARROW) {
1116 		np->u.arrow.prop = prop;
1117 		set_arrow_prop(prop, np->u.arrow.lhs);
1118 		/*
1119 		 * no need to recurse right or handle T_LIST since
1120 		 * T_ARROWs always cascade left and are at the top
1121 		 * of the parse tree.  (you can see this in the rule
1122 		 * for "propbody" in escparse.y.)
1123 		 */
1124 	}
1125 }
1126 
1127 struct node *
1128 tree_stmt(enum nodetype t, struct node *np, const char *file, int line)
1129 {
1130 	struct node *ret = newnode(t, file, line);
1131 	struct node *pp;
1132 	int inlist = 0;
1133 
1134 	ret->u.stmt.np = np;
1135 
1136 	switch (t) {
1137 	case T_PROP:
1138 		check_proplists(t, np);
1139 		check_propnames(t, np, 0, 0);
1140 		check_propscope(np);
1141 		set_arrow_prop(ret, np);
1142 
1143 		for (pp = Props; pp; pp = pp->u.stmt.next) {
1144 			if (tree_treecmp(pp, ret, T_NAME,
1145 					(lut_cmp)tree_namecmp) == 0) {
1146 				inlist = 1;
1147 				break;
1148 			}
1149 		}
1150 		if (inlist == 0)
1151 			stats_counter_bump(Propcount);
1152 
1153 		/* "Props" is a linked list of all prop statements */
1154 		if (Lastprops)
1155 			Lastprops->u.stmt.next = ret;
1156 		else
1157 			Props = ret;
1158 		Lastprops = ret;
1159 		break;
1160 
1161 	case T_MASK:
1162 		check_proplists(t, np);
1163 		check_propnames(t, np, 0, 0);
1164 		check_propscope(np);
1165 		set_arrow_prop(ret, np);
1166 
1167 		for (pp = Masks; pp; pp = pp->u.stmt.next) {
1168 			if (tree_treecmp(pp, ret, T_NAME,
1169 					(lut_cmp)tree_namecmp) == 0) {
1170 				inlist = 1;
1171 				break;
1172 			}
1173 		}
1174 		if (inlist == 0)
1175 			stats_counter_bump(Maskcount);
1176 
1177 		/* "Masks" is a linked list of all mask statements */
1178 		if (Lastmasks)
1179 			Lastmasks->u.stmt.next = ret;
1180 		else
1181 			Masks = ret;
1182 		Lastmasks = ret;
1183 		stats_counter_bump(Maskcount);
1184 		break;
1185 
1186 	default:
1187 		outfl(O_DIE, np->file, np->line,
1188 		    "tree_stmt: internal error (t %d)", t);
1189 	}
1190 
1191 	return (ret);
1192 }
1193 
1194 void
1195 tree_report()
1196 {
1197 	/*
1198 	 * The only declarations with required properties
1199 	 * currently are faults and serds. Make sure the
1200 	 * the declarations have the required properties.
1201 	 */
1202 	lut_walk(Faults, (lut_cb)check_required_props, (void *)T_FAULT);
1203 	lut_walk(Upsets, (lut_cb)check_required_props, (void *)T_UPSET);
1204 	lut_walk(Errors, (lut_cb)check_required_props, (void *)T_ERROR);
1205 	lut_walk(Ereports, (lut_cb)check_required_props, (void *)T_EREPORT);
1206 	lut_walk(SERDs, (lut_cb)check_required_props, (void *)T_SERD);
1207 	lut_walk(STATs, (lut_cb)check_required_props, (void *)T_STAT);
1208 
1209 	/*
1210 	 * we do this now rather than while building the parse
1211 	 * tree because it is inconvenient for the user if we
1212 	 * require SERD engines to be declared before used in
1213 	 * an upset "engine" property.
1214 	 */
1215 	lut_walk(Faults, (lut_cb)check_refcount, (void *)T_FAULT);
1216 	lut_walk(Upsets, (lut_cb)check_upset_engine, (void *)T_UPSET);
1217 	lut_walk(Upsets, (lut_cb)check_refcount, (void *)T_UPSET);
1218 	lut_walk(Errors, (lut_cb)check_refcount, (void *)T_ERROR);
1219 	lut_walk(Ereports, (lut_cb)check_refcount, (void *)T_EREPORT);
1220 	lut_walk(SERDs, (lut_cb)check_refcount, (void *)T_SERD);
1221 
1222 	/* check for cycles */
1223 	lut_walk(Errors, (lut_cb)check_cycle, (void *)0);
1224 }
1225 
1226 /* compare two T_NAMES by only looking at components, not iterators */
1227 int
1228 tree_namecmp(struct node *np1, struct node *np2)
1229 {
1230 	ASSERT(np1 != NULL);
1231 	ASSERT(np2 != NULL);
1232 	ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t));
1233 	ASSERTinfo(np2->t == T_NAME, ptree_nodetype2str(np1->t));
1234 
1235 	while (np1 && np2 && np1->u.name.s == np2->u.name.s) {
1236 		np1 = np1->u.name.next;
1237 		np2 = np2->u.name.next;
1238 	}
1239 	if (np1 == NULL)
1240 		if (np2 == NULL)
1241 			return (0);
1242 		else
1243 			return (-1);
1244 	else if (np2 == NULL)
1245 		return (1);
1246 	else
1247 		return (np2->u.name.s - np1->u.name.s);
1248 }
1249 
1250 int
1251 tree_eventcmp(struct node *np1, struct node *np2)
1252 {
1253 	int ret;
1254 
1255 	ASSERT(np1 != NULL);
1256 	ASSERT(np2 != NULL);
1257 	ASSERTinfo(np1->t == T_EVENT, ptree_nodetype2str(np1->t));
1258 	ASSERTinfo(np2->t == T_EVENT, ptree_nodetype2str(np2->t));
1259 
1260 	if ((ret = tree_namecmp(np1->u.event.ename,
1261 		np2->u.event.ename)) == 0) {
1262 			if (np1->u.event.epname == NULL &&
1263 				np2->u.event.epname == NULL)
1264 				return (0);
1265 			else if (np1->u.event.epname == NULL)
1266 				return (-1);
1267 			else if (np2->u.event.epname == NULL)
1268 				return (1);
1269 			else
1270 				return tree_namecmp(np1->u.event.epname,
1271 					np2->u.event.epname);
1272 	} else
1273 	return (ret);
1274 }
1275