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