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