/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* tree.c -- routines for manipulating the prop tree
*
* the actions in escparse.y call these routines to construct
* the parse tree. these routines, in turn, call the check_X()
* routines for semantic checking.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <alloca.h>
#include "alloc.h"
#include "out.h"
#include "stats.h"
#include "stable.h"
#include "literals.h"
#include "lut.h"
#include "esclex.h"
#include "tree.h"
#include "check.h"
#include "ptree.h"
static char *Newname;
void
tree_init(void)
{
Nodesize =
}
void
tree_fini(void)
{
/* free entire parse tree */
/* free up the luts we keep for decls */
}
}
/*ARGSUSED*/
static int
{
switch (t) {
case T_NAME:
break;
case T_GLOBID:
break;
case T_TIMEVAL:
case T_NUM:
break;
case T_QUOTE:
break;
case T_FUNC:
break;
case T_FAULT:
case T_UPSET:
case T_DEFECT:
case T_ERROR:
case T_EREPORT:
case T_ASRU:
case T_FRU:
case T_SERD:
case T_STAT:
case T_CONFIG:
case T_PROP:
case T_MASK:
break;
case T_EVENT:
break;
case T_ARROW:
break;
default:
break;
}
return (size);
}
struct node *
{
ret->t = t;
return (ret);
}
/*ARGSUSED*/
void
{
return;
switch (root->t) {
case T_NAME:
break;
case T_FUNC:
break;
case T_AND:
case T_OR:
case T_EQ:
case T_NE:
case T_ADD:
case T_DIV:
case T_MOD:
case T_MUL:
case T_SUB:
case T_LT:
case T_LE:
case T_GT:
case T_GE:
case T_BITAND:
case T_BITOR:
case T_BITXOR:
case T_BITNOT:
case T_LSHIFT:
case T_RSHIFT:
case T_NVPAIR:
case T_ASSIGN:
case T_CONDIF:
case T_CONDELSE:
case T_LIST:
break;
case T_EVENT:
break;
case T_NOT:
break;
case T_ARROW:
break;
case T_PROP:
case T_MASK:
break;
case T_FAULT:
case T_UPSET:
case T_DEFECT:
case T_ERROR:
case T_EREPORT:
case T_ASRU:
case T_FRU:
case T_SERD:
case T_STAT:
case T_CONFIG:
break;
case T_TIMEVAL:
case T_NUM:
case T_QUOTE:
case T_GLOBID:
case T_NOTHING:
break;
default:
"internal error: tree_free unexpected nodetype: %d",
root->t);
/*NOTREACHED*/
}
}
static int
{
return (0);
return (1);
if (np1->t == t)
switch (np1->t) {
case T_NAME:
cmp_func))
return (1);
cmp_func));
/*NOTREACHED*/
break;
case T_FUNC:
t, cmp_func));
/*NOTREACHED*/
break;
case T_AND:
case T_OR:
case T_EQ:
case T_NE:
case T_ADD:
case T_DIV:
case T_MOD:
case T_MUL:
case T_SUB:
case T_LT:
case T_LE:
case T_GT:
case T_GE:
case T_BITAND:
case T_BITOR:
case T_BITXOR:
case T_BITNOT:
case T_LSHIFT:
case T_RSHIFT:
case T_NVPAIR:
case T_ASSIGN:
case T_CONDIF:
case T_CONDELSE:
case T_LIST:
cmp_func))
return (1);
cmp_func));
/*NOTREACHED*/
break;
case T_EVENT:
cmp_func))
return (1);
cmp_func))
return (1);
/*NOTREACHED*/
break;
case T_NOT:
cmp_func));
/*NOTREACHED*/
break;
case T_ARROW:
cmp_func))
return (1);
cmp_func))
return (1);
cmp_func))
return (1);
cmp_func));
/*NOTREACHED*/
break;
case T_PROP:
case T_MASK:
cmp_func));
/*NOTREACHED*/
break;
case T_FAULT:
case T_UPSET:
case T_DEFECT:
case T_ERROR:
case T_EREPORT:
case T_ASRU:
case T_FRU:
case T_SERD:
case T_STAT:
return (1);
t, cmp_func));
/*NOTREACHED*/
break;
case T_TIMEVAL:
case T_NUM:
case T_QUOTE:
case T_GLOBID:
case T_NOTHING:
break;
default:
"internal error: tree_treecmp unexpected nodetype: %d",
np1->t);
/*NOTREACHED*/
break;
}
return (0);
}
struct node *
{
if (np)
return (Root);
}
struct node *
tree_nothing(void)
{
}
struct node *
{
return (ret);
}
/*
* ename_compress -- convert event class name in to more space-efficient form
*
* this routine is called after the parser has completed an "ename", which
* is that part of an event that contains the class name (like ereport.x.y.z).
* after this routine gets done with the ename, two things are true:
* 1. the ename uses only a single struct node
* 2. ename->u.name.s contains the *complete* class name, dots and all,
* entered into the string table.
*
* so in addition to saving space by using fewer struct nodes, this routine
* allows consumers of the fault tree to assume the ename is a single
* string, rather than a linked list of strings.
*/
static struct node *
{
char *buf;
char *cp;
int len = 0;
return (ename);
return (ename); /* no compression to be applied here */
len++; /* room for '.' and final '\0' */
}
*cp++ = '.';
}
return (ename);
}
struct node *
{
return (ret);
}
struct node *
{
/* PHASE2, possible optimization: convert to table driven */
if (s == L_fault)
else if (s == L_upset)
else if (s == L_defect)
else if (s == L_error)
else if (s == L_ereport)
else if (s == L_serd)
else if (s == L_stat)
else
}
return (ret);
}
struct node *
{
char *ss;
char *ptr;
}
ptr--;
*ptr = '\0';
return (ret);
}
struct node *
{
return (ret);
}
struct node *
{
"tree_name_append: internal error (np1 type %d)", np1->t);
"tree_name_append: internal error (np2 type %d)", np2->t);
return (np1);
}
/*
* tree_name_repairdash -- repair a class name that contained a dash
*
* this routine is called by the parser when a dash is encountered
* in a class name. the event protocol allows the dashes but our
* lexer considers them a separate token (arithmetic minus). an extra
* rule in the parser catches this case and calls this routine to fixup
* the last component of the class name (so far) by constructing the
* new stable entry for a name including the dash.
*/
struct node *
{
int len;
char *buf;
"tree_name_repairdash: internal error (np type %d)",
np->t);
return (np);
}
struct node *
{
int len;
char *buf;
"tree_name_repairdash: internal error (np type %d)",
np->t);
return (np);
}
struct node *
{
return (np1);
}
struct node *
{
const unsigned long long *ullp;
"unrecognized number suffix: %s", suffix);
/* still construct a valid timeval node so parsing continues */
} else {
}
return (ret);
}
struct node *
{
return (ret);
}
struct node *
{
return (ret);
}
struct node *
{
const char *ptr;
/*
* keep track of the properties we're interested in so we can ignore the
* rest
*/
} else if (strcmp(s, L_is_connected) == 0) {
}
return (ret);
}
/*
* given a list from a prop or mask statement or a function argument,
* convert all iterators to explicit iterators by inventing appropriate
* iterator names.
*/
static void
{
int count;
namesz = 200;
}
return; /* all done */
switch (np->t) {
case T_ASSIGN:
case T_CONDIF:
case T_CONDELSE:
case T_NE:
case T_EQ:
case T_LT:
case T_LE:
case T_GT:
case T_GE:
case T_BITAND:
case T_BITOR:
case T_BITXOR:
case T_BITNOT:
case T_LSHIFT:
case T_RSHIFT:
case T_LIST:
case T_AND:
case T_OR:
case T_NOT:
case T_ADD:
case T_SUB:
case T_MUL:
case T_DIV:
case T_MOD:
break;
case T_EVENT:
break;
case T_FUNC:
break;
case T_NAME:
if (eventonly)
return;
/*
* found implicit iterator. convert
* it to an explicit iterator by
* using the name of the component
* appended with '#' and the number
* of times we've seen this same
* component name in this path so far.
*/
count = 0;
break;
count++;
100) {
100;
}
/*
* made up interator name is:
* name#ordinal
* or
* name##ordinal
* the first one is used for vertical
* expansion, the second for horizontal.
* either way, the '#' embedded in
* the name makes it impossible to
* collide with an actual iterator
* given to us in the eversholt file.
*/
}
break;
}
}
struct node *
{
make_explicit(np, 0);
return (np);
}
struct node *
{
make_explicit(lhs, 0);
make_explicit(rhs, 0);
return (ret);
}
static struct lut *
{
if (np) {
} else
"internal error: nvpair2lut type %s",
ptree_nodetype2str(np->t));
}
return (lutp);
}
struct lut *
{
}
struct node *
{
}
struct lut *
{
(lut_cmp)tree_namecmp));
}
struct node *
{
return (struct node *)
}
struct node *
{
return (struct node *)
}
struct lut *
{
}
struct node *
{
return ((struct node *)
}
struct node *
{
return ((struct node *)
}
static struct node *
{
/* allocate parse tree node */
/*
* the global lut pointed to by lutpp (Faults, Defects, Upsets,
* Errors, Ereports, Serds, FRUs, or ASRUs) keeps the first decl.
* if this isn't the first declr, we merge the
* nvpairs into the first decl so we have a
* merged table to look up properties from.
* if this is the first time we've seen this fault,
* we add it to the global lut and start lutp
* off with any nvpairs from this declaration statement.
*/
/* this is the first time name is declared */
} else if (!justpath &&
/* this is the first time event is declared */
} else {
/* was declared before, just add new nvpairs to its lutp */
}
return (ret);
}
/*ARGSUSED*/
static void
{
L_engine);
return;
return;
}
struct node *
{
switch (t) {
case T_EVENT:
/* determine the type of event being declared */
case N_FAULT:
&Faults, Faultcount, 0);
/* increment serd statement reference */
break;
case N_UPSET:
&Upsets, Upsetcount, 0);
/* increment serd statement reference */
break;
case N_DEFECT:
&Defects, Defectcount, 0);
/* increment serd statement reference */
break;
case N_ERROR:
&Errors, Errorcount, 0);
break;
case N_EREPORT:
&Ereports, Ereportcount, 0);
/*
* Keep a lut of just the enames, so that the DE
* can subscribe to a uniqified list of event
* classes.
*/
/*
* Keep a lut of the enames (event classes) to
* silently discard if we can't find a matching
* configuration node when an ereport of of a given
* class is received. Such events are declaired
* with 'discard_if_config_unknown=1'.
*/
}
break;
default:
"tree_decl: internal error, event name type %s",
}
break;
case T_ENGINE:
/* determine the type of engine being declared */
case N_SERD:
break;
case N_STAT:
break;
default:
"tree_decl: internal error, engine name type %s",
}
break;
case T_ASRU:
break;
case T_FRU:
break;
case T_CONFIG:
/*
* config statements are different from above: they
* are not merged at all (until the configuration cache
* code does its own style of merging. and the properties
* are a free-for-all -- we don't check for allowed or
* required config properties.
*/
break;
default:
ptree_nodetype2str(t));
}
return (ret);
}
/* keep backpointers in arrows to the prop they belong to (used for scoping) */
static void
{
return;
/*
* no need to recurse right or handle T_LIST since
* T_ARROWs always cascade left and are at the top
* of the parse tree. (you can see this in the rule
* for "propbody" in escparse.y.)
*/
}
}
struct node *
{
int inlist = 0;
switch (t) {
case T_PROP:
check_proplists(t, np);
check_propnames(t, np, 0, 0);
(lut_cmp)tree_namecmp) == 0) {
inlist = 1;
break;
}
}
if (inlist == 0)
/* "Props" is a linked list of all prop statements */
if (Lastprops)
else
break;
case T_MASK:
check_proplists(t, np);
check_propnames(t, np, 0, 0);
(lut_cmp)tree_namecmp) == 0) {
inlist = 1;
break;
}
}
if (inlist == 0)
/* "Masks" is a linked list of all mask statements */
if (Lastmasks)
else
break;
default:
"tree_stmt: internal error (t %d)", t);
}
return (ret);
}
void
{
/*
* The only declarations with required properties
* currently are faults and serds. Make sure the
* the declarations have the required properties.
*/
/*
* we do this now rather than while building the parse
* tree because it is inconvenient for the user if we
* require SERD engines to be declared before used in
* an upset "engine" property.
*/
/* check for cycles */
}
/* compare two T_NAMES by only looking at components, not iterators */
int
{
}
return (0);
else
return (-1);
return (1);
else
}
int
{
int ret;
return (0);
return (-1);
return (1);
else
} else
return (ret);
}