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