Home | History | Annotate | Download | only in common
      1      0    stevel /*
      2      0    stevel  * CDDL HEADER START
      3      0    stevel  *
      4      0    stevel  * The contents of this file are subject to the terms of the
      5   2869    gavinm  * Common Development and Distribution License (the "License").
      6   2869    gavinm  * You may not use this file except in compliance with the License.
      7      0    stevel  *
      8      0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0    stevel  * or http://www.opensolaris.org/os/licensing.
     10      0    stevel  * See the License for the specific language governing permissions
     11      0    stevel  * and limitations under the License.
     12      0    stevel  *
     13      0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0    stevel  *
     19      0    stevel  * CDDL HEADER END
     20      0    stevel  */
     21      0    stevel /*
     22  11202   Stephen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0    stevel  * Use is subject to license terms.
     24      0    stevel  *
     25      0    stevel  * check.c -- routines for checking the prop tree
     26      0    stevel  *
     27      0    stevel  * this module provides semantic checks on the parse tree.  most of
     28      0    stevel  * these checks happen during the construction of the parse tree,
     29      0    stevel  * when the various tree_X() routines call the various check_X()
     30      0    stevel  * routines.  in a couple of special cases, a check function will
     31      0    stevel  * process the parse tree after it has been fully constructed.  these
     32      0    stevel  * cases are noted in the comments above the check function.
     33      0    stevel  */
     34      0    stevel 
     35      0    stevel #include <stdio.h>
     36      0    stevel #include "out.h"
     37      0    stevel #include "stable.h"
     38      0    stevel #include "literals.h"
     39      0    stevel #include "lut.h"
     40      0    stevel #include "tree.h"
     41      0    stevel #include "ptree.h"
     42      0    stevel #include "check.h"
     43      0    stevel 
     44      0    stevel static int check_reportlist(enum nodetype t, const char *s, struct node *np);
     45      0    stevel static int check_num(enum nodetype t, const char *s, struct node *np);
     46      0    stevel static int check_quote(enum nodetype t, const char *s, struct node *np);
     47   1414     cindi static int check_action(enum nodetype t, const char *s, struct node *np);
     48      0    stevel static int check_num_func(enum nodetype t, const char *s, struct node *np);
     49      0    stevel static int check_fru_asru(enum nodetype t, const char *s, struct node *np);
     50      0    stevel static int check_engine(enum nodetype t, const char *s, struct node *np);
     51   1414     cindi static int check_count(enum nodetype t, const char *s, struct node *np);
     52      0    stevel static int check_timeval(enum nodetype t, const char *s, struct node *np);
     53      0    stevel static int check_id(enum nodetype t, const char *s, struct node *np);
     54      0    stevel static int check_serd_method(enum nodetype t, const char *s, struct node *np);
     55   1414     cindi static int check_serd_id(enum nodetype t, const char *s, struct node *np);
     56      0    stevel static int check_nork(struct node *np);
     57      0    stevel static void check_cycle_lhs(struct node *stmtnp, struct node *arrow);
     58      0    stevel static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs,
     59      0    stevel     struct node *rhs);
     60      0    stevel static void check_cycle_rhs(struct node *rhs);
     61    854  rw145199 static void check_proplists_lhs(enum nodetype t, struct node *lhs);
     62      0    stevel 
     63      0    stevel static struct {
     64      0    stevel 	enum nodetype t;
     65      0    stevel 	const char *name;
     66      0    stevel 	int required;
     67      0    stevel 	int (*checker)(enum nodetype t, const char *s, struct node *np);
     68      0    stevel 	int outflags;
     69      0    stevel } Allowednames[] = {
     70   7197    stephh 	{ T_FAULT, "FITrate", 0, check_num_func, O_ERR },
     71      0    stevel 	{ T_FAULT, "FRU", 0, check_fru_asru, O_ERR },
     72      0    stevel 	{ T_FAULT, "ASRU", 0, check_fru_asru, O_ERR },
     73   1414     cindi 	{ T_FAULT, "message", 0, check_num_func, O_ERR },
     74   7197    stephh 	{ T_FAULT, "retire", 0, check_num_func, O_ERR },
     75   7197    stephh 	{ T_FAULT, "response", 0, check_num_func, O_ERR },
     76   1414     cindi 	{ T_FAULT, "action", 0, check_action, O_ERR },
     77   1414     cindi 	{ T_FAULT, "count", 0, check_count, O_ERR },
     78   7197    stephh 	{ T_FAULT, "engine", 0, check_engine, O_ERR },
     79      0    stevel 	{ T_UPSET, "engine", 0, check_engine, O_ERR },
     80      0    stevel 	{ T_DEFECT, "FRU", 0, check_fru_asru, O_ERR },
     81      0    stevel 	{ T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR },
     82   7197    stephh 	{ T_DEFECT, "engine", 0, check_engine, O_ERR },
     83   8245   Stephen 	{ T_DEFECT, "FITrate", 0, check_num_func, O_ERR },
     84      0    stevel 	{ T_EREPORT, "poller", 0, check_id, O_ERR },
     85      0    stevel 	{ T_EREPORT, "delivery", 0, check_timeval, O_ERR },
     86   6640       cth 	{ T_EREPORT, "discard_if_config_unknown", 0, check_num, O_ERR },
     87      0    stevel 	{ T_SERD, "N", 1, check_num, O_ERR },
     88      0    stevel 	{ T_SERD, "T", 1, check_timeval, O_ERR },
     89   7197    stephh 	{ T_SERD, "method", 0, check_serd_method, O_ERR },
     90   7197    stephh 	{ T_SERD, "trip", 0, check_reportlist, O_ERR },
     91      0    stevel 	{ T_SERD, "FRU", 0, check_fru_asru, O_ERR },
     92   1414     cindi 	{ T_SERD, "id", 0, check_serd_id, O_ERR },
     93      0    stevel 	{ T_ERROR, "ASRU", 0, check_fru_asru, O_ERR },
     94      0    stevel 	{ T_CONFIG, NULL, 0, check_quote, O_ERR },
     95      0    stevel 	{ 0, NULL, 0 },
     96      0    stevel };
     97      0    stevel 
     98      0    stevel void
     99      0    stevel check_init(void)
    100      0    stevel {
    101      0    stevel 	int i;
    102      0    stevel 
    103      0    stevel 	for (i = 0; Allowednames[i].t; i++)
    104      0    stevel 		if (Allowednames[i].name != NULL)
    105      0    stevel 			Allowednames[i].name = stable(Allowednames[i].name);
    106      0    stevel }
    107      0    stevel 
    108      0    stevel void
    109      0    stevel check_fini(void)
    110      0    stevel {
    111      0    stevel }
    112      0    stevel 
    113      0    stevel /*ARGSUSED*/
    114      0    stevel void
    115      0    stevel check_report_combination(struct node *np)
    116      0    stevel {
    117      0    stevel 	/* nothing to check for here.  poller is only prop and it is optional */
    118      0    stevel }
    119      0    stevel 
    120      0    stevel /*
    121      0    stevel  * check_path_iterators -- verify all iterators are explicit
    122      0    stevel  */
    123      0    stevel static void
    124      0    stevel check_path_iterators(struct node *np)
    125      0    stevel {
    126      0    stevel 	if (np == NULL)
    127      0    stevel 		return;
    128      0    stevel 
    129      0    stevel 	switch (np->t) {
    130      0    stevel 		case T_ARROW:
    131      0    stevel 			check_path_iterators(np->u.arrow.lhs);
    132      0    stevel 			check_path_iterators(np->u.arrow.rhs);
    133      0    stevel 			break;
    134      0    stevel 
    135      0    stevel 		case T_LIST:
    136      0    stevel 			check_path_iterators(np->u.expr.left);
    137      0    stevel 			check_path_iterators(np->u.expr.right);
    138      0    stevel 			break;
    139      0    stevel 
    140      0    stevel 		case T_EVENT:
    141      0    stevel 			check_path_iterators(np->u.event.epname);
    142      0    stevel 			break;
    143      0    stevel 
    144      0    stevel 		case T_NAME:
    145      0    stevel 			if (np->u.name.child == NULL)
    146      0    stevel 				outfl(O_DIE, np->file, np->line,
    147      0    stevel 				    "internal error: check_path_iterators: "
    148      0    stevel 				    "unexpected implicit iterator: %s",
    149      0    stevel 				    np->u.name.s);
    150      0    stevel 			check_path_iterators(np->u.name.next);
    151      0    stevel 			break;
    152      0    stevel 
    153      0    stevel 		default:
    154      0    stevel 			outfl(O_DIE, np->file, np->line,
    155      0    stevel 			    "internal error: check_path_iterators: "
    156      0    stevel 			    "unexpected type: %s",
    157      0    stevel 			    ptree_nodetype2str(np->t));
    158      0    stevel 	}
    159      0    stevel }
    160      0    stevel 
    161      0    stevel void
    162      0    stevel check_arrow(struct node *np)
    163      0    stevel {
    164      0    stevel 	ASSERTinfo(np->t == T_ARROW, ptree_nodetype2str(np->t));
    165      0    stevel 
    166      0    stevel 	if (np->u.arrow.lhs->t != T_ARROW &&
    167      0    stevel 	    np->u.arrow.lhs->t != T_LIST &&
    168      0    stevel 	    np->u.arrow.lhs->t != T_EVENT) {
    169      0    stevel 		outfl(O_ERR,
    170      0    stevel 		    np->u.arrow.lhs->file, np->u.arrow.lhs->line,
    171      0    stevel 		    "%s not allowed on left-hand side of arrow",
    172      0    stevel 		    ptree_nodetype2str(np->u.arrow.lhs->t));
    173      0    stevel 	}
    174      0    stevel 
    175      0    stevel 	if (!check_nork(np->u.arrow.nnp) ||
    176   5633  cy152378 	    !check_nork(np->u.arrow.knp))
    177   5633  cy152378 		outfl(O_ERR, np->file, np->line,
    178   5633  cy152378 		    "counts associated with propagation arrows "
    179   5633  cy152378 		    "must be integers");
    180      0    stevel 
    181      0    stevel 	check_path_iterators(np);
    182      0    stevel }
    183      0    stevel 
    184      0    stevel /*
    185      0    stevel  * make sure the nork values are valid.
    186      0    stevel  * Nork values must be "A" for all(T_NAME),
    187      0    stevel  * a number(T_NUM), or a simple
    188      0    stevel  * expression(T_SUB, T_ADD, T_MUL, T_DIV)
    189      0    stevel  */
    190      0    stevel static int
    191      0    stevel check_nork(struct node *np)
    192      0    stevel {
    193      0    stevel 	int rval = 0;
    194      0    stevel 
    195      0    stevel 	/* NULL means no nork value which is allowed */
    196      0    stevel 	if (np == NULL) {
    197      0    stevel 		rval = 1;
    198      0    stevel 	}
    199      0    stevel 	else
    200      0    stevel 	{
    201      0    stevel 		/* if the nork is a name it must be A for "All" */
    202      0    stevel 		if (np->t == T_NAME)
    203      0    stevel 			if (*np->u.name.s == 'A')
    204      0    stevel 				return (1);
    205      0    stevel 
    206      0    stevel 		/*  T_NUM allowed */
    207      0    stevel 		if (np->t == T_NUM)
    208      0    stevel 			rval = 1;
    209      0    stevel 
    210      0    stevel 		/*  simple expressions allowed */
    211      0    stevel 		if (np->t == T_SUB ||
    212   5633  cy152378 		    np->t == T_ADD ||
    213   5633  cy152378 		    np->t == T_MUL ||
    214   5633  cy152378 		    np->t == T_DIV)
    215      0    stevel 			rval = 1;
    216      0    stevel 	}
    217      0    stevel 
    218      0    stevel 	return (rval);
    219      0    stevel }
    220      0    stevel 
    221      0    stevel static int
    222      0    stevel check_reportlist(enum nodetype t, const char *s, struct node *np)
    223      0    stevel {
    224      0    stevel 	if (np == NULL)
    225      0    stevel 		return (1);
    226      0    stevel 	else if (np->t == T_EVENT) {
    227      0    stevel 		if (np->u.event.ename->u.name.t != N_EREPORT) {
    228      0    stevel 			outfl(O_ERR, np->file, np->line,
    229      0    stevel 			    "%s %s property must begin with \"ereport.\"",
    230      0    stevel 			    ptree_nodetype2str(t), s);
    231      0    stevel 		} else if (tree_event2np_lut_lookup(Ereports, np) == NULL) {
    232      0    stevel 			outfl(O_ERR, np->file, np->line,
    233      0    stevel 			    "%s %s property contains undeclared name",
    234      0    stevel 			    ptree_nodetype2str(t), s);
    235      0    stevel 		}
    236      0    stevel 		check_type_iterator(np);
    237      0    stevel 	} else if (np->t == T_LIST) {
    238      0    stevel 		(void) check_reportlist(t, s, np->u.expr.left);
    239      0    stevel 		(void) check_reportlist(t, s, np->u.expr.right);
    240      0    stevel 	}
    241      0    stevel 	return (1);
    242      0    stevel }
    243      0    stevel 
    244      0    stevel static int
    245      0    stevel check_num(enum nodetype t, const char *s, struct node *np)
    246      0    stevel {
    247      0    stevel 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    248      0    stevel 	if (np->t != T_NUM)
    249      0    stevel 		outfl(O_ERR, np->file, np->line,
    250      0    stevel 		    "%s %s property must be a single number",
    251      0    stevel 		    ptree_nodetype2str(t), s);
    252      0    stevel 	return (1);
    253      0    stevel }
    254      0    stevel 
    255      0    stevel /*ARGSUSED1*/
    256      0    stevel static int
    257      0    stevel check_quote(enum nodetype t, const char *s, struct node *np)
    258      0    stevel {
    259      0    stevel 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    260      0    stevel 	if (np->t != T_QUOTE)
    261      0    stevel 		outfl(O_ERR, np->file, np->line,
    262      0    stevel 		    "%s properties must be quoted strings",
    263      0    stevel 		    ptree_nodetype2str(t));
    264      0    stevel 	return (1);
    265      0    stevel }
    266      0    stevel 
    267      0    stevel static int
    268   1414     cindi check_action(enum nodetype t, const char *s, struct node *np)
    269   1414     cindi {
    270   1414     cindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    271   1414     cindi 
    272   1414     cindi 	if (np->t != T_FUNC)
    273   1414     cindi 		outfl(O_ERR, np->file, np->line,
    274   1414     cindi 		    "%s %s property must be a function or list of functions",
    275   1414     cindi 		    ptree_nodetype2str(t), s);
    276   1414     cindi 	return (1);
    277   1414     cindi }
    278   1414     cindi 
    279   1414     cindi static int
    280      0    stevel check_num_func(enum nodetype t, const char *s, struct node *np)
    281      0    stevel {
    282      0    stevel 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    283      0    stevel 	if (np->t != T_NUM && np->t != T_FUNC)
    284      0    stevel 		outfl(O_ERR, np->file, np->line,
    285      0    stevel 		    "%s %s property must be a number or function",
    286      0    stevel 		    ptree_nodetype2str(t), s);
    287      0    stevel 	return (1);
    288      0    stevel }
    289      0    stevel 
    290      0    stevel static int
    291      0    stevel check_fru_asru(enum nodetype t, const char *s, struct node *np)
    292      0    stevel {
    293      0    stevel 	ASSERT(s != NULL);
    294      0    stevel 
    295      0    stevel 	/* make sure it is a node type T_NAME? */
    296      0    stevel 	if (np->t == T_NAME) {
    297   5633  cy152378 		if (s == L_ASRU) {
    298   5633  cy152378 			if (tree_name2np_lut_lookup_name(ASRUs, np) == NULL)
    299   5633  cy152378 				outfl(O_ERR, np->file, np->line,
    300   5633  cy152378 				    "ASRU property contains undeclared asru");
    301   5633  cy152378 		} else if (s == L_FRU) {
    302   5633  cy152378 			if (tree_name2np_lut_lookup_name(FRUs, np) == NULL)
    303   5633  cy152378 				outfl(O_ERR, np->file, np->line,
    304   5633  cy152378 				    "FRU property contains undeclared fru");
    305   5633  cy152378 		} else {
    306      0    stevel 			outfl(O_ERR, np->file, np->line,
    307   5633  cy152378 			    "illegal property name in %s declaration: %s",
    308   5633  cy152378 			    ptree_nodetype2str(t), s);
    309   5633  cy152378 		}
    310   5633  cy152378 		check_type_iterator(np);
    311      0    stevel 	} else
    312      0    stevel 		outfl(O_ERR, np->file, np->line,
    313      0    stevel 		    "illegal type used for %s property: %s",
    314      0    stevel 		    s, ptree_nodetype2str(np->t));
    315      0    stevel 	return (1);
    316      0    stevel }
    317      0    stevel 
    318      0    stevel static int
    319      0    stevel check_engine(enum nodetype t, const char *s, struct node *np)
    320      0    stevel {
    321      0    stevel 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    322      0    stevel 	if (np->t != T_EVENT)
    323      0    stevel 		outfl(O_ERR, np->file, np->line,
    324      0    stevel 		    "%s %s property must be an engine name "
    325      0    stevel 		    "(i.e. serd.x or serd.x@a/b)",
    326      0    stevel 		    ptree_nodetype2str(t), s);
    327      0    stevel 
    328      0    stevel 	return (1);
    329      0    stevel }
    330      0    stevel 
    331      0    stevel static int
    332   1414     cindi check_count(enum nodetype t, const char *s, struct node *np)
    333   1414     cindi {
    334   1414     cindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    335   1414     cindi 	if (np->t != T_EVENT)
    336   1414     cindi 		outfl(O_ERR, np->file, np->line,
    337   1414     cindi 		    "%s %s property must be an engine name "
    338   1414     cindi 		    "(i.e. stat.x or stat.x@a/b)",
    339   1414     cindi 		    ptree_nodetype2str(t), s);
    340   1414     cindi 
    341   1414     cindi 	/* XXX confirm engine has been declared */
    342   1414     cindi 	return (1);
    343   1414     cindi }
    344   1414     cindi 
    345   1414     cindi static int
    346      0    stevel check_timeval(enum nodetype t, const char *s, struct node *np)
    347      0    stevel {
    348      0    stevel 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    349      0    stevel 	if (np->t != T_TIMEVAL)
    350      0    stevel 		outfl(O_ERR, np->file, np->line,
    351      0    stevel 		    "%s %s property must be a number with time units",
    352      0    stevel 		    ptree_nodetype2str(t), s);
    353      0    stevel 	return (1);
    354      0    stevel }
    355      0    stevel 
    356      0    stevel static int
    357      0    stevel check_id(enum nodetype t, const char *s, struct node *np)
    358      0    stevel {
    359      0    stevel 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    360      0    stevel 	if (np->t != T_NAME || np->u.name.next || np->u.name.child)
    361      0    stevel 		outfl(O_ERR, np->file, np->line,
    362      0    stevel 		    "%s %s property must be simple name",
    363      0    stevel 		    ptree_nodetype2str(t), s);
    364      0    stevel 	return (1);
    365      0    stevel }
    366      0    stevel 
    367      0    stevel static int
    368      0    stevel check_serd_method(enum nodetype t, const char *s, struct node *np)
    369      0    stevel {
    370      0    stevel 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    371      0    stevel 	if (np->t != T_NAME || np->u.name.next || np->u.name.child ||
    372      0    stevel 	    (np->u.name.s != L_volatile &&
    373      0    stevel 	    np->u.name.s != L_persistent))
    374      0    stevel 		outfl(O_ERR, np->file, np->line,
    375      0    stevel 		    "%s %s property must be \"volatile\" or \"persistent\"",
    376   1414     cindi 		    ptree_nodetype2str(t), s);
    377   1414     cindi 	return (1);
    378   1414     cindi }
    379   1414     cindi 
    380   1414     cindi static int
    381   1414     cindi check_serd_id(enum nodetype t, const char *s, struct node *np)
    382   1414     cindi {
    383   1414     cindi 	ASSERTinfo(np != NULL, ptree_nodetype2str(t));
    384   1414     cindi 	if (np->t != T_GLOBID)
    385   1414     cindi 		outfl(O_ERR, np->file, np->line,
    386   1414     cindi 		    "%s %s property must be a global ID",
    387      0    stevel 		    ptree_nodetype2str(t), s);
    388      0    stevel 	return (1);
    389      0    stevel }
    390      0    stevel 
    391      0    stevel void
    392      0    stevel check_stmt_required_properties(struct node *stmtnp)
    393      0    stevel {
    394      0    stevel 	struct lut *lutp = stmtnp->u.stmt.lutp;
    395      0    stevel 	struct node *np = stmtnp->u.stmt.np;
    396      0    stevel 	int i;
    397      0    stevel 
    398      0    stevel 	for (i = 0; Allowednames[i].t; i++)
    399      0    stevel 		if (stmtnp->t == Allowednames[i].t &&
    400      0    stevel 		    Allowednames[i].required &&
    401      0    stevel 		    tree_s2np_lut_lookup(lutp, Allowednames[i].name) == NULL)
    402      0    stevel 			outfl(Allowednames[i].outflags,
    403      0    stevel 			    np->file, np->line,
    404      0    stevel 			    "%s statement missing property: %s",
    405      0    stevel 			    ptree_nodetype2str(stmtnp->t),
    406      0    stevel 			    Allowednames[i].name);
    407      0    stevel }
    408      0    stevel 
    409      0    stevel void
    410      0    stevel check_stmt_allowed_properties(enum nodetype t,
    411      0    stevel     struct node *nvpairnp, struct lut *lutp)
    412      0    stevel {
    413      0    stevel 	int i;
    414      0    stevel 	const char *s = nvpairnp->u.expr.left->u.name.s;
    415      0    stevel 	struct node *np;
    416      0    stevel 
    417      0    stevel 	for (i = 0; Allowednames[i].t; i++)
    418      0    stevel 		if (t == Allowednames[i].t && Allowednames[i].name == NULL) {
    419      0    stevel 			/* NULL name means just call checker */
    420      0    stevel 			(*Allowednames[i].checker)(t, s,
    421      0    stevel 			    nvpairnp->u.expr.right);
    422      0    stevel 			return;
    423      0    stevel 		} else if (t == Allowednames[i].t && s == Allowednames[i].name)
    424      0    stevel 			break;
    425      0    stevel 	if (Allowednames[i].name == NULL)
    426      0    stevel 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
    427      0    stevel 		    "illegal property name in %s declaration: %s",
    428      0    stevel 		    ptree_nodetype2str(t), s);
    429      0    stevel 	else if ((np = tree_s2np_lut_lookup(lutp, s)) != NULL) {
    430      0    stevel 		/*
    431      0    stevel 		 * redeclaring prop is allowed if value is the same
    432      0    stevel 		 */
    433      0    stevel 		if (np->t != nvpairnp->u.expr.right->t)
    434      0    stevel 			outfl(O_ERR, nvpairnp->file, nvpairnp->line,
    435      0    stevel 			    "property redeclared (with differnt type) "
    436      0    stevel 			    "in %s declaration: %s",
    437      0    stevel 			    ptree_nodetype2str(t), s);
    438      0    stevel 		switch (np->t) {
    439      0    stevel 			case T_NUM:
    440      0    stevel 			case T_TIMEVAL:
    441      0    stevel 				if (np->u.ull == nvpairnp->u.expr.right->u.ull)
    442      0    stevel 					return;
    443      0    stevel 				break;
    444      0    stevel 
    445      0    stevel 			case T_NAME:
    446      0    stevel 				if (tree_namecmp(np,
    447      0    stevel 				    nvpairnp->u.expr.right) == 0)
    448      0    stevel 					return;
    449      0    stevel 				break;
    450      0    stevel 
    451      0    stevel 			case T_EVENT:
    452      0    stevel 				if (tree_eventcmp(np,
    453      0    stevel 				    nvpairnp->u.expr.right) == 0)
    454      0    stevel 					return;
    455      0    stevel 				break;
    456      0    stevel 
    457      0    stevel 			default:
    458      0    stevel 				outfl(O_ERR, nvpairnp->file, nvpairnp->line,
    459      0    stevel 				    "value for property \"%s\" is an "
    460      0    stevel 				    "invalid type: %s",
    461      0    stevel 				    nvpairnp->u.expr.left->u.name.s,
    462      0    stevel 				    ptree_nodetype2str(np->t));
    463      0    stevel 				return;
    464      0    stevel 		}
    465      0    stevel 		outfl(O_ERR, nvpairnp->file, nvpairnp->line,
    466      0    stevel 		    "property redeclared in %s declaration: %s",
    467      0    stevel 		    ptree_nodetype2str(t), s);
    468      0    stevel 	} else
    469      0    stevel 		(*Allowednames[i].checker)(t, s, nvpairnp->u.expr.right);
    470      0    stevel }
    471      0    stevel 
    472      0    stevel void
    473      0    stevel check_propnames(enum nodetype t, struct node *np, int from, int to)
    474      0    stevel {
    475      0    stevel 	struct node *dnp;
    476      0    stevel 	struct lut *lutp;
    477      0    stevel 
    478      0    stevel 	ASSERT(np != NULL);
    479      0    stevel 	ASSERTinfo(np->t == T_EVENT || np->t == T_LIST || np->t == T_ARROW,
    480   5633  cy152378 	    ptree_nodetype2str(np->t));
    481      0    stevel 
    482      0    stevel 	if (np->t == T_EVENT) {
    483      0    stevel 		switch (np->u.event.ename->u.name.t) {
    484      0    stevel 		case N_UNSPEC:
    485      0    stevel 			outfl(O_ERR, np->file, np->line,
    486      0    stevel 			    "name in %s statement must begin with "
    487      0    stevel 			    "type (example: \"error.\")",
    488      0    stevel 			    ptree_nodetype2str(t));
    489      0    stevel 			return;
    490      0    stevel 		case N_FAULT:
    491      0    stevel 			lutp = Faults;
    492      0    stevel 			if (to) {
    493      0    stevel 				outfl(O_ERR, np->file, np->line,
    494      0    stevel 				    "%s has fault on right side of \"->\"",
    495      0    stevel 				    ptree_nodetype2str(t));
    496      0    stevel 				return;
    497      0    stevel 			}
    498      0    stevel 			if (!from) {
    499      0    stevel 				outfl(O_DIE, np->file, np->line,
    500      0    stevel 				    "internal error: %s has fault without "
    501      0    stevel 				    "from flag",
    502      0    stevel 				    ptree_nodetype2str(t));
    503      0    stevel 			}
    504      0    stevel 			break;
    505      0    stevel 		case N_UPSET:
    506      0    stevel 			lutp = Upsets;
    507      0    stevel 			if (to) {
    508      0    stevel 				outfl(O_ERR, np->file, np->line,
    509      0    stevel 				    "%s has upset on right side of \"->\"",
    510      0    stevel 				    ptree_nodetype2str(t));
    511      0    stevel 				return;
    512      0    stevel 			}
    513      0    stevel 			if (!from)
    514      0    stevel 				outfl(O_DIE, np->file, np->line,
    515      0    stevel 				    "internal error: %s has upset without "
    516      0    stevel 				    "from flag",
    517      0    stevel 				    ptree_nodetype2str(t));
    518      0    stevel 			break;
    519      0    stevel 		case N_DEFECT:
    520      0    stevel 			lutp = Defects;
    521      0    stevel 			if (to) {
    522      0    stevel 				outfl(O_ERR, np->file, np->line,
    523      0    stevel 				    "%s has defect on right side of \"->\"",
    524      0    stevel 				    ptree_nodetype2str(t));
    525      0    stevel 				return;
    526      0    stevel 			}
    527      0    stevel 			if (!from) {
    528      0    stevel 				outfl(O_DIE, np->file, np->line,
    529      0    stevel 				    "internal error: %s has defect without "
    530      0    stevel 				    "from flag",
    531      0    stevel 				    ptree_nodetype2str(t));
    532      0    stevel 			}
    533      0    stevel 			break;
    534      0    stevel 		case N_ERROR:
    535      0    stevel 			lutp = Errors;
    536      0    stevel 			if (!from && !to)
    537      0    stevel 				outfl(O_DIE, np->file, np->line,
    538      0    stevel 				    "%s has error without from or to flags",
    539      0    stevel 				    ptree_nodetype2str(t));
    540      0    stevel 			break;
    541      0    stevel 		case N_EREPORT:
    542      0    stevel 			lutp = Ereports;
    543      0    stevel 			if (from) {
    544      0    stevel 				outfl(O_ERR, np->file, np->line,
    545      0    stevel 				    "%s has report on left side of \"->\"",
    546      0    stevel 				    ptree_nodetype2str(t));
    547      0    stevel 				return;
    548      0    stevel 			}
    549      0    stevel 			if (!to)
    550      0    stevel 				outfl(O_DIE, np->file, np->line,
    551      0    stevel 				    "internal error: %s has report without "
    552      0    stevel 				    "to flag",
    553      0    stevel 				    ptree_nodetype2str(t));
    554      0    stevel 			break;
    555      0    stevel 		default:
    556      0    stevel 			outfl(O_DIE, np->file, np->line,
    557      0    stevel 			    "internal error: check_propnames: "
    558      0    stevel 			    "unexpected type: %d", np->u.name.t);
    559      0    stevel 		}
    560      0    stevel 
    561      0    stevel 		if ((dnp = tree_event2np_lut_lookup(lutp, np)) == NULL) {
    562      0    stevel 			outfl(O_ERR, np->file, np->line,
    563      0    stevel 			    "%s statement contains undeclared event",
    564      0    stevel 			    ptree_nodetype2str(t));
    565      0    stevel 		} else
    566      0    stevel 			dnp->u.stmt.flags |= STMT_REF;
    567      0    stevel 		np->u.event.declp = dnp;
    568      0    stevel 	} else if (np->t == T_LIST) {
    569      0    stevel 		check_propnames(t, np->u.expr.left, from, to);
    570      0    stevel 		check_propnames(t, np->u.expr.right, from, to);
    571      0    stevel 	} else if (np->t == T_ARROW) {
    572      0    stevel 		check_propnames(t, np->u.arrow.lhs, 1, to);
    573      0    stevel 		check_propnames(t, np->u.arrow.rhs, from, 1);
    574      0    stevel 	}
    575      0    stevel }
    576      0    stevel 
    577      0    stevel static struct lut *
    578      0    stevel record_iterators(struct node *np, struct lut *ex)
    579      0    stevel {
    580      0    stevel 	if (np == NULL)
    581      0    stevel 		return (ex);
    582      0    stevel 
    583      0    stevel 	switch (np->t) {
    584      0    stevel 	case T_ARROW:
    585      0    stevel 		ex = record_iterators(np->u.arrow.lhs, ex);
    586      0    stevel 		ex = record_iterators(np->u.arrow.rhs, ex);
    587      0    stevel 		break;
    588      0    stevel 
    589      0    stevel 	case T_LIST:
    590      0    stevel 		ex = record_iterators(np->u.expr.left, ex);
    591      0    stevel 		ex = record_iterators(np->u.expr.right, ex);
    592      0    stevel 		break;
    593      0    stevel 
    594      0    stevel 	case T_EVENT:
    595      0    stevel 		ex = record_iterators(np->u.event.epname, ex);
    596      0    stevel 		break;
    597      0    stevel 
    598      0    stevel 	case T_NAME:
    599      0    stevel 		if (np->u.name.child && np->u.name.child->t == T_NAME)
    600      0    stevel 			ex = lut_add(ex, (void *) np->u.name.child->u.name.s,
    601      0    stevel 			    (void *) np, NULL);
    602      0    stevel 		ex = record_iterators(np->u.name.next, ex);
    603      0    stevel 		break;
    604      0    stevel 
    605      0    stevel 	default:
    606      0    stevel 		outfl(O_DIE, np->file, np->line,
    607      0    stevel 		    "record_iterators: internal error: unexpected type: %s",
    608      0    stevel 		    ptree_nodetype2str(np->t));
    609      0    stevel 	}
    610      0    stevel 
    611      0    stevel 	return (ex);
    612      0    stevel }
    613      0    stevel 
    614      0    stevel void
    615      0    stevel check_exprscope(struct node *np, struct lut *ex)
    616      0    stevel {
    617      0    stevel 	if (np == NULL)
    618      0    stevel 		return;
    619      0    stevel 
    620      0    stevel 	switch (np->t) {
    621      0    stevel 	case T_EVENT:
    622      0    stevel 		check_exprscope(np->u.event.eexprlist, ex);
    623      0    stevel 		break;
    624      0    stevel 
    625      0    stevel 	case T_ARROW:
    626      0    stevel 		check_exprscope(np->u.arrow.lhs, ex);
    627      0    stevel 		check_exprscope(np->u.arrow.rhs, ex);
    628      0    stevel 		break;
    629      0    stevel 
    630      0    stevel 	case T_NAME:
    631      0    stevel 		if (np->u.name.child && np->u.name.child->t == T_NAME) {
    632      0    stevel 			if (lut_lookup(ex,
    633   5633  cy152378 			    (void *) np->u.name.child->u.name.s, NULL) == NULL)
    634      0    stevel 				outfl(O_ERR, np->file, np->line,
    635   5633  cy152378 				    "constraint contains undefined"
    636   5633  cy152378 				    " iterator: %s",
    637   5633  cy152378 				    np->u.name.child->u.name.s);
    638      0    stevel 		}
    639      0    stevel 		check_exprscope(np->u.name.next, ex);
    640      0    stevel 		break;
    641      0    stevel 
    642      0    stevel 	case T_QUOTE:
    643      0    stevel 	case T_GLOBID:
    644      0    stevel 		break;
    645      0    stevel 
    646      0    stevel 	case T_ASSIGN:
    647      0    stevel 	case T_NE:
    648      0    stevel 	case T_EQ:
    649      0    stevel 	case T_LIST:
    650      0    stevel 	case T_AND:
    651      0    stevel 	case T_OR:
    652      0    stevel 	case T_NOT:
    653      0    stevel 	case T_ADD:
    654      0    stevel 	case T_SUB:
    655      0    stevel 	case T_MUL:
    656      0    stevel 	case T_DIV:
    657      0    stevel 	case T_MOD:
    658      0    stevel 	case T_LT:
    659      0    stevel 	case T_LE:
    660      0    stevel 	case T_GT:
    661      0    stevel 	case T_GE:
    662      0    stevel 	case T_BITAND:
    663      0    stevel 	case T_BITOR:
    664      0    stevel 	case T_BITXOR:
    665      0    stevel 	case T_BITNOT:
    666      0    stevel 	case T_LSHIFT:
    667      0    stevel 	case T_RSHIFT:
    668      0    stevel 	case T_CONDIF:
    669      0    stevel 	case T_CONDELSE:
    670      0    stevel 		check_exprscope(np->u.expr.left, ex);
    671      0    stevel 		check_exprscope(np->u.expr.right, ex);
    672      0    stevel 		break;
    673      0    stevel 
    674      0    stevel 	case T_FUNC:
    675      0    stevel 		check_exprscope(np->u.func.arglist, ex);
    676      0    stevel 		break;
    677      0    stevel 
    678      0    stevel 	case T_NUM:
    679      0    stevel 	case T_TIMEVAL:
    680      0    stevel 		break;
    681      0    stevel 
    682      0    stevel 	default:
    683      0    stevel 		outfl(O_DIE, np->file, np->line,
    684      0    stevel 		    "check_exprscope: internal error: unexpected type: %s",
    685      0    stevel 		    ptree_nodetype2str(np->t));
    686      0    stevel 	}
    687      0    stevel }
    688      0    stevel 
    689      0    stevel /*
    690      0    stevel  * check_propscope -- check constraints for out of scope variable refs
    691      0    stevel  */
    692      0    stevel void
    693      0    stevel check_propscope(struct node *np)
    694      0    stevel {
    695      0    stevel 	struct lut *ex;
    696      0    stevel 
    697      0    stevel 	ex = record_iterators(np, NULL);
    698      0    stevel 	check_exprscope(np, ex);
    699      0    stevel 	lut_free(ex, NULL, NULL);
    700      0    stevel }
    701      0    stevel 
    702      0    stevel /*
    703      0    stevel  * check_upset_engine -- validate the engine property in an upset statement
    704      0    stevel  *
    705      0    stevel  * we do this after the full parse tree has been constructed rather than while
    706      0    stevel  * building the parse tree because it is inconvenient for the user if we
    707      0    stevel  * require SERD engines to be declared before used in an upset "engine"
    708      0    stevel  * property.
    709      0    stevel  */
    710      0    stevel 
    711      0    stevel /*ARGSUSED*/
    712      0    stevel void
    713      0    stevel check_upset_engine(struct node *lhs, struct node *rhs, void *arg)
    714      0    stevel {
    715      0    stevel 	enum nodetype t = (enum nodetype)arg;
    716      0    stevel 	struct node *engnp;
    717      0    stevel 	struct node *declp;
    718      0    stevel 
    719      0    stevel 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
    720      0    stevel 
    721      0    stevel 	if ((engnp = tree_s2np_lut_lookup(rhs->u.stmt.lutp, L_engine)) == NULL)
    722      0    stevel 		return;
    723      0    stevel 
    724      0    stevel 	ASSERT(engnp->t == T_EVENT);
    725      0    stevel 
    726      0    stevel 	if ((declp = tree_event2np_lut_lookup(SERDs, engnp)) == NULL) {
    727      0    stevel 		outfl(O_ERR, engnp->file, engnp->line,
    728      0    stevel 		    "%s %s property contains undeclared name",
    729      0    stevel 		    ptree_nodetype2str(t), L_engine);
    730      0    stevel 		return;
    731      0    stevel 	}
    732      0    stevel 	engnp->u.event.declp = declp;
    733      0    stevel }
    734      0    stevel 
    735      0    stevel /*
    736      0    stevel  * check_refcount -- see if declared names are used
    737      0    stevel  *
    738      0    stevel  * this is run after the entire parse tree is constructed, so a refcount
    739      0    stevel  * of zero means the name has been declared but otherwise not used.
    740      0    stevel  */
    741      0    stevel 
    742      0    stevel void
    743      0    stevel check_refcount(struct node *lhs, struct node *rhs, void *arg)
    744      0    stevel {
    745      0    stevel 	enum nodetype t = (enum nodetype)arg;
    746      0    stevel 
    747      0    stevel 	ASSERTeq(rhs->t, t, ptree_nodetype2str);
    748      0    stevel 
    749      0    stevel 	if (rhs->u.stmt.flags & STMT_REF)
    750      0    stevel 		return;
    751      0    stevel 
    752      0    stevel 	outfl(O_WARN|O_NONL, rhs->file, rhs->line,
    753      0    stevel 	    "%s name declared but not used: ", ptree_nodetype2str(t));
    754      0    stevel 	ptree_name(O_WARN|O_NONL, lhs);
    755      0    stevel 	out(O_WARN, NULL);
    756      0    stevel }
    757      0    stevel 
    758      0    stevel /*
    759      0    stevel  * set check_cycle_warninglevel only for val >= 0
    760      0    stevel  */
    761      0    stevel int
    762      0    stevel check_cycle_level(long long val)
    763      0    stevel {
    764      0    stevel 	static int check_cycle_warninglevel = -1;
    765      0    stevel 
    766      0    stevel 	if (val == 0)
    767      0    stevel 		check_cycle_warninglevel = 0;
    768      0    stevel 	else if (val > 0)
    769      0    stevel 		check_cycle_warninglevel = 1;
    770      0    stevel 
    771      0    stevel 	return (check_cycle_warninglevel);
    772      0    stevel }
    773      0    stevel 
    774      0    stevel /*
    775      0    stevel  * check_cycle -- see props from an error have cycles
    776      0    stevel  *
    777      0    stevel  * this is run after the entire parse tree is constructed, for
    778      0    stevel  * each error that has been declared.
    779      0    stevel  */
    780      0    stevel 
    781      0    stevel /*ARGSUSED*/
    782      0    stevel void
    783      0    stevel check_cycle(struct node *lhs, struct node *rhs, void *arg)
    784      0    stevel {
    785      0    stevel 	struct node *np;
    786      0    stevel 
    787      0    stevel 	ASSERTeq(rhs->t, T_ERROR, ptree_nodetype2str);
    788      0    stevel 
    789      0    stevel 	if (rhs->u.stmt.flags & STMT_CYCLE)
    790      0    stevel 		return;		/* already reported this cycle */
    791      0    stevel 
    792      0    stevel 	if (rhs->u.stmt.flags & STMT_CYMARK) {
    793      0    stevel #ifdef ESC
    794      0    stevel 		int warninglevel;
    795      0    stevel 
    796      0    stevel 		warninglevel = check_cycle_level(-1);
    797      0    stevel 		if (warninglevel <= 0) {
    798      0    stevel 			int olevel = O_ERR;
    799      0    stevel 
    800      0    stevel 			if (warninglevel == 0)
    801      0    stevel 				olevel = O_WARN;
    802      0    stevel 
    803      0    stevel 			out(olevel|O_NONL, "cycle in propagation tree: ");
    804      0    stevel 			ptree_name(olevel|O_NONL, rhs->u.stmt.np);
    805      0    stevel 			out(olevel, NULL);
    806      0    stevel 		}
    807      0    stevel #endif /* ESC */
    808      0    stevel 
    809      0    stevel 		rhs->u.stmt.flags |= STMT_CYCLE;
    810      0    stevel 	}
    811      0    stevel 
    812      0    stevel 	rhs->u.stmt.flags |= STMT_CYMARK;
    813      0    stevel 
    814      0    stevel 	/* for each propagation */
    815      0    stevel 	for (np = Props; np; np = np->u.stmt.next)
    816      0    stevel 		check_cycle_lhs(rhs, np->u.stmt.np);
    817      0    stevel 
    818      0    stevel 	rhs->u.stmt.flags &= ~STMT_CYMARK;
    819      0    stevel }
    820      0    stevel 
    821      0    stevel /*
    822      0    stevel  * check_cycle_lhs -- find the lhs of an arrow for cycle checking
    823      0    stevel  */
    824      0    stevel 
    825      0    stevel static void
    826      0    stevel check_cycle_lhs(struct node *stmtnp, struct node *arrow)
    827      0    stevel {
    828      0    stevel 	struct node *trylhs;
    829      0    stevel 	struct node *tryrhs;
    830      0    stevel 
    831      0    stevel 	/* handle cascaded arrows */
    832      0    stevel 	switch (arrow->u.arrow.lhs->t) {
    833      0    stevel 	case T_ARROW:
    834      0    stevel 		/* first recurse left */
    835      0    stevel 		check_cycle_lhs(stmtnp, arrow->u.arrow.lhs);
    836      0    stevel 
    837    854  rw145199 		/*
    838    854  rw145199 		 * return if there's a list of events internal to
    839    854  rw145199 		 * cascaded props (which is not allowed)
    840   1414     cindi 		 */
    841    854  rw145199 		if (arrow->u.arrow.lhs->u.arrow.rhs->t != T_EVENT)
    842    854  rw145199 			return;
    843      0    stevel 
    844      0    stevel 		/* then try this arrow (thing cascaded *to*) */
    845      0    stevel 		trylhs = arrow->u.arrow.lhs->u.arrow.rhs;
    846      0    stevel 		tryrhs = arrow->u.arrow.rhs;
    847      0    stevel 		break;
    848      0    stevel 
    849      0    stevel 	case T_EVENT:
    850      0    stevel 	case T_LIST:
    851      0    stevel 		trylhs = arrow->u.arrow.lhs;
    852      0    stevel 		tryrhs = arrow->u.arrow.rhs;
    853      0    stevel 		break;
    854      0    stevel 
    855      0    stevel 	default:
    856      0    stevel 		out(O_DIE, "lhs: unexpected type: %s",
    857      0    stevel 		    ptree_nodetype2str(arrow->u.arrow.lhs->t));
    858      0    stevel 		/*NOTREACHED*/
    859      0    stevel 	}
    860      0    stevel 
    861      0    stevel 	check_cycle_lhs_try(stmtnp, trylhs, tryrhs);
    862      0    stevel }
    863      0    stevel 
    864      0    stevel /*
    865      0    stevel  * check_cycle_lhs_try -- try matching an event name on lhs of an arrow
    866      0    stevel  */
    867      0    stevel 
    868      0    stevel static void
    869      0    stevel check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, struct node *rhs)
    870      0    stevel {
    871      0    stevel 	if (lhs->t == T_LIST) {
    872      0    stevel 		check_cycle_lhs_try(stmtnp, lhs->u.expr.left, rhs);
    873      0    stevel 		check_cycle_lhs_try(stmtnp, lhs->u.expr.right, rhs);
    874      0    stevel 		return;
    875      0    stevel 	}
    876      0    stevel 
    877      0    stevel 	ASSERT(lhs->t == T_EVENT);
    878      0    stevel 
    879      0    stevel 	if (tree_eventcmp(stmtnp->u.stmt.np, lhs) != 0)
    880      0    stevel 		return;		/* no match */
    881      0    stevel 
    882      0    stevel 	check_cycle_rhs(rhs);
    883      0    stevel }
    884      0    stevel 
    885      0    stevel /*
    886      0    stevel  * check_cycle_rhs -- foreach error on rhs, see if we cycle to a marked error
    887      0    stevel  */
    888      0    stevel 
    889      0    stevel static void
    890      0    stevel check_cycle_rhs(struct node *rhs)
    891      0    stevel {
    892      0    stevel 	struct node *dnp;
    893      0    stevel 
    894      0    stevel 	if (rhs->t == T_LIST) {
    895      0    stevel 		check_cycle_rhs(rhs->u.expr.left);
    896      0    stevel 		check_cycle_rhs(rhs->u.expr.right);
    897      0    stevel 		return;
    898      0    stevel 	}
    899      0    stevel 
    900      0    stevel 	ASSERT(rhs->t == T_EVENT);
    901      0    stevel 
    902      0    stevel 	if (rhs->u.event.ename->u.name.t != N_ERROR)
    903      0    stevel 		return;
    904      0    stevel 
    905      0    stevel 	if ((dnp = tree_event2np_lut_lookup(Errors, rhs)) == NULL) {
    906      0    stevel 		outfl(O_ERR|O_NONL,
    907      0    stevel 		    rhs->file, rhs->line,
    908      0    stevel 		    "unexpected undeclared event during cycle check");
    909      0    stevel 		ptree_name(O_ERR|O_NONL, rhs);
    910      0    stevel 		out(O_ERR, NULL);
    911      0    stevel 		return;
    912      0    stevel 	}
    913      0    stevel 	check_cycle(NULL, dnp, 0);
    914      0    stevel }
    915      0    stevel 
    916      0    stevel /*
    917      0    stevel  * Force iterators to be simple names, expressions, or numbers
    918      0    stevel  */
    919      0    stevel void
    920      0    stevel check_name_iterator(struct node *np)
    921      0    stevel {
    922      0    stevel 	if (np->u.name.child->t != T_NUM &&
    923      0    stevel 	    np->u.name.child->t != T_NAME &&
    924      0    stevel 	    np->u.name.child->t != T_CONDIF &&
    925      0    stevel 	    np->u.name.child->t != T_SUB &&
    926      0    stevel 	    np->u.name.child->t != T_ADD &&
    927      0    stevel 	    np->u.name.child->t != T_MUL &&
    928      0    stevel 	    np->u.name.child->t != T_DIV &&
    929      0    stevel 	    np->u.name.child->t != T_MOD &&
    930      0    stevel 	    np->u.name.child->t != T_LSHIFT &&
    931      0    stevel 	    np->u.name.child->t != T_RSHIFT) {
    932      0    stevel 		outfl(O_ERR|O_NONL, np->file, np->line,
    933      0    stevel 		"invalid iterator: ");
    934      0    stevel 		ptree_name_iter(O_ERR|O_NONL, np);
    935      0    stevel 		out(O_ERR, NULL);
    936      0    stevel 	}
    937      0    stevel }
    938      0    stevel 
    939      0    stevel /*
    940      0    stevel  * Iterators on a declaration may only be implicit
    941      0    stevel  */
    942      0    stevel void
    943      0    stevel check_type_iterator(struct node *np)
    944      0    stevel {
    945      0    stevel 	while (np != NULL) {
    946      0    stevel 		if (np->t == T_EVENT) {
    947      0    stevel 			np = np->u.event.epname;
    948      0    stevel 		} else if (np->t == T_NAME) {
    949      0    stevel 			if (np->u.name.child != NULL &&
    950      0    stevel 			    np->u.name.child->t != T_NUM) {
    951      0    stevel 				outfl(O_ERR|O_NONL, np->file, np->line,
    952      0    stevel 				    "explicit iterators disallowed "
    953      0    stevel 				    "in declarations: ");
    954      0    stevel 				ptree_name_iter(O_ERR|O_NONL, np);
    955      0    stevel 				out(O_ERR, NULL);
    956      0    stevel 			}
    957      0    stevel 			np = np->u.name.next;
    958      0    stevel 		} else {
    959      0    stevel 			break;
    960      0    stevel 		}
    961      0    stevel 	}
    962      0    stevel }
    963      0    stevel 
    964      0    stevel void
    965  11202   Stephen check_cat_list(struct node *np)
    966  11202   Stephen {
    967  11202   Stephen 	if (np->t == T_FUNC)
    968  11202   Stephen 		check_func(np);
    969  11202   Stephen 	else if (np->t == T_LIST) {
    970  11202   Stephen 		check_cat_list(np->u.expr.left);
    971  11202   Stephen 		check_cat_list(np->u.expr.right);
    972  11202   Stephen 	}
    973  11202   Stephen }
    974  11202   Stephen 
    975  11202   Stephen void
    976      0    stevel check_func(struct node *np)
    977      0    stevel {
    978   6806       cth 	struct node *arglist = np->u.func.arglist;
    979   6806       cth 
    980      0    stevel 	ASSERTinfo(np->t == T_FUNC, ptree_nodetype2str(np->t));
    981      0    stevel 
    982      0    stevel 	if (np->u.func.s == L_within) {
    983      0    stevel 		switch (arglist->t) {
    984   6806       cth 		case T_NUM:
    985   6806       cth 			if (arglist->u.ull != 0ULL) {
    986   6806       cth 				outfl(O_ERR, arglist->file, arglist->line,
    987   6806       cth 				    "parameter of within must be 0"
    988   6806       cth 				    ", \"infinity\" or a time value.");
    989   6806       cth 			}
    990   6806       cth 			break;
    991   6806       cth 
    992   6806       cth 		case T_NAME:
    993   6806       cth 			if (arglist->u.name.s != L_infinity) {
    994   6806       cth 				outfl(O_ERR, arglist->file, arglist->line,
    995   6806       cth 				    "parameter of within must be 0"
    996   6806       cth 				    ", \"infinity\" or a time value.");
    997   6806       cth 			}
    998   6806       cth 			break;
    999   6806       cth 
   1000   6806       cth 		case T_LIST:
   1001   6806       cth 			/*
   1002   6806       cth 			 * if two parameters, the left or min must be
   1003   6806       cth 			 * either T_NUM or T_TIMEVAL
   1004   6806       cth 			 */
   1005   6806       cth 			if (arglist->u.expr.left->t != T_NUM &&
   1006   6806       cth 			    arglist->u.expr.left->t != T_TIMEVAL) {
   1007   6806       cth 				outfl(O_ERR, arglist->file, arglist->line,
   1008   6806       cth 				    "first parameter of within must be"
   1009   6806       cth 				    " either a time value or zero.");
   1010   6806       cth 			}
   1011      0    stevel 
   1012   6640       cth 			/*
   1013   6640       cth 			 * if two parameters, the right or max must
   1014   6640       cth 			 * be either T_NUM, T_NAME or T_TIMEVAL
   1015   6640       cth 			 */
   1016   6640       cth 			if (arglist->u.expr.right->t != T_NUM &&
   1017   6640       cth 			    arglist->u.expr.right->t != T_TIMEVAL &&
   1018   6806       cth 			    arglist->u.expr.right->t != T_NAME) {
   1019   6806       cth 				outfl(O_ERR, arglist->file, arglist->line,
   1020   6640       cth 				    "second parameter of within must "
   1021   6806       cth 				    "be 0, \"infinity\" or time value.");
   1022   6806       cth 			}
   1023      0    stevel 
   1024   6806       cth 			/*
   1025   6806       cth 			 * if right or left is a T_NUM it must
   1026   6806       cth 			 * be zero
   1027   6806       cth 			 */
   1028   6806       cth 			if ((arglist->u.expr.left->t == T_NUM) &&
   1029   6806       cth 			    (arglist->u.expr.left->u.ull != 0ULL)) {
   1030   6806       cth 				outfl(O_ERR, arglist->file, arglist->line,
   1031   6806       cth 				    "within parameter must be "
   1032   6806       cth 				    "0 or a time value.");
   1033   6806       cth 			}
   1034   6806       cth 			if ((arglist->u.expr.right->t == T_NUM) &&
   1035   6806       cth 			    (arglist->u.expr.right->u.ull != 0ULL)) {
   1036   6806       cth 				outfl(O_ERR, arglist->file, arglist->line,
   1037   6806       cth 				    "within parameter must be "
   1038   6806       cth 				    "0 or a time value.");
   1039   6806       cth 			}
   1040      0    stevel 
   1041   6806       cth 			/* if right is a T_NAME it must be "infinity" */
   1042   6806       cth 			if ((arglist->u.expr.right->t == T_NAME) &&
   1043   6806       cth 			    (arglist->u.expr.right->u.name.s != L_infinity)) {
   1044   6806       cth 				outfl(O_ERR, arglist->file, arglist->line,
   1045   6806       cth 				    "\"infinity\" is the only "
   1046   6806       cth 				    "valid name for within parameter.");
   1047   6806       cth 			}
   1048      0    stevel 
   1049   6640       cth 			/*
   1050   6640       cth 			 * the first parameter [min] must not be greater
   1051   6640       cth 			 * than the second parameter [max].
   1052   6640       cth 			 */
   1053   6640       cth 			if (arglist->u.expr.left->u.ull >
   1054   6806       cth 			    arglist->u.expr.right->u.ull) {
   1055      0    stevel 				outfl(O_ERR, arglist->file, arglist->line,
   1056   6806       cth 				    "the first value (min) of"
   1057   6806       cth 				    " within must be less than"
   1058   6806       cth 				    " the second (max) value");
   1059   6806       cth 			}
   1060   6806       cth 			break;
   1061   6806       cth 
   1062   6806       cth 		case T_TIMEVAL:
   1063   6806       cth 			break; /* no restrictions on T_TIMEVAL */
   1064   6806       cth 
   1065   6806       cth 		default:
   1066   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1067   6806       cth 			    "parameter of within must be 0"
   1068   6806       cth 			    ", \"infinity\" or a time value.");
   1069      0    stevel 		}
   1070      0    stevel 	} else if (np->u.func.s == L_call) {
   1071   6806       cth 		if (arglist->t != T_QUOTE &&
   1072   6806       cth 		    arglist->t != T_LIST &&
   1073   6806       cth 		    arglist->t != T_GLOBID &&
   1074   6806       cth 		    arglist->t != T_CONDIF &&
   1075   6806       cth 		    arglist->t != T_LIST &&
   1076   6806       cth 		    arglist->t != T_FUNC)
   1077   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1078   5633  cy152378 			    "invalid first argument to call()");
   1079      0    stevel 	} else if (np->u.func.s == L_fru) {
   1080   6806       cth 		if (arglist->t != T_NAME)
   1081   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1082   5633  cy152378 			    "argument to fru() must be a path");
   1083      0    stevel 	} else if (np->u.func.s == L_asru) {
   1084   6806       cth 		if (arglist->t != T_NAME)
   1085   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1086   5633  cy152378 			    "argument to asru() must be a path");
   1087      0    stevel 	} else if (np->u.func.s == L_is_connected ||
   1088      0    stevel 	    np->u.func.s == L_is_under) {
   1089   6806       cth 		if (arglist->t == T_LIST &&
   1090   6806       cth 		    (arglist->u.expr.left->t == T_NAME ||
   1091  11202   Stephen 		    arglist->u.expr.left->t == T_FUNC) &&
   1092   6806       cth 		    (arglist->u.expr.right->t == T_NAME ||
   1093  11202   Stephen 		    arglist->u.expr.right->t == T_FUNC)) {
   1094   6806       cth 			if (arglist->u.expr.left->t == T_FUNC)
   1095   6806       cth 				check_func(arglist->u.expr.left);
   1096   6806       cth 			if (arglist->u.expr.right->t == T_FUNC)
   1097   6806       cth 				check_func(arglist->u.expr.right);
   1098      0    stevel 		} else {
   1099   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1100      0    stevel 			    "%s() must have paths or calls to "
   1101      0    stevel 			    "fru() and/or asru() as arguments",
   1102      0    stevel 			    np->u.func.s);
   1103      0    stevel 		}
   1104      0    stevel 	} else if (np->u.func.s == L_is_on) {
   1105  11202   Stephen 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
   1106   7197    stephh 			if (arglist->t == T_FUNC)
   1107   7197    stephh 				check_func(arglist);
   1108      0    stevel 		} else {
   1109   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1110   7197    stephh 			    "argument to is_on() must be a path or a call to "
   1111      0    stevel 			    "fru() or asru()");
   1112      0    stevel 		}
   1113      0    stevel 	} else if (np->u.func.s == L_is_present) {
   1114  11202   Stephen 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
   1115   7197    stephh 			if (arglist->t == T_FUNC)
   1116   7197    stephh 				check_func(arglist);
   1117      0    stevel 		} else {
   1118   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1119   7197    stephh 			    "argument to is_present() must be a path or a call "
   1120   7197    stephh 			    "to fru() or asru()");
   1121      0    stevel 		}
   1122   7275    stephh 	} else if (np->u.func.s == L_has_fault) {
   1123   7275    stephh 		if (arglist->t == T_LIST &&
   1124   7275    stephh 		    (arglist->u.expr.left->t == T_NAME ||
   1125  11202   Stephen 		    arglist->u.expr.left->t == T_FUNC) &&
   1126   7275    stephh 		    arglist->u.expr.right->t == T_QUOTE) {
   1127   7275    stephh 			if (arglist->u.expr.left->t == T_FUNC)
   1128   7275    stephh 				check_func(arglist->u.expr.left);
   1129   7275    stephh 		} else {
   1130   7275    stephh 			outfl(O_ERR, arglist->file, arglist->line,
   1131   7275    stephh 			    "%s() must have path or call to "
   1132   7275    stephh 			    "fru() and/or asru() as first argument; "
   1133   7275    stephh 			    "second argument must be a string", np->u.func.s);
   1134   7275    stephh 		}
   1135      0    stevel 	} else if (np->u.func.s == L_is_type) {
   1136  11202   Stephen 		if (arglist->t == T_NAME || arglist->t == T_FUNC) {
   1137   7197    stephh 			if (arglist->t == T_FUNC)
   1138   7197    stephh 				check_func(arglist);
   1139      0    stevel 		} else {
   1140   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1141   7197    stephh 			    "argument to is_type() must be a path or a call to "
   1142      0    stevel 			    "fru() or asru()");
   1143      0    stevel 		}
   1144   1414     cindi 	} else if (np->u.func.s == L_confcall) {
   1145   6806       cth 		if (arglist->t != T_QUOTE &&
   1146   6806       cth 		    (arglist->t != T_LIST ||
   1147   6806       cth 		    arglist->u.expr.left->t != T_QUOTE))
   1148   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1149   1414     cindi 			    "confcall(): first argument must be a string "
   1150   1414     cindi 			    "(the name of the operation)");
   1151   2869    gavinm 	} else if (np->u.func.s == L_confprop ||
   1152   2869    gavinm 	    np->u.func.s == L_confprop_defined) {
   1153   6806       cth 		if (arglist->t == T_LIST &&
   1154   7197    stephh 		    (arglist->u.expr.left->t == T_NAME ||
   1155  11202   Stephen 		    arglist->u.expr.left->t == T_FUNC) &&
   1156   6806       cth 		    arglist->u.expr.right->t == T_QUOTE) {
   1157   7197    stephh 			if (arglist->u.expr.left->t == T_FUNC)
   1158   7197    stephh 				check_func(arglist->u.expr.left);
   1159      0    stevel 		} else {
   1160   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1161   7197    stephh 			    "%s(): first argument must be a path or a call to "
   1162      0    stevel 			    "fru() or asru(); "
   1163   2869    gavinm 			    "second argument must be a string", np->u.func.s);
   1164      0    stevel 		}
   1165   1414     cindi 	} else if (np->u.func.s == L_count) {
   1166   6806       cth 		if (arglist->t != T_EVENT) {
   1167   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1168   1414     cindi 			    "count(): argument must be an engine name");
   1169   1414     cindi 		}
   1170   1414     cindi 	} else if (np->u.func.s == L_defined) {
   1171   6806       cth 		if (arglist->t != T_GLOBID)
   1172   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1173   5633  cy152378 			    "argument to defined() must be a global");
   1174      0    stevel 	} else if (np->u.func.s == L_payloadprop) {
   1175   6806       cth 		if (arglist->t != T_QUOTE)
   1176   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1177   5633  cy152378 			    "argument to payloadprop() must be a string");
   1178   1414     cindi 	} else if (np->u.func.s == L_payloadprop_contains) {
   1179   6806       cth 		if (arglist->t != T_LIST ||
   1180   6806       cth 		    arglist->u.expr.left->t != T_QUOTE ||
   1181   6806       cth 		    arglist->u.expr.right == NULL)
   1182   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1183   1414     cindi 			    "args to payloadprop_contains(): must be a quoted "
   1184   1414     cindi 			    "string (property name) and an expression "
   1185   1414     cindi 			    "(to match)");
   1186   1414     cindi 	} else if (np->u.func.s == L_payloadprop_defined) {
   1187   6806       cth 		if (arglist->t != T_QUOTE)
   1188   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1189   1414     cindi 			    "arg to payloadprop_defined(): must be a quoted "
   1190   1414     cindi 			    "string");
   1191   1414     cindi 	} else if (np->u.func.s == L_setpayloadprop) {
   1192   6806       cth 		if (arglist->t == T_LIST &&
   1193   6806       cth 		    arglist->u.expr.left->t == T_QUOTE) {
   1194   6806       cth 			if (arglist->u.expr.right->t == T_FUNC)
   1195   6806       cth 				check_func(arglist->u.expr.right);
   1196   1414     cindi 		} else {
   1197   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1198   1414     cindi 			    "setpayloadprop(): "
   1199   1414     cindi 			    "first arg must be a string, "
   1200   1414     cindi 			    "second arg a value");
   1201   1414     cindi 		}
   1202   7197    stephh 	} else if (np->u.func.s == L_setserdn || np->u.func.s == L_setserdt ||
   1203   7197    stephh 	    np->u.func.s == L_setserdsuffix || np->u.func.s ==
   1204   7197    stephh 	    L_setserdincrement) {
   1205   7197    stephh 		if (arglist->t == T_FUNC)
   1206   7197    stephh 			check_func(arglist);
   1207  11202   Stephen 	} else if (np->u.func.s == L_cat) {
   1208  11202   Stephen 		check_cat_list(arglist);
   1209      0    stevel 	} else if (np->u.func.s == L_envprop) {
   1210   6806       cth 		if (arglist->t != T_QUOTE)
   1211   6806       cth 			outfl(O_ERR, arglist->file, arglist->line,
   1212   5633  cy152378 			    "argument to envprop() must be a string");
   1213      0    stevel 	} else
   1214      0    stevel 		outfl(O_WARN, np->file, np->line,
   1215   5633  cy152378 		    "possible platform-specific function: %s",
   1216   5633  cy152378 		    np->u.func.s);
   1217      0    stevel }
   1218      0    stevel 
   1219      0    stevel void
   1220      0    stevel check_expr(struct node *np)
   1221      0    stevel {
   1222      0    stevel 	ASSERT(np != NULL);
   1223      0    stevel 
   1224      0    stevel 	switch (np->t) {
   1225      0    stevel 	case T_ASSIGN:
   1226      0    stevel 		ASSERT(np->u.expr.left != NULL);
   1227      0    stevel 		if (np->u.expr.left->t != T_GLOBID)
   1228      0    stevel 			outfl(O_ERR, np->file, np->line,
   1229      0    stevel 			    "assignment only allowed to globals (e.g. $a)");
   1230      0    stevel 		break;
   1231      0    stevel 	}
   1232      0    stevel }
   1233      0    stevel 
   1234      0    stevel void
   1235      0    stevel check_event(struct node *np)
   1236      0    stevel {
   1237      0    stevel 	ASSERT(np != NULL);
   1238   1414     cindi 	ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t));
   1239      0    stevel 
   1240      0    stevel 	if (np->u.event.epname == NULL) {
   1241      0    stevel 		outfl(O_ERR|O_NONL, np->file, np->line,
   1242      0    stevel 		    "pathless events not allowed: ");
   1243      0    stevel 		ptree_name(O_ERR|O_NONL, np->u.event.ename);
   1244      0    stevel 		out(O_ERR, NULL);
   1245      0    stevel 	}
   1246      0    stevel }
   1247      0    stevel 
   1248      0    stevel /*
   1249      0    stevel  * check for properties that are required on declarations. This
   1250      0    stevel  * should be done after all declarations since they can be
   1251      0    stevel  * redeclared with a different set of properties.
   1252      0    stevel  */
   1253      0    stevel /*ARGSUSED*/
   1254      0    stevel void
   1255      0    stevel check_required_props(struct node *lhs, struct node *rhs, void *arg)
   1256      0    stevel {
   1257   5633  cy152378 	ASSERTeq(rhs->t, (enum nodetype)arg, ptree_nodetype2str);
   1258      0    stevel 
   1259      0    stevel 	check_stmt_required_properties(rhs);
   1260      0    stevel }
   1261    854  rw145199 
   1262    854  rw145199 /*
   1263    854  rw145199  * check that cascading prop statements do not contain lists internally.
   1264    854  rw145199  * the first and last event lists in the cascading prop may be single
   1265    854  rw145199  * events or lists of events.
   1266    854  rw145199  */
   1267    854  rw145199 /*ARGSUSED*/
   1268    854  rw145199 void
   1269    854  rw145199 check_proplists(enum nodetype t, struct node *np)
   1270    854  rw145199 {
   1271    854  rw145199 	ASSERT(np->t == T_ARROW);
   1272    854  rw145199 	/*
   1273    854  rw145199 	 * not checking the right hand side of the top level prop
   1274    854  rw145199 	 * since it is the last part of the propagation and can be
   1275    854  rw145199 	 * an event or list of events
   1276    854  rw145199 	 */
   1277    854  rw145199 	check_proplists_lhs(t, np->u.arrow.lhs);
   1278    854  rw145199 }
   1279    854  rw145199 
   1280    854  rw145199 /*ARGSUSED*/
   1281    854  rw145199 static void
   1282    854  rw145199 check_proplists_lhs(enum nodetype t, struct node *lhs)
   1283    854  rw145199 {
   1284    854  rw145199 	if (lhs->t == T_ARROW) {
   1285    854  rw145199 		if (lhs->u.arrow.rhs->t == T_LIST) {
   1286    854  rw145199 			outfl(O_ERR, lhs->file, lhs->line,
   1287   5633  cy152378 			    "lists are not allowed internally on cascading %s",
   1288   5633  cy152378 			    (t == T_PROP) ? "propagations" : "masks");
   1289    854  rw145199 		}
   1290    854  rw145199 		check_proplists_lhs(t, lhs->u.arrow.lhs);
   1291    854  rw145199 	}
   1292    854  rw145199 }
   1293