xref: /illumos-gate/usr/src/cmd/fm/eversholt/common/check.c (revision 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*7aec1d6eScindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * check.c -- routines for checking the prop tree
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * this module provides semantic checks on the parse tree.  most of
297c478bd9Sstevel@tonic-gate  * these checks happen during the construction of the parse tree,
307c478bd9Sstevel@tonic-gate  * when the various tree_X() routines call the various check_X()
317c478bd9Sstevel@tonic-gate  * routines.  in a couple of special cases, a check function will
327c478bd9Sstevel@tonic-gate  * process the parse tree after it has been fully constructed.  these
337c478bd9Sstevel@tonic-gate  * cases are noted in the comments above the check function.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include "out.h"
407c478bd9Sstevel@tonic-gate #include "stable.h"
417c478bd9Sstevel@tonic-gate #include "literals.h"
427c478bd9Sstevel@tonic-gate #include "lut.h"
437c478bd9Sstevel@tonic-gate #include "tree.h"
447c478bd9Sstevel@tonic-gate #include "ptree.h"
457c478bd9Sstevel@tonic-gate #include "check.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static int check_reportlist(enum nodetype t, const char *s, struct node *np);
487c478bd9Sstevel@tonic-gate static int check_num(enum nodetype t, const char *s, struct node *np);
497c478bd9Sstevel@tonic-gate static int check_quote(enum nodetype t, const char *s, struct node *np);
50*7aec1d6eScindi static int check_action(enum nodetype t, const char *s, struct node *np);
517c478bd9Sstevel@tonic-gate static int check_num_func(enum nodetype t, const char *s, struct node *np);
527c478bd9Sstevel@tonic-gate static int check_fru_asru(enum nodetype t, const char *s, struct node *np);
537c478bd9Sstevel@tonic-gate static int check_engine(enum nodetype t, const char *s, struct node *np);
54*7aec1d6eScindi static int check_count(enum nodetype t, const char *s, struct node *np);
557c478bd9Sstevel@tonic-gate static int check_timeval(enum nodetype t, const char *s, struct node *np);
567c478bd9Sstevel@tonic-gate static int check_id(enum nodetype t, const char *s, struct node *np);
577c478bd9Sstevel@tonic-gate static int check_serd_method(enum nodetype t, const char *s, struct node *np);
58*7aec1d6eScindi static int check_serd_id(enum nodetype t, const char *s, struct node *np);
597c478bd9Sstevel@tonic-gate static int check_nork(struct node *np);
607c478bd9Sstevel@tonic-gate static void check_cycle_lhs(struct node *stmtnp, struct node *arrow);
617c478bd9Sstevel@tonic-gate static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs,
627c478bd9Sstevel@tonic-gate     struct node *rhs);
637c478bd9Sstevel@tonic-gate static void check_cycle_rhs(struct node *rhs);
64f358d892Srw145199 static void check_proplists_lhs(enum nodetype t, struct node *lhs);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static struct {
677c478bd9Sstevel@tonic-gate 	enum nodetype t;
687c478bd9Sstevel@tonic-gate 	const char *name;
697c478bd9Sstevel@tonic-gate 	int required;
707c478bd9Sstevel@tonic-gate 	int (*checker)(enum nodetype t, const char *s, struct node *np);
717c478bd9Sstevel@tonic-gate 	int outflags;
727c478bd9Sstevel@tonic-gate } Allowednames[] = {
737c478bd9Sstevel@tonic-gate 	{ T_FAULT, "FITrate", 1, check_num_func, O_ERR },
747c478bd9Sstevel@tonic-gate 	{ T_FAULT, "FRU", 0, check_fru_asru, O_ERR },
757c478bd9Sstevel@tonic-gate 	{ T_FAULT, "ASRU", 0, check_fru_asru, O_ERR },
76*7aec1d6eScindi 	{ T_FAULT, "message", 0, check_num_func, O_ERR },
77*7aec1d6eScindi 	{ T_FAULT, "action", 0, check_action, O_ERR },
78*7aec1d6eScindi 	{ T_FAULT, "count", 0, check_count, O_ERR },
797c478bd9Sstevel@tonic-gate 	{ T_UPSET, "engine", 0, check_engine, O_ERR },
807c478bd9Sstevel@tonic-gate 	{ T_DEFECT, "FRU", 0, check_fru_asru, O_ERR },
817c478bd9Sstevel@tonic-gate 	{ T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR },
827c478bd9Sstevel@tonic-gate 	{ T_EREPORT, "poller", 0, check_id, O_ERR },
837c478bd9Sstevel@tonic-gate 	{ T_EREPORT, "delivery", 0, check_timeval, O_ERR },
847c478bd9Sstevel@tonic-gate 	{ T_SERD, "N", 1, check_num, O_ERR },
857c478bd9Sstevel@tonic-gate 	{ T_SERD, "T", 1, check_timeval, O_ERR },
867c478bd9Sstevel@tonic-gate 	{ T_SERD, "method", 1, check_serd_method, O_ERR },
877c478bd9Sstevel@tonic-gate 	{ T_SERD, "trip", 1, check_reportlist, O_ERR },
887c478bd9Sstevel@tonic-gate 	{ T_SERD, "FRU", 0, check_fru_asru, O_ERR },
89*7aec1d6eScindi 	{ T_SERD, "id", 0, check_serd_id, O_ERR },
907c478bd9Sstevel@tonic-gate 	{ T_ERROR, "ASRU", 0, check_fru_asru, O_ERR },
917c478bd9Sstevel@tonic-gate 	{ T_CONFIG, NULL, 0, check_quote, O_ERR },
927c478bd9Sstevel@tonic-gate 	{ 0, NULL, 0 },
937c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate void
967c478bd9Sstevel@tonic-gate check_init(void)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	int i;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
1017c478bd9Sstevel@tonic-gate 		if (Allowednames[i].name != NULL)
1027c478bd9Sstevel@tonic-gate 			Allowednames[i].name = stable(Allowednames[i].name);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate void
1067c478bd9Sstevel@tonic-gate check_fini(void)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1117c478bd9Sstevel@tonic-gate void
1127c478bd9Sstevel@tonic-gate check_report_combination(struct node *np)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate 	/* nothing to check for here.  poller is only prop and it is optional */
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*
1187c478bd9Sstevel@tonic-gate  * check_path_iterators -- verify all iterators are explicit
1197c478bd9Sstevel@tonic-gate  */
1207c478bd9Sstevel@tonic-gate static void
1217c478bd9Sstevel@tonic-gate check_path_iterators(struct node *np)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	if (np == NULL)
1247c478bd9Sstevel@tonic-gate 		return;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	switch (np->t) {
1277c478bd9Sstevel@tonic-gate 		case T_ARROW:
1287c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.lhs);
1297c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.arrow.rhs);
1307c478bd9Sstevel@tonic-gate 			break;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 		case T_LIST:
1337c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.expr.left);
1347c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.expr.right);
1357c478bd9Sstevel@tonic-gate 			break;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 		case T_EVENT:
1387c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.event.epname);
1397c478bd9Sstevel@tonic-gate 			break;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		case T_NAME:
1427c478bd9Sstevel@tonic-gate 			if (np->u.name.child == NULL)
1437c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
1447c478bd9Sstevel@tonic-gate 				    "internal error: check_path_iterators: "
1457c478bd9Sstevel@tonic-gate 				    "unexpected implicit iterator: %s",
1467c478bd9Sstevel@tonic-gate 				    np->u.name.s);
1477c478bd9Sstevel@tonic-gate 			check_path_iterators(np->u.name.next);
1487c478bd9Sstevel@tonic-gate 			break;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 		default:
1517c478bd9Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
1527c478bd9Sstevel@tonic-gate 			    "internal error: check_path_iterators: "
1537c478bd9Sstevel@tonic-gate 			    "unexpected type: %s",
1547c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(np->t));
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate void
1597c478bd9Sstevel@tonic-gate check_arrow(struct node *np)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	ASSERTinfo(np->t == T_ARROW, ptree_nodetype2str(np->t));
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	if (np->u.arrow.lhs->t != T_ARROW &&
1647c478bd9Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_LIST &&
1657c478bd9Sstevel@tonic-gate 	    np->u.arrow.lhs->t != T_EVENT) {
1667c478bd9Sstevel@tonic-gate 		outfl(O_ERR,
1677c478bd9Sstevel@tonic-gate 		    np->u.arrow.lhs->file, np->u.arrow.lhs->line,
1687c478bd9Sstevel@tonic-gate 		    "%s not allowed on left-hand side of arrow",
1697c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->u.arrow.lhs->t));
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (!check_nork(np->u.arrow.nnp) ||
1737c478bd9Sstevel@tonic-gate 		!check_nork(np->u.arrow.knp))
1747c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
1757c478bd9Sstevel@tonic-gate 			    "counts associated with propagation arrows "
1767c478bd9Sstevel@tonic-gate 			    "must be integers");
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	check_path_iterators(np);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * make sure the nork values are valid.
1837c478bd9Sstevel@tonic-gate  * Nork values must be "A" for all(T_NAME),
1847c478bd9Sstevel@tonic-gate  * a number(T_NUM), or a simple
1857c478bd9Sstevel@tonic-gate  * expression(T_SUB, T_ADD, T_MUL, T_DIV)
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate static int
1887c478bd9Sstevel@tonic-gate check_nork(struct node *np)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	int rval = 0;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/* NULL means no nork value which is allowed */
1937c478bd9Sstevel@tonic-gate 	if (np == NULL) {
1947c478bd9Sstevel@tonic-gate 		rval = 1;
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 	else
1977c478bd9Sstevel@tonic-gate 	{
1987c478bd9Sstevel@tonic-gate 		/* if the nork is a name it must be A for "All" */
1997c478bd9Sstevel@tonic-gate 		if (np->t == T_NAME)
2007c478bd9Sstevel@tonic-gate 			if (*np->u.name.s == 'A')
2017c478bd9Sstevel@tonic-gate 				return (1);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 		/*  T_NUM allowed */
2047c478bd9Sstevel@tonic-gate 		if (np->t == T_NUM)
2057c478bd9Sstevel@tonic-gate 			rval = 1;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		/*  simple expressions allowed */
2087c478bd9Sstevel@tonic-gate 		if (np->t == T_SUB ||
2097c478bd9Sstevel@tonic-gate 			np->t == T_ADD ||
2107c478bd9Sstevel@tonic-gate 			np->t == T_MUL ||
2117c478bd9Sstevel@tonic-gate 			np->t == T_DIV)
2127c478bd9Sstevel@tonic-gate 			rval = 1;
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	return (rval);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate static int
2197c478bd9Sstevel@tonic-gate check_reportlist(enum nodetype t, const char *s, struct node *np)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	if (np == NULL)
2227c478bd9Sstevel@tonic-gate 		return (1);
2237c478bd9Sstevel@tonic-gate 	else if (np->t == T_EVENT) {
2247c478bd9Sstevel@tonic-gate 		if (np->u.event.ename->u.name.t != N_EREPORT) {
2257c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2267c478bd9Sstevel@tonic-gate 			    "%s %s property must begin with \"ereport.\"",
2277c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2287c478bd9Sstevel@tonic-gate 		} else if (tree_event2np_lut_lookup(Ereports, np) == NULL) {
2297c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2307c478bd9Sstevel@tonic-gate 			    "%s %s property contains undeclared name",
2317c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 		check_type_iterator(np);
2347c478bd9Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
2357c478bd9Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.left);
2367c478bd9Sstevel@tonic-gate 		(void) check_reportlist(t, s, np->u.expr.right);
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 	return (1);
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate static int
2427c478bd9Sstevel@tonic-gate check_num(enum nodetype t, const char *s, struct node *np)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2457c478bd9Sstevel@tonic-gate 	if (np->t != T_NUM)
2467c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2477c478bd9Sstevel@tonic-gate 		    "%s %s property must be a single number",
2487c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2497c478bd9Sstevel@tonic-gate 	return (1);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
2537c478bd9Sstevel@tonic-gate static int
2547c478bd9Sstevel@tonic-gate check_quote(enum nodetype t, const char *s, struct node *np)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2577c478bd9Sstevel@tonic-gate 	if (np->t != T_QUOTE)
2587c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2597c478bd9Sstevel@tonic-gate 		    "%s properties must be quoted strings",
2607c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t));
2617c478bd9Sstevel@tonic-gate 	return (1);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate static int
265*7aec1d6eScindi check_action(enum nodetype t, const char *s, struct node *np)
266*7aec1d6eScindi {
267*7aec1d6eScindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
268*7aec1d6eScindi 
269*7aec1d6eScindi 	if (np->t != T_FUNC)
270*7aec1d6eScindi 		outfl(O_ERR, np->file, np->line,
271*7aec1d6eScindi 		    "%s %s property must be a function or list of functions",
272*7aec1d6eScindi 		    ptree_nodetype2str(t), s);
273*7aec1d6eScindi 	return (1);
274*7aec1d6eScindi }
275*7aec1d6eScindi 
276*7aec1d6eScindi static int
2777c478bd9Sstevel@tonic-gate check_num_func(enum nodetype t, const char *s, struct node *np)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
2807c478bd9Sstevel@tonic-gate 	if (np->t != T_NUM && np->t != T_FUNC)
2817c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
2827c478bd9Sstevel@tonic-gate 		    "%s %s property must be a number or function",
2837c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
2847c478bd9Sstevel@tonic-gate 	return (1);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate static int
2887c478bd9Sstevel@tonic-gate check_fru_asru(enum nodetype t, const char *s, struct node *np)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	ASSERT(s != NULL);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/* make sure it is a node type T_NAME? */
2937c478bd9Sstevel@tonic-gate 	if (np->t == T_NAME) {
2947c478bd9Sstevel@tonic-gate 	    if (s == L_ASRU) {
2957c478bd9Sstevel@tonic-gate 		if (tree_name2np_lut_lookup_name(ASRUs, np) == NULL)
2967c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
2977c478bd9Sstevel@tonic-gate 			    "ASRU property contains undeclared asru");
2987c478bd9Sstevel@tonic-gate 	    } else if (s == L_FRU) {
2997c478bd9Sstevel@tonic-gate 		if (tree_name2np_lut_lookup_name(FRUs, np) == NULL)
3007c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
3017c478bd9Sstevel@tonic-gate 			    "FRU property contains undeclared fru");
3027c478bd9Sstevel@tonic-gate 	    } else {
3037c478bd9Sstevel@tonic-gate 		    outfl(O_ERR, np->file, np->line,
3047c478bd9Sstevel@tonic-gate 			"illegal property name in %s declaration: %s",
3057c478bd9Sstevel@tonic-gate 			ptree_nodetype2str(t), s);
3067c478bd9Sstevel@tonic-gate 	    }
3077c478bd9Sstevel@tonic-gate 	    check_type_iterator(np);
3087c478bd9Sstevel@tonic-gate 	} else
3097c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3107c478bd9Sstevel@tonic-gate 		    "illegal type used for %s property: %s",
3117c478bd9Sstevel@tonic-gate 		    s, ptree_nodetype2str(np->t));
3127c478bd9Sstevel@tonic-gate 	return (1);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate static int
3167c478bd9Sstevel@tonic-gate check_engine(enum nodetype t, const char *s, struct node *np)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3197c478bd9Sstevel@tonic-gate 	if (np->t != T_EVENT)
3207c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3217c478bd9Sstevel@tonic-gate 		    "%s %s property must be an engine name "
3227c478bd9Sstevel@tonic-gate 		    "(i.e. serd.x or serd.x@a/b)",
3237c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	return (1);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate static int
329*7aec1d6eScindi check_count(enum nodetype t, const char *s, struct node *np)
330*7aec1d6eScindi {
331*7aec1d6eScindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
332*7aec1d6eScindi 	if (np->t != T_EVENT)
333*7aec1d6eScindi 		outfl(O_ERR, np->file, np->line,
334*7aec1d6eScindi 		    "%s %s property must be an engine name "
335*7aec1d6eScindi 		    "(i.e. stat.x or stat.x@a/b)",
336*7aec1d6eScindi 		    ptree_nodetype2str(t), s);
337*7aec1d6eScindi 
338*7aec1d6eScindi 	/* XXX confirm engine has been declared */
339*7aec1d6eScindi 	return (1);
340*7aec1d6eScindi }
341*7aec1d6eScindi 
342*7aec1d6eScindi static int
3437c478bd9Sstevel@tonic-gate check_timeval(enum nodetype t, const char *s, struct node *np)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3467c478bd9Sstevel@tonic-gate 	if (np->t != T_TIMEVAL)
3477c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3487c478bd9Sstevel@tonic-gate 		    "%s %s property must be a number with time units",
3497c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3507c478bd9Sstevel@tonic-gate 	return (1);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate static int
3547c478bd9Sstevel@tonic-gate check_id(enum nodetype t, const char *s, struct node *np)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3577c478bd9Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child)
3587c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3597c478bd9Sstevel@tonic-gate 		    "%s %s property must be simple name",
3607c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3617c478bd9Sstevel@tonic-gate 	return (1);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate static int
3657c478bd9Sstevel@tonic-gate check_serd_method(enum nodetype t, const char *s, struct node *np)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
3687c478bd9Sstevel@tonic-gate 	if (np->t != T_NAME || np->u.name.next || np->u.name.child ||
3697c478bd9Sstevel@tonic-gate 	    (np->u.name.s != L_volatile &&
3707c478bd9Sstevel@tonic-gate 	    np->u.name.s != L_persistent))
3717c478bd9Sstevel@tonic-gate 		outfl(O_ERR, np->file, np->line,
3727c478bd9Sstevel@tonic-gate 		    "%s %s property must be \"volatile\" or \"persistent\"",
3737c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
3747c478bd9Sstevel@tonic-gate 	return (1);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
377*7aec1d6eScindi static int
378*7aec1d6eScindi check_serd_id(enum nodetype t, const char *s, struct node *np)
379*7aec1d6eScindi {
380*7aec1d6eScindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
381*7aec1d6eScindi 	if (np->t != T_GLOBID)
382*7aec1d6eScindi 		outfl(O_ERR, np->file, np->line,
383*7aec1d6eScindi 		    "%s %s property must be a global ID",
384*7aec1d6eScindi 		    ptree_nodetype2str(t), s);
385*7aec1d6eScindi 	return (1);
386*7aec1d6eScindi }
387*7aec1d6eScindi 
3887c478bd9Sstevel@tonic-gate void
3897c478bd9Sstevel@tonic-gate check_stmt_required_properties(struct node *stmtnp)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	struct lut *lutp = stmtnp->u.stmt.lutp;
3927c478bd9Sstevel@tonic-gate 	struct node *np = stmtnp->u.stmt.np;
3937c478bd9Sstevel@tonic-gate 	int i;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
3967c478bd9Sstevel@tonic-gate 		if (stmtnp->t == Allowednames[i].t &&
3977c478bd9Sstevel@tonic-gate 		    Allowednames[i].required &&
3987c478bd9Sstevel@tonic-gate 		    tree_s2np_lut_lookup(lutp, Allowednames[i].name) == NULL)
3997c478bd9Sstevel@tonic-gate 			outfl(Allowednames[i].outflags,
4007c478bd9Sstevel@tonic-gate 			    np->file, np->line,
4017c478bd9Sstevel@tonic-gate 			    "%s statement missing property: %s",
4027c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(stmtnp->t),
4037c478bd9Sstevel@tonic-gate 			    Allowednames[i].name);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate void
4077c478bd9Sstevel@tonic-gate check_stmt_allowed_properties(enum nodetype t,
4087c478bd9Sstevel@tonic-gate     struct node *nvpairnp, struct lut *lutp)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate 	int i;
4117c478bd9Sstevel@tonic-gate 	const char *s = nvpairnp->u.expr.left->u.name.s;
4127c478bd9Sstevel@tonic-gate 	struct node *np;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	for (i = 0; Allowednames[i].t; i++)
4157c478bd9Sstevel@tonic-gate 		if (t == Allowednames[i].t && Allowednames[i].name == NULL) {
4167c478bd9Sstevel@tonic-gate 			/* NULL name means just call checker */
4177c478bd9Sstevel@tonic-gate 			(*Allowednames[i].checker)(t, s,
4187c478bd9Sstevel@tonic-gate 			    nvpairnp->u.expr.right);
4197c478bd9Sstevel@tonic-gate 			return;
4207c478bd9Sstevel@tonic-gate 		} else if (t == Allowednames[i].t && s == Allowednames[i].name)
4217c478bd9Sstevel@tonic-gate 			break;
4227c478bd9Sstevel@tonic-gate 	if (Allowednames[i].name == NULL)
4237c478bd9Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4247c478bd9Sstevel@tonic-gate 		    "illegal property name in %s declaration: %s",
4257c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4267c478bd9Sstevel@tonic-gate 	else if ((np = tree_s2np_lut_lookup(lutp, s)) != NULL) {
4277c478bd9Sstevel@tonic-gate 		/*
4287c478bd9Sstevel@tonic-gate 		 * redeclaring prop is allowed if value is the same
4297c478bd9Sstevel@tonic-gate 		 */
4307c478bd9Sstevel@tonic-gate 		if (np->t != nvpairnp->u.expr.right->t)
4317c478bd9Sstevel@tonic-gate 			outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4327c478bd9Sstevel@tonic-gate 			    "property redeclared (with differnt type) "
4337c478bd9Sstevel@tonic-gate 			    "in %s declaration: %s",
4347c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t), s);
4357c478bd9Sstevel@tonic-gate 		switch (np->t) {
4367c478bd9Sstevel@tonic-gate 			case T_NUM:
4377c478bd9Sstevel@tonic-gate 			case T_TIMEVAL:
4387c478bd9Sstevel@tonic-gate 				if (np->u.ull == nvpairnp->u.expr.right->u.ull)
4397c478bd9Sstevel@tonic-gate 					return;
4407c478bd9Sstevel@tonic-gate 				break;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 			case T_NAME:
4437c478bd9Sstevel@tonic-gate 				if (tree_namecmp(np,
4447c478bd9Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4457c478bd9Sstevel@tonic-gate 					return;
4467c478bd9Sstevel@tonic-gate 				break;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 			case T_EVENT:
4497c478bd9Sstevel@tonic-gate 				if (tree_eventcmp(np,
4507c478bd9Sstevel@tonic-gate 				    nvpairnp->u.expr.right) == 0)
4517c478bd9Sstevel@tonic-gate 					return;
4527c478bd9Sstevel@tonic-gate 				break;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 			default:
4557c478bd9Sstevel@tonic-gate 				outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4567c478bd9Sstevel@tonic-gate 				    "value for property \"%s\" is an "
4577c478bd9Sstevel@tonic-gate 				    "invalid type: %s",
4587c478bd9Sstevel@tonic-gate 				    nvpairnp->u.expr.left->u.name.s,
4597c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(np->t));
4607c478bd9Sstevel@tonic-gate 				return;
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
4637c478bd9Sstevel@tonic-gate 		    "property redeclared in %s declaration: %s",
4647c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), s);
4657c478bd9Sstevel@tonic-gate 	} else
4667c478bd9Sstevel@tonic-gate 		(*Allowednames[i].checker)(t, s, nvpairnp->u.expr.right);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate void
4707c478bd9Sstevel@tonic-gate check_propnames(enum nodetype t, struct node *np, int from, int to)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	struct node *dnp;
4737c478bd9Sstevel@tonic-gate 	struct lut *lutp;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
4767c478bd9Sstevel@tonic-gate 	ASSERTinfo(np->t == T_EVENT || np->t == T_LIST || np->t == T_ARROW,
4777c478bd9Sstevel@tonic-gate 				ptree_nodetype2str(np->t));
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if (np->t == T_EVENT) {
4807c478bd9Sstevel@tonic-gate 		switch (np->u.event.ename->u.name.t) {
4817c478bd9Sstevel@tonic-gate 		case N_UNSPEC:
4827c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
4837c478bd9Sstevel@tonic-gate 			    "name in %s statement must begin with "
4847c478bd9Sstevel@tonic-gate 			    "type (example: \"error.\")",
4857c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t));
4867c478bd9Sstevel@tonic-gate 			return;
4877c478bd9Sstevel@tonic-gate 		case N_FAULT:
4887c478bd9Sstevel@tonic-gate 			lutp = Faults;
4897c478bd9Sstevel@tonic-gate 			if (to) {
4907c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
4917c478bd9Sstevel@tonic-gate 				    "%s has fault on right side of \"->\"",
4927c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
4937c478bd9Sstevel@tonic-gate 				return;
4947c478bd9Sstevel@tonic-gate 			}
4957c478bd9Sstevel@tonic-gate 			if (!from) {
4967c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
4977c478bd9Sstevel@tonic-gate 				    "internal error: %s has fault without "
4987c478bd9Sstevel@tonic-gate 				    "from flag",
4997c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5007c478bd9Sstevel@tonic-gate 			}
5017c478bd9Sstevel@tonic-gate 			break;
5027c478bd9Sstevel@tonic-gate 		case N_UPSET:
5037c478bd9Sstevel@tonic-gate 			lutp = Upsets;
5047c478bd9Sstevel@tonic-gate 			if (to) {
5057c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5067c478bd9Sstevel@tonic-gate 				    "%s has upset on right side of \"->\"",
5077c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5087c478bd9Sstevel@tonic-gate 				return;
5097c478bd9Sstevel@tonic-gate 			}
5107c478bd9Sstevel@tonic-gate 			if (!from)
5117c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5127c478bd9Sstevel@tonic-gate 				    "internal error: %s has upset without "
5137c478bd9Sstevel@tonic-gate 				    "from flag",
5147c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5157c478bd9Sstevel@tonic-gate 			break;
5167c478bd9Sstevel@tonic-gate 		case N_DEFECT:
5177c478bd9Sstevel@tonic-gate 			lutp = Defects;
5187c478bd9Sstevel@tonic-gate 			if (to) {
5197c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5207c478bd9Sstevel@tonic-gate 				    "%s has defect on right side of \"->\"",
5217c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5227c478bd9Sstevel@tonic-gate 				return;
5237c478bd9Sstevel@tonic-gate 			}
5247c478bd9Sstevel@tonic-gate 			if (!from) {
5257c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5267c478bd9Sstevel@tonic-gate 				    "internal error: %s has defect without "
5277c478bd9Sstevel@tonic-gate 				    "from flag",
5287c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5297c478bd9Sstevel@tonic-gate 			}
5307c478bd9Sstevel@tonic-gate 			break;
5317c478bd9Sstevel@tonic-gate 		case N_ERROR:
5327c478bd9Sstevel@tonic-gate 			lutp = Errors;
5337c478bd9Sstevel@tonic-gate 			if (!from && !to)
5347c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5357c478bd9Sstevel@tonic-gate 				    "%s has error without from or to flags",
5367c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5377c478bd9Sstevel@tonic-gate 			break;
5387c478bd9Sstevel@tonic-gate 		case N_EREPORT:
5397c478bd9Sstevel@tonic-gate 			lutp = Ereports;
5407c478bd9Sstevel@tonic-gate 			if (from) {
5417c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
5427c478bd9Sstevel@tonic-gate 				    "%s has report on left side of \"->\"",
5437c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5447c478bd9Sstevel@tonic-gate 				return;
5457c478bd9Sstevel@tonic-gate 			}
5467c478bd9Sstevel@tonic-gate 			if (!to)
5477c478bd9Sstevel@tonic-gate 				outfl(O_DIE, np->file, np->line,
5487c478bd9Sstevel@tonic-gate 				    "internal error: %s has report without "
5497c478bd9Sstevel@tonic-gate 				    "to flag",
5507c478bd9Sstevel@tonic-gate 				    ptree_nodetype2str(t));
5517c478bd9Sstevel@tonic-gate 			break;
5527c478bd9Sstevel@tonic-gate 		default:
5537c478bd9Sstevel@tonic-gate 			outfl(O_DIE, np->file, np->line,
5547c478bd9Sstevel@tonic-gate 			    "internal error: check_propnames: "
5557c478bd9Sstevel@tonic-gate 			    "unexpected type: %d", np->u.name.t);
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		if ((dnp = tree_event2np_lut_lookup(lutp, np)) == NULL) {
5597c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
5607c478bd9Sstevel@tonic-gate 			    "%s statement contains undeclared event",
5617c478bd9Sstevel@tonic-gate 			    ptree_nodetype2str(t));
5627c478bd9Sstevel@tonic-gate 		} else
5637c478bd9Sstevel@tonic-gate 			dnp->u.stmt.flags |= STMT_REF;
5647c478bd9Sstevel@tonic-gate 		np->u.event.declp = dnp;
5657c478bd9Sstevel@tonic-gate 	} else if (np->t == T_LIST) {
5667c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.expr.left, from, to);
5677c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.expr.right, from, to);
5687c478bd9Sstevel@tonic-gate 	} else if (np->t == T_ARROW) {
5697c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.lhs, 1, to);
5707c478bd9Sstevel@tonic-gate 		check_propnames(t, np->u.arrow.rhs, from, 1);
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate static struct lut *
5757c478bd9Sstevel@tonic-gate record_iterators(struct node *np, struct lut *ex)
5767c478bd9Sstevel@tonic-gate {
5777c478bd9Sstevel@tonic-gate 	if (np == NULL)
5787c478bd9Sstevel@tonic-gate 		return (ex);
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	switch (np->t) {
5817c478bd9Sstevel@tonic-gate 	case T_ARROW:
5827c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.lhs, ex);
5837c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.arrow.rhs, ex);
5847c478bd9Sstevel@tonic-gate 		break;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	case T_LIST:
5877c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.left, ex);
5887c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.expr.right, ex);
5897c478bd9Sstevel@tonic-gate 		break;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	case T_EVENT:
5927c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.event.epname, ex);
5937c478bd9Sstevel@tonic-gate 		break;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	case T_NAME:
5967c478bd9Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME)
5977c478bd9Sstevel@tonic-gate 			ex = lut_add(ex, (void *) np->u.name.child->u.name.s,
5987c478bd9Sstevel@tonic-gate 			    (void *) np, NULL);
5997c478bd9Sstevel@tonic-gate 		ex = record_iterators(np->u.name.next, ex);
6007c478bd9Sstevel@tonic-gate 		break;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	default:
6037c478bd9Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6047c478bd9Sstevel@tonic-gate 		    "record_iterators: internal error: unexpected type: %s",
6057c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	return (ex);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate void
6127c478bd9Sstevel@tonic-gate check_exprscope(struct node *np, struct lut *ex)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	if (np == NULL)
6157c478bd9Sstevel@tonic-gate 		return;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	switch (np->t) {
6187c478bd9Sstevel@tonic-gate 	case T_EVENT:
6197c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.event.eexprlist, ex);
6207c478bd9Sstevel@tonic-gate 		break;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	case T_ARROW:
6237c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.arrow.lhs, ex);
6247c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.arrow.rhs, ex);
6257c478bd9Sstevel@tonic-gate 		break;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	case T_NAME:
6287c478bd9Sstevel@tonic-gate 		if (np->u.name.child && np->u.name.child->t == T_NAME) {
6297c478bd9Sstevel@tonic-gate 			if (lut_lookup(ex,
6307c478bd9Sstevel@tonic-gate 					(void *) np->u.name.child->u.name.s,
6317c478bd9Sstevel@tonic-gate 					NULL) == NULL)
6327c478bd9Sstevel@tonic-gate 				outfl(O_ERR, np->file, np->line,
6337c478bd9Sstevel@tonic-gate 					"constraint contains undefined"
6347c478bd9Sstevel@tonic-gate 					" iterator: %s",
6357c478bd9Sstevel@tonic-gate 					np->u.name.child->u.name.s);
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.name.next, ex);
6387c478bd9Sstevel@tonic-gate 		break;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	case T_QUOTE:
6417c478bd9Sstevel@tonic-gate 	case T_GLOBID:
6427c478bd9Sstevel@tonic-gate 		break;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	case T_ASSIGN:
6457c478bd9Sstevel@tonic-gate 	case T_NE:
6467c478bd9Sstevel@tonic-gate 	case T_EQ:
6477c478bd9Sstevel@tonic-gate 	case T_LIST:
6487c478bd9Sstevel@tonic-gate 	case T_AND:
6497c478bd9Sstevel@tonic-gate 	case T_OR:
6507c478bd9Sstevel@tonic-gate 	case T_NOT:
6517c478bd9Sstevel@tonic-gate 	case T_ADD:
6527c478bd9Sstevel@tonic-gate 	case T_SUB:
6537c478bd9Sstevel@tonic-gate 	case T_MUL:
6547c478bd9Sstevel@tonic-gate 	case T_DIV:
6557c478bd9Sstevel@tonic-gate 	case T_MOD:
6567c478bd9Sstevel@tonic-gate 	case T_LT:
6577c478bd9Sstevel@tonic-gate 	case T_LE:
6587c478bd9Sstevel@tonic-gate 	case T_GT:
6597c478bd9Sstevel@tonic-gate 	case T_GE:
6607c478bd9Sstevel@tonic-gate 	case T_BITAND:
6617c478bd9Sstevel@tonic-gate 	case T_BITOR:
6627c478bd9Sstevel@tonic-gate 	case T_BITXOR:
6637c478bd9Sstevel@tonic-gate 	case T_BITNOT:
6647c478bd9Sstevel@tonic-gate 	case T_LSHIFT:
6657c478bd9Sstevel@tonic-gate 	case T_RSHIFT:
6667c478bd9Sstevel@tonic-gate 	case T_CONDIF:
6677c478bd9Sstevel@tonic-gate 	case T_CONDELSE:
6687c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.expr.left, ex);
6697c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.expr.right, ex);
6707c478bd9Sstevel@tonic-gate 		break;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	case T_FUNC:
6737c478bd9Sstevel@tonic-gate 		check_exprscope(np->u.func.arglist, ex);
6747c478bd9Sstevel@tonic-gate 		break;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	case T_NUM:
6777c478bd9Sstevel@tonic-gate 	case T_TIMEVAL:
6787c478bd9Sstevel@tonic-gate 		break;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	default:
6817c478bd9Sstevel@tonic-gate 		outfl(O_DIE, np->file, np->line,
6827c478bd9Sstevel@tonic-gate 		    "check_exprscope: internal error: unexpected type: %s",
6837c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(np->t));
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate  * check_propscope -- check constraints for out of scope variable refs
6897c478bd9Sstevel@tonic-gate  */
6907c478bd9Sstevel@tonic-gate void
6917c478bd9Sstevel@tonic-gate check_propscope(struct node *np)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	struct lut *ex;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	ex = record_iterators(np, NULL);
6967c478bd9Sstevel@tonic-gate 	check_exprscope(np, ex);
6977c478bd9Sstevel@tonic-gate 	lut_free(ex, NULL, NULL);
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate /*
7017c478bd9Sstevel@tonic-gate  * check_upset_engine -- validate the engine property in an upset statement
7027c478bd9Sstevel@tonic-gate  *
7037c478bd9Sstevel@tonic-gate  * we do this after the full parse tree has been constructed rather than while
7047c478bd9Sstevel@tonic-gate  * building the parse tree because it is inconvenient for the user if we
7057c478bd9Sstevel@tonic-gate  * require SERD engines to be declared before used in an upset "engine"
7067c478bd9Sstevel@tonic-gate  * property.
7077c478bd9Sstevel@tonic-gate  */
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7107c478bd9Sstevel@tonic-gate void
7117c478bd9Sstevel@tonic-gate check_upset_engine(struct node *lhs, struct node *rhs, void *arg)
7127c478bd9Sstevel@tonic-gate {
7137c478bd9Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7147c478bd9Sstevel@tonic-gate 	struct node *engnp;
7157c478bd9Sstevel@tonic-gate 	struct node *declp;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	if ((engnp = tree_s2np_lut_lookup(rhs->u.stmt.lutp, L_engine)) == NULL)
7207c478bd9Sstevel@tonic-gate 		return;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	ASSERT(engnp->t == T_EVENT);
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	if ((declp = tree_event2np_lut_lookup(SERDs, engnp)) == NULL) {
7257c478bd9Sstevel@tonic-gate 		outfl(O_ERR, engnp->file, engnp->line,
7267c478bd9Sstevel@tonic-gate 		    "%s %s property contains undeclared name",
7277c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(t), L_engine);
7287c478bd9Sstevel@tonic-gate 		return;
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 	engnp->u.event.declp = declp;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate  * check_refcount -- see if declared names are used
7357c478bd9Sstevel@tonic-gate  *
7367c478bd9Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, so a refcount
7377c478bd9Sstevel@tonic-gate  * of zero means the name has been declared but otherwise not used.
7387c478bd9Sstevel@tonic-gate  */
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate void
7417c478bd9Sstevel@tonic-gate check_refcount(struct node *lhs, struct node *rhs, void *arg)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_REF)
7487c478bd9Sstevel@tonic-gate 		return;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	outfl(O_WARN|O_NONL, rhs->file, rhs->line,
7517c478bd9Sstevel@tonic-gate 	    "%s name declared but not used: ", ptree_nodetype2str(t));
7527c478bd9Sstevel@tonic-gate 	ptree_name(O_WARN|O_NONL, lhs);
7537c478bd9Sstevel@tonic-gate 	out(O_WARN, NULL);
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate /*
7577c478bd9Sstevel@tonic-gate  * set check_cycle_warninglevel only for val >= 0
7587c478bd9Sstevel@tonic-gate  */
7597c478bd9Sstevel@tonic-gate int
7607c478bd9Sstevel@tonic-gate check_cycle_level(long long val)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	static int check_cycle_warninglevel = -1;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	if (val == 0)
7657c478bd9Sstevel@tonic-gate 		check_cycle_warninglevel = 0;
7667c478bd9Sstevel@tonic-gate 	else if (val > 0)
7677c478bd9Sstevel@tonic-gate 		check_cycle_warninglevel = 1;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	return (check_cycle_warninglevel);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate /*
7737c478bd9Sstevel@tonic-gate  * check_cycle -- see props from an error have cycles
7747c478bd9Sstevel@tonic-gate  *
7757c478bd9Sstevel@tonic-gate  * this is run after the entire parse tree is constructed, for
7767c478bd9Sstevel@tonic-gate  * each error that has been declared.
7777c478bd9Sstevel@tonic-gate  */
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7807c478bd9Sstevel@tonic-gate void
7817c478bd9Sstevel@tonic-gate check_cycle(struct node *lhs, struct node *rhs, void *arg)
7827c478bd9Sstevel@tonic-gate {
7837c478bd9Sstevel@tonic-gate 	struct node *np;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	ASSERTeq(rhs->t, T_ERROR, ptree_nodetype2str);
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYCLE)
7887c478bd9Sstevel@tonic-gate 		return;		/* already reported this cycle */
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	if (rhs->u.stmt.flags & STMT_CYMARK) {
7917c478bd9Sstevel@tonic-gate #ifdef ESC
7927c478bd9Sstevel@tonic-gate 		int warninglevel;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 		warninglevel = check_cycle_level(-1);
7957c478bd9Sstevel@tonic-gate 		if (warninglevel <= 0) {
7967c478bd9Sstevel@tonic-gate 			int olevel = O_ERR;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 			if (warninglevel == 0)
7997c478bd9Sstevel@tonic-gate 				olevel = O_WARN;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 			out(olevel|O_NONL, "cycle in propagation tree: ");
8027c478bd9Sstevel@tonic-gate 			ptree_name(olevel|O_NONL, rhs->u.stmt.np);
8037c478bd9Sstevel@tonic-gate 			out(olevel, NULL);
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate #endif /* ESC */
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 		rhs->u.stmt.flags |= STMT_CYCLE;
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	rhs->u.stmt.flags |= STMT_CYMARK;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/* for each propagation */
8137c478bd9Sstevel@tonic-gate 	for (np = Props; np; np = np->u.stmt.next)
8147c478bd9Sstevel@tonic-gate 		check_cycle_lhs(rhs, np->u.stmt.np);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	rhs->u.stmt.flags &= ~STMT_CYMARK;
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate /*
8207c478bd9Sstevel@tonic-gate  * check_cycle_lhs -- find the lhs of an arrow for cycle checking
8217c478bd9Sstevel@tonic-gate  */
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static void
8247c478bd9Sstevel@tonic-gate check_cycle_lhs(struct node *stmtnp, struct node *arrow)
8257c478bd9Sstevel@tonic-gate {
8267c478bd9Sstevel@tonic-gate 	struct node *trylhs;
8277c478bd9Sstevel@tonic-gate 	struct node *tryrhs;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	/* handle cascaded arrows */
8307c478bd9Sstevel@tonic-gate 	switch (arrow->u.arrow.lhs->t) {
8317c478bd9Sstevel@tonic-gate 	case T_ARROW:
8327c478bd9Sstevel@tonic-gate 		/* first recurse left */
8337c478bd9Sstevel@tonic-gate 		check_cycle_lhs(stmtnp, arrow->u.arrow.lhs);
8347c478bd9Sstevel@tonic-gate 
835f358d892Srw145199 		/*
836f358d892Srw145199 		 * return if there's a list of events internal to
837f358d892Srw145199 		 * cascaded props (which is not allowed)
838f358d892Srw145199 		 */
839f358d892Srw145199 		if (arrow->u.arrow.lhs->u.arrow.rhs->t != T_EVENT)
840f358d892Srw145199 			return;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 		/* then try this arrow (thing cascaded *to*) */
8437c478bd9Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs->u.arrow.rhs;
8447c478bd9Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8457c478bd9Sstevel@tonic-gate 		break;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	case T_EVENT:
8487c478bd9Sstevel@tonic-gate 	case T_LIST:
8497c478bd9Sstevel@tonic-gate 		trylhs = arrow->u.arrow.lhs;
8507c478bd9Sstevel@tonic-gate 		tryrhs = arrow->u.arrow.rhs;
8517c478bd9Sstevel@tonic-gate 		break;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	default:
8547c478bd9Sstevel@tonic-gate 		out(O_DIE, "lhs: unexpected type: %s",
8557c478bd9Sstevel@tonic-gate 		    ptree_nodetype2str(arrow->u.arrow.lhs->t));
8567c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	check_cycle_lhs_try(stmtnp, trylhs, tryrhs);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate  * check_cycle_lhs_try -- try matching an event name on lhs of an arrow
8647c478bd9Sstevel@tonic-gate  */
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate static void
8677c478bd9Sstevel@tonic-gate check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, struct node *rhs)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	if (lhs->t == T_LIST) {
8707c478bd9Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.left, rhs);
8717c478bd9Sstevel@tonic-gate 		check_cycle_lhs_try(stmtnp, lhs->u.expr.right, rhs);
8727c478bd9Sstevel@tonic-gate 		return;
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	ASSERT(lhs->t == T_EVENT);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	if (tree_eventcmp(stmtnp->u.stmt.np, lhs) != 0)
8787c478bd9Sstevel@tonic-gate 		return;		/* no match */
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	check_cycle_rhs(rhs);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate  * check_cycle_rhs -- foreach error on rhs, see if we cycle to a marked error
8857c478bd9Sstevel@tonic-gate  */
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate static void
8887c478bd9Sstevel@tonic-gate check_cycle_rhs(struct node *rhs)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	struct node *dnp;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	if (rhs->t == T_LIST) {
8937c478bd9Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.left);
8947c478bd9Sstevel@tonic-gate 		check_cycle_rhs(rhs->u.expr.right);
8957c478bd9Sstevel@tonic-gate 		return;
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	ASSERT(rhs->t == T_EVENT);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	if (rhs->u.event.ename->u.name.t != N_ERROR)
9017c478bd9Sstevel@tonic-gate 		return;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	if ((dnp = tree_event2np_lut_lookup(Errors, rhs)) == NULL) {
9047c478bd9Sstevel@tonic-gate 		outfl(O_ERR|O_NONL,
9057c478bd9Sstevel@tonic-gate 		    rhs->file, rhs->line,
9067c478bd9Sstevel@tonic-gate 		    "unexpected undeclared event during cycle check");
9077c478bd9Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, rhs);
9087c478bd9Sstevel@tonic-gate 		out(O_ERR, NULL);
9097c478bd9Sstevel@tonic-gate 		return;
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 	check_cycle(NULL, dnp, 0);
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate /*
9157c478bd9Sstevel@tonic-gate  * Force iterators to be simple names, expressions, or numbers
9167c478bd9Sstevel@tonic-gate  */
9177c478bd9Sstevel@tonic-gate void
9187c478bd9Sstevel@tonic-gate check_name_iterator(struct node *np)
9197c478bd9Sstevel@tonic-gate {
9207c478bd9Sstevel@tonic-gate 	if (np->u.name.child->t != T_NUM &&
9217c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_NAME &&
9227c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_CONDIF &&
9237c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_SUB &&
9247c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_ADD &&
9257c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_MUL &&
9267c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_DIV &&
9277c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_MOD &&
9287c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_LSHIFT &&
9297c478bd9Sstevel@tonic-gate 	    np->u.name.child->t != T_RSHIFT) {
9307c478bd9Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
9317c478bd9Sstevel@tonic-gate 		"invalid iterator: ");
9327c478bd9Sstevel@tonic-gate 		ptree_name_iter(O_ERR|O_NONL, np);
9337c478bd9Sstevel@tonic-gate 		out(O_ERR, NULL);
9347c478bd9Sstevel@tonic-gate 	}
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate /*
9387c478bd9Sstevel@tonic-gate  * Iterators on a declaration may only be implicit
9397c478bd9Sstevel@tonic-gate  */
9407c478bd9Sstevel@tonic-gate void
9417c478bd9Sstevel@tonic-gate check_type_iterator(struct node *np)
9427c478bd9Sstevel@tonic-gate {
9437c478bd9Sstevel@tonic-gate 	while (np != NULL) {
9447c478bd9Sstevel@tonic-gate 		if (np->t == T_EVENT) {
9457c478bd9Sstevel@tonic-gate 			np = np->u.event.epname;
9467c478bd9Sstevel@tonic-gate 		} else if (np->t == T_NAME) {
9477c478bd9Sstevel@tonic-gate 			if (np->u.name.child != NULL &&
9487c478bd9Sstevel@tonic-gate 			    np->u.name.child->t != T_NUM) {
9497c478bd9Sstevel@tonic-gate 				outfl(O_ERR|O_NONL, np->file, np->line,
9507c478bd9Sstevel@tonic-gate 				    "explicit iterators disallowed "
9517c478bd9Sstevel@tonic-gate 				    "in declarations: ");
9527c478bd9Sstevel@tonic-gate 				ptree_name_iter(O_ERR|O_NONL, np);
9537c478bd9Sstevel@tonic-gate 				out(O_ERR, NULL);
9547c478bd9Sstevel@tonic-gate 			}
9557c478bd9Sstevel@tonic-gate 			np = np->u.name.next;
9567c478bd9Sstevel@tonic-gate 		} else {
9577c478bd9Sstevel@tonic-gate 			break;
9587c478bd9Sstevel@tonic-gate 		}
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate void
9637c478bd9Sstevel@tonic-gate check_func(struct node *np)
9647c478bd9Sstevel@tonic-gate {
9657c478bd9Sstevel@tonic-gate 	ASSERTinfo(np->t == T_FUNC, ptree_nodetype2str(np->t));
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	if (np->u.func.s == L_within) {
9687c478bd9Sstevel@tonic-gate 		struct node *arglist = np->u.func.arglist;
9697c478bd9Sstevel@tonic-gate 		switch (arglist->t) {
9707c478bd9Sstevel@tonic-gate 			case T_NUM:
9717c478bd9Sstevel@tonic-gate 				if (arglist->u.ull != 0ULL)
9727c478bd9Sstevel@tonic-gate 				    outfl(O_ERR, arglist->file, arglist->line,
9737c478bd9Sstevel@tonic-gate 					"parameter of within must be 0"
9747c478bd9Sstevel@tonic-gate 					", \"infinity\" or a time value.");
9757c478bd9Sstevel@tonic-gate 				break;
9767c478bd9Sstevel@tonic-gate 			case T_NAME:
9777c478bd9Sstevel@tonic-gate 				if (arglist->u.name.s != L_infinity)
9787c478bd9Sstevel@tonic-gate 				    outfl(O_ERR, arglist->file, arglist->line,
9797c478bd9Sstevel@tonic-gate 					"parameter of within must be 0"
9807c478bd9Sstevel@tonic-gate 					", \"infinity\" or a time value.");
9817c478bd9Sstevel@tonic-gate 				break;
9827c478bd9Sstevel@tonic-gate 			case T_LIST:
9837c478bd9Sstevel@tonic-gate 				/*
9847c478bd9Sstevel@tonic-gate 				 * if two parameters, the left or min must be
9857c478bd9Sstevel@tonic-gate 				 * either T_NUM or T_TIMEVAL
9867c478bd9Sstevel@tonic-gate 				 */
9877c478bd9Sstevel@tonic-gate 				if (arglist->u.expr.left->t != T_NUM &&
9887c478bd9Sstevel@tonic-gate 				    arglist->u.expr.left->t != T_TIMEVAL)
9897c478bd9Sstevel@tonic-gate 					outfl(O_ERR,
9907c478bd9Sstevel@tonic-gate 					    arglist->file, arglist->line,
9917c478bd9Sstevel@tonic-gate 					    "first parameter of within must be"
9927c478bd9Sstevel@tonic-gate 					    " either a time value or zero.");
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 				/*
9957c478bd9Sstevel@tonic-gate 				 * if two parameters, the right or max must
9967c478bd9Sstevel@tonic-gate 				 * be either T_NUM, T_NAME or T_TIMEVAL
9977c478bd9Sstevel@tonic-gate 				 */
9987c478bd9Sstevel@tonic-gate 				if (arglist->u.expr.right->t != T_NUM &&
9997c478bd9Sstevel@tonic-gate 				    arglist->u.expr.right->t != T_TIMEVAL &&
10007c478bd9Sstevel@tonic-gate 				    arglist->u.expr.right->t != T_NAME)
10017c478bd9Sstevel@tonic-gate 					outfl(O_ERR,
10027c478bd9Sstevel@tonic-gate 					    arglist->file, arglist->line,
10037c478bd9Sstevel@tonic-gate 					    "second parameter of within must "
10047c478bd9Sstevel@tonic-gate 					    "be 0, \"infinity\" "
10057c478bd9Sstevel@tonic-gate 					    "or time value.");
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 				/*
10087c478bd9Sstevel@tonic-gate 				 * if right or left is a T_NUM it must
10097c478bd9Sstevel@tonic-gate 				 * be zero
10107c478bd9Sstevel@tonic-gate 				 */
10117c478bd9Sstevel@tonic-gate 				if (arglist->u.expr.left->t == T_NUM)
10127c478bd9Sstevel@tonic-gate 					if (arglist->u.expr.left->u.ull != 0ULL)
10137c478bd9Sstevel@tonic-gate 					    outfl(O_ERR,
10147c478bd9Sstevel@tonic-gate 						arglist->file, arglist->line,
10157c478bd9Sstevel@tonic-gate 						"within parameter must be 0 or"
10167c478bd9Sstevel@tonic-gate 						" a time value.");
10177c478bd9Sstevel@tonic-gate 				if (arglist->u.expr.right->t == T_NUM)
10187c478bd9Sstevel@tonic-gate 					if (arglist->u.expr.right->u.ull
10197c478bd9Sstevel@tonic-gate 					    != 0ULL)
10207c478bd9Sstevel@tonic-gate 					    outfl(O_ERR,
10217c478bd9Sstevel@tonic-gate 						arglist->file, arglist->line,
10227c478bd9Sstevel@tonic-gate 						"within parameter must be 0 or"
10237c478bd9Sstevel@tonic-gate 						" a time value.");
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 				/* if right is a T_NAME it must be "infinity" */
10267c478bd9Sstevel@tonic-gate 				if (arglist->u.expr.right->t == T_NAME)
10277c478bd9Sstevel@tonic-gate 					if (arglist->u.expr.right->u.name.s
10287c478bd9Sstevel@tonic-gate 					    != L_infinity)
10297c478bd9Sstevel@tonic-gate 					    outfl(O_ERR,
10307c478bd9Sstevel@tonic-gate 						arglist->file, arglist->line,
10317c478bd9Sstevel@tonic-gate 						"\"infinity\" is the only valid"
10327c478bd9Sstevel@tonic-gate 						" name for within parameter.");
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 				/*
10357c478bd9Sstevel@tonic-gate 				 * the first parameter [min] must not be greater
10367c478bd9Sstevel@tonic-gate 				 * than the second parameter [max].
10377c478bd9Sstevel@tonic-gate 				 */
10387c478bd9Sstevel@tonic-gate 				if (arglist->u.expr.left->u.ull >
10397c478bd9Sstevel@tonic-gate 				    arglist->u.expr.right->u.ull)
10407c478bd9Sstevel@tonic-gate 					outfl(O_ERR,
10417c478bd9Sstevel@tonic-gate 					    arglist->file, arglist->line,
10427c478bd9Sstevel@tonic-gate 					    "the first value (min) of"
10437c478bd9Sstevel@tonic-gate 					    " within must be less than"
10447c478bd9Sstevel@tonic-gate 					    " the second (max) value");
10457c478bd9Sstevel@tonic-gate 				break;
10467c478bd9Sstevel@tonic-gate 			case T_TIMEVAL:
10477c478bd9Sstevel@tonic-gate 				break; /* no restrictions on T_TIMEVAL */
10487c478bd9Sstevel@tonic-gate 			default:
10497c478bd9Sstevel@tonic-gate 				outfl(O_ERR, arglist->file, arglist->line,
10507c478bd9Sstevel@tonic-gate 					"parameter of within must be 0"
10517c478bd9Sstevel@tonic-gate 					", \"infinity\" or a time value.");
10527c478bd9Sstevel@tonic-gate 		}
10537c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_call) {
10547c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_QUOTE &&
10557c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->t != T_LIST &&
10567c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->t != T_GLOBID &&
10577c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->t != T_CONDIF &&
10587c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->t != T_LIST &&
10597c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->t != T_FUNC)
10607c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10617c478bd9Sstevel@tonic-gate 				np->u.func.arglist->line,
10627c478bd9Sstevel@tonic-gate 				"invalid first argument to call()");
10637c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_fru) {
10647c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_NAME)
10657c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10667c478bd9Sstevel@tonic-gate 				np->u.func.arglist->line,
10677c478bd9Sstevel@tonic-gate 				"argument to fru() must be a path");
10687c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_asru) {
10697c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_NAME)
10707c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10717c478bd9Sstevel@tonic-gate 				np->u.func.arglist->line,
10727c478bd9Sstevel@tonic-gate 				"argument to asru() must be a path");
10737c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_connected ||
10747c478bd9Sstevel@tonic-gate 	    np->u.func.s == L_is_under) {
10757c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_LIST &&
10767c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->t == T_NAME ||
10777c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->t == T_FUNC &&
10787c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->u.func.s == L_fru ||
10797c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.left->u.func.s == L_asru))) &&
10807c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.right->t == T_NAME ||
10817c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.right->t == T_FUNC &&
10827c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.right->u.func.s == L_fru ||
10837c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.right->u.func.s == L_asru)))) {
10847c478bd9Sstevel@tonic-gate 			if (np->u.func.arglist->u.expr.left->t == T_FUNC)
10857c478bd9Sstevel@tonic-gate 				check_func(np->u.func.arglist->u.expr.left);
10867c478bd9Sstevel@tonic-gate 			if (np->u.func.arglist->u.expr.right->t == T_FUNC)
10877c478bd9Sstevel@tonic-gate 				check_func(np->u.func.arglist->u.expr.right);
10887c478bd9Sstevel@tonic-gate 		} else {
10897c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
10907c478bd9Sstevel@tonic-gate 			    np->u.func.arglist->line,
10917c478bd9Sstevel@tonic-gate 			    "%s() must have paths or calls to "
10927c478bd9Sstevel@tonic-gate 			    "fru() and/or asru() as arguments",
10937c478bd9Sstevel@tonic-gate 			    np->u.func.s);
10947c478bd9Sstevel@tonic-gate 		}
10957c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_on) {
10967c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_FUNC &&
10977c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.func.s == L_fru ||
10987c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->u.func.s == L_asru)) {
10997c478bd9Sstevel@tonic-gate 			check_func(np->u.func.arglist);
11007c478bd9Sstevel@tonic-gate 		} else {
11017c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11027c478bd9Sstevel@tonic-gate 			    np->u.func.arglist->line,
11037c478bd9Sstevel@tonic-gate 			    "argument to is_on() must be a call to "
11047c478bd9Sstevel@tonic-gate 			    "fru() or asru()");
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_present) {
11077c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_FUNC &&
11087c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.func.s == L_fru ||
11097c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->u.func.s == L_asru)) {
11107c478bd9Sstevel@tonic-gate 			check_func(np->u.func.arglist);
11117c478bd9Sstevel@tonic-gate 		} else {
11127c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11137c478bd9Sstevel@tonic-gate 			    np->u.func.arglist->line,
11147c478bd9Sstevel@tonic-gate 			    "argument to is_present() must be a call to "
11157c478bd9Sstevel@tonic-gate 			    "fru() or asru()");
11167c478bd9Sstevel@tonic-gate 		}
11177c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_is_type) {
11187c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_FUNC &&
11197c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.func.s == L_fru ||
11207c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->u.func.s == L_asru)) {
11217c478bd9Sstevel@tonic-gate 			check_func(np->u.func.arglist);
11227c478bd9Sstevel@tonic-gate 		} else {
11237c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11247c478bd9Sstevel@tonic-gate 			    np->u.func.arglist->line,
11257c478bd9Sstevel@tonic-gate 			    "argument to is_type() must be a call to "
11267c478bd9Sstevel@tonic-gate 			    "fru() or asru()");
11277c478bd9Sstevel@tonic-gate 		}
1128*7aec1d6eScindi 	} else if (np->u.func.s == L_confcall) {
1129*7aec1d6eScindi 		if (np->u.func.arglist->t != T_QUOTE &&
1130*7aec1d6eScindi 		    (np->u.func.arglist->t != T_LIST ||
1131*7aec1d6eScindi 		    np->u.func.arglist->u.expr.left->t != T_QUOTE))
1132*7aec1d6eScindi 			outfl(O_ERR, np->u.func.arglist->file,
1133*7aec1d6eScindi 			    np->u.func.arglist->line,
1134*7aec1d6eScindi 			    "confcall(): first argument must be a string "
1135*7aec1d6eScindi 			    "(the name of the operation)");
11367c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_confprop) {
11377c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t == T_LIST &&
11387c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->t == T_FUNC &&
11397c478bd9Sstevel@tonic-gate 		    (np->u.func.arglist->u.expr.left->u.func.s == L_fru ||
11407c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.left->u.func.s == L_asru)) &&
11417c478bd9Sstevel@tonic-gate 		    np->u.func.arglist->u.expr.right->t == T_QUOTE) {
11427c478bd9Sstevel@tonic-gate 			check_func(np->u.func.arglist->u.expr.left);
11437c478bd9Sstevel@tonic-gate 		} else {
11447c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11457c478bd9Sstevel@tonic-gate 			    np->u.func.arglist->line,
11467c478bd9Sstevel@tonic-gate 			    "confprop(): first argument must be a call to "
11477c478bd9Sstevel@tonic-gate 			    "fru() or asru(); "
11487c478bd9Sstevel@tonic-gate 			    "second argument must be a string");
11497c478bd9Sstevel@tonic-gate 		}
1150*7aec1d6eScindi 	} else if (np->u.func.s == L_count) {
1151*7aec1d6eScindi 		if (np->u.func.arglist->t != T_EVENT) {
1152*7aec1d6eScindi 			outfl(O_ERR, np->u.func.arglist->file,
1153*7aec1d6eScindi 			    np->u.func.arglist->line,
1154*7aec1d6eScindi 			    "count(): argument must be an engine name");
1155*7aec1d6eScindi 		}
1156*7aec1d6eScindi 	} else if (np->u.func.s == L_defined) {
1157*7aec1d6eScindi 		if (np->u.func.arglist->t != T_GLOBID)
1158*7aec1d6eScindi 			outfl(O_ERR, np->u.func.arglist->file,
1159*7aec1d6eScindi 				np->u.func.arglist->line,
1160*7aec1d6eScindi 				"argument to defined() must be a global");
11617c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_payloadprop) {
11627c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_QUOTE)
11637c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11647c478bd9Sstevel@tonic-gate 				np->u.func.arglist->line,
11657c478bd9Sstevel@tonic-gate 				"argument to payloadprop() must be a string");
1166*7aec1d6eScindi 	} else if (np->u.func.s == L_payloadprop_contains) {
1167*7aec1d6eScindi 		if (np->u.func.arglist->t != T_LIST ||
1168*7aec1d6eScindi 		    np->u.func.arglist->u.expr.left->t != T_QUOTE ||
1169*7aec1d6eScindi 		    np->u.func.arglist->u.expr.right == NULL)
1170*7aec1d6eScindi 			outfl(O_ERR, np->u.func.arglist->file,
1171*7aec1d6eScindi 			    np->u.func.arglist->line,
1172*7aec1d6eScindi 			    "args to payloadprop_contains(): must be a quoted "
1173*7aec1d6eScindi 			    "string (property name) and an expression "
1174*7aec1d6eScindi 			    "(to match)");
1175*7aec1d6eScindi 	} else if (np->u.func.s == L_payloadprop_defined) {
1176*7aec1d6eScindi 		if (np->u.func.arglist->t != T_QUOTE)
1177*7aec1d6eScindi 			outfl(O_ERR, np->u.func.arglist->file,
1178*7aec1d6eScindi 			    np->u.func.arglist->line,
1179*7aec1d6eScindi 			    "arg to payloadprop_defined(): must be a quoted "
1180*7aec1d6eScindi 			    "string");
1181*7aec1d6eScindi 	} else if (np->u.func.s == L_setpayloadprop) {
1182*7aec1d6eScindi 		if (np->u.func.arglist->t == T_LIST &&
1183*7aec1d6eScindi 		    np->u.func.arglist->u.expr.left->t == T_QUOTE) {
1184*7aec1d6eScindi 			if (np->u.func.arglist->u.expr.right->t == T_FUNC)
1185*7aec1d6eScindi 				check_func(np->u.func.arglist->u.expr.right);
1186*7aec1d6eScindi 		} else {
1187*7aec1d6eScindi 			outfl(O_ERR, np->u.func.arglist->file,
1188*7aec1d6eScindi 			    np->u.func.arglist->line,
1189*7aec1d6eScindi 			    "setpayloadprop(): "
1190*7aec1d6eScindi 			    "first arg must be a string, "
1191*7aec1d6eScindi 			    "second arg a value");
1192*7aec1d6eScindi 		}
11937c478bd9Sstevel@tonic-gate 	} else if (np->u.func.s == L_envprop) {
11947c478bd9Sstevel@tonic-gate 		if (np->u.func.arglist->t != T_QUOTE)
11957c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->u.func.arglist->file,
11967c478bd9Sstevel@tonic-gate 				np->u.func.arglist->line,
11977c478bd9Sstevel@tonic-gate 				"argument to envprop() must be a string");
11987c478bd9Sstevel@tonic-gate 	} else
11997c478bd9Sstevel@tonic-gate 		outfl(O_WARN, np->file, np->line,
12007c478bd9Sstevel@tonic-gate 			"possible platform-specific function: %s",
12017c478bd9Sstevel@tonic-gate 			np->u.func.s);
12027c478bd9Sstevel@tonic-gate }
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate void
12057c478bd9Sstevel@tonic-gate check_expr(struct node *np)
12067c478bd9Sstevel@tonic-gate {
12077c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	switch (np->t) {
12107c478bd9Sstevel@tonic-gate 	case T_ASSIGN:
12117c478bd9Sstevel@tonic-gate 		ASSERT(np->u.expr.left != NULL);
12127c478bd9Sstevel@tonic-gate 		if (np->u.expr.left->t != T_GLOBID)
12137c478bd9Sstevel@tonic-gate 			outfl(O_ERR, np->file, np->line,
12147c478bd9Sstevel@tonic-gate 			    "assignment only allowed to globals (e.g. $a)");
12157c478bd9Sstevel@tonic-gate 		break;
12167c478bd9Sstevel@tonic-gate 	}
12177c478bd9Sstevel@tonic-gate }
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate void
12207c478bd9Sstevel@tonic-gate check_event(struct node *np)
12217c478bd9Sstevel@tonic-gate {
12227c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
1223*7aec1d6eScindi 	ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	if (np->u.event.epname == NULL) {
12267c478bd9Sstevel@tonic-gate 		outfl(O_ERR|O_NONL, np->file, np->line,
12277c478bd9Sstevel@tonic-gate 		    "pathless events not allowed: ");
12287c478bd9Sstevel@tonic-gate 		ptree_name(O_ERR|O_NONL, np->u.event.ename);
12297c478bd9Sstevel@tonic-gate 		out(O_ERR, NULL);
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate /*
12347c478bd9Sstevel@tonic-gate  * check for properties that are required on declarations. This
12357c478bd9Sstevel@tonic-gate  * should be done after all declarations since they can be
12367c478bd9Sstevel@tonic-gate  * redeclared with a different set of properties.
12377c478bd9Sstevel@tonic-gate  */
12387c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12397c478bd9Sstevel@tonic-gate void
12407c478bd9Sstevel@tonic-gate check_required_props(struct node *lhs, struct node *rhs, void *arg)
12417c478bd9Sstevel@tonic-gate {
12427c478bd9Sstevel@tonic-gate 	enum nodetype t = (enum nodetype)arg;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	check_stmt_required_properties(rhs);
12477c478bd9Sstevel@tonic-gate }
1248f358d892Srw145199 
1249f358d892Srw145199 /*
1250f358d892Srw145199  * check that cascading prop statements do not contain lists internally.
1251f358d892Srw145199  * the first and last event lists in the cascading prop may be single
1252f358d892Srw145199  * events or lists of events.
1253f358d892Srw145199  */
1254f358d892Srw145199 /*ARGSUSED*/
1255f358d892Srw145199 void
1256f358d892Srw145199 check_proplists(enum nodetype t, struct node *np)
1257f358d892Srw145199 {
1258f358d892Srw145199 	ASSERT(np->t == T_ARROW);
1259f358d892Srw145199 	/*
1260f358d892Srw145199 	 * not checking the right hand side of the top level prop
1261f358d892Srw145199 	 * since it is the last part of the propagation and can be
1262f358d892Srw145199 	 * an event or list of events
1263f358d892Srw145199 	 */
1264f358d892Srw145199 	check_proplists_lhs(t, np->u.arrow.lhs);
1265f358d892Srw145199 }
1266f358d892Srw145199 
1267f358d892Srw145199 /*ARGSUSED*/
1268f358d892Srw145199 static void
1269f358d892Srw145199 check_proplists_lhs(enum nodetype t, struct node *lhs)
1270f358d892Srw145199 {
1271f358d892Srw145199 	if (lhs->t == T_ARROW) {
1272f358d892Srw145199 		if (lhs->u.arrow.rhs->t == T_LIST) {
1273f358d892Srw145199 			outfl(O_ERR, lhs->file, lhs->line,
1274f358d892Srw145199 				"lists are not allowed internally on"
1275f358d892Srw145199 				" cascading %s",
1276f358d892Srw145199 				(t == T_PROP) ? "propagations" : "masks");
1277f358d892Srw145199 		}
1278f358d892Srw145199 		check_proplists_lhs(t, lhs->u.arrow.lhs);
1279f358d892Srw145199 	}
1280f358d892Srw145199 }
1281