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