diff options
Diffstat (limited to 'src/pmlogrewrite/gram.y')
-rw-r--r-- | src/pmlogrewrite/gram.y | 986 |
1 files changed, 986 insertions, 0 deletions
diff --git a/src/pmlogrewrite/gram.y b/src/pmlogrewrite/gram.y new file mode 100644 index 0000000..bdbb795 --- /dev/null +++ b/src/pmlogrewrite/gram.y @@ -0,0 +1,986 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 2011 Ken McDonell. All Rights Reserved. + * Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +%{ +/* + * pmlogrewrite parser + */ +#include "pmapi.h" +#include "impl.h" +#include "logger.h" +#include <errno.h> +#include <assert.h> + +static indomspec_t *current_indomspec; +static int current_star_indom; +static int do_walk_indom; +static int star_domain; + +static metricspec_t *current_metricspec; +static int current_star_metric; +static int star_cluster; +static int do_walk_metric; +static int output = OUTPUT_ALL; +static int one_inst; +static char *one_name; + +indomspec_t * +walk_indom(int mode) +{ + static indomspec_t *ip; + + if (do_walk_indom) { + if (mode == W_START) + ip = indom_root; + else + ip = ip->i_next; + while (ip != NULL && pmInDom_domain(ip->old_indom) != star_domain) + ip = ip->i_next; + } + else { + if (mode == W_START) + ip = current_indomspec; + else + ip = NULL; + } + + return ip; +} + +metricspec_t * +walk_metric(int mode, int flag, char *which) +{ + static metricspec_t *mp; + + if (do_walk_metric) { + if (mode == W_START) + mp = metric_root; + else + mp = mp->m_next; + while (mp != NULL) { + if (pmid_domain(mp->old_desc.pmid) == star_domain && + (star_cluster == PM_ID_NULL || star_cluster == pmid_cluster(mp->old_desc.pmid))) + break; + mp = mp->m_next; + } + } + else { + if (mode == W_START) + mp = current_metricspec; + else + mp = NULL; + } + + if (mp != NULL) { + if (mp->flags & flag) { + snprintf(mess, sizeof(mess), "Duplicate %s clause for metric %s", which, mp->old_name); + yyerror(mess); + } + if (flag != METRIC_DELETE) { + if (mp->flags & METRIC_DELETE) { + snprintf(mess, sizeof(mess), "Conflicting %s clause for deleted metric %s", which, mp->old_name); + yyerror(mess); + } + } + else { + if (mp->flags & (~METRIC_DELETE)) { + snprintf(mess, sizeof(mess), "Conflicting delete and other clauses for metric %s", mp->old_name); + yyerror(mess); + } + } + } + + return mp; +} + +%} + +%union { + char *str; + int ival; + double dval; + pmInDom indom; + pmID pmid; +} + +%token TOK_LBRACE + TOK_RBRACE + TOK_PLUS + TOK_MINUS + TOK_COLON + TOK_COMMA + TOK_ASSIGN + TOK_GLOBAL + TOK_INDOM + TOK_DUPLICATE + TOK_METRIC + TOK_HOSTNAME + TOK_TZ + TOK_TIME + TOK_NAME + TOK_INST + TOK_INAME + TOK_DELETE + TOK_PMID + TOK_NULL_INT + TOK_TYPE + TOK_SEM + TOK_UNITS + TOK_OUTPUT + TOK_RESCALE + +%token<str> TOK_GNAME TOK_NUMBER TOK_STRING TOK_HNAME TOK_FLOAT +%token<str> TOK_INDOM_STAR TOK_PMID_INT TOK_PMID_STAR +%token<ival> TOK_TYPE_NAME TOK_SEM_NAME TOK_SPACE_NAME TOK_TIME_NAME +%token<ival> TOK_COUNT_NAME TOK_OUTPUT_TYPE + +%type<str> hname +%type<indom> indom_int null_or_indom +%type<pmid> pmid_int pmid_or_name +%type<ival> signnumber number rescaleopt duplicateopt +%type<dval> float + +%% + +config : speclist + ; + +speclist : spec + | spec speclist + ; + +spec : globalspec + | indomspec + | metricspec + ; + +globalspec : TOK_GLOBAL TOK_LBRACE globaloptlist TOK_RBRACE + | TOK_GLOBAL TOK_LBRACE TOK_RBRACE + ; + +globaloptlist : globalopt + | globalopt globaloptlist + ; + +globalopt : TOK_HOSTNAME TOK_ASSIGN hname + { + if (global.flags & GLOBAL_CHANGE_HOSTNAME) { + snprintf(mess, sizeof(mess), "Duplicate global hostname clause"); + yyerror(mess); + } + if (strcmp(inarch.label.ll_hostname, $3) == 0) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Global hostname (%s): No change", inarch.label.ll_hostname); + yywarn(mess); + } + } + else { + strncpy(global.hostname, $3, sizeof(global.hostname)); + global.flags |= GLOBAL_CHANGE_HOSTNAME; + } + free($3); + } + | TOK_TZ TOK_ASSIGN TOK_STRING + { + if (global.flags & GLOBAL_CHANGE_TZ) { + snprintf(mess, sizeof(mess), "Duplicate global tz clause"); + yyerror(mess); + } + if (strcmp(inarch.label.ll_tz, $3) == 0) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Global timezone (%s): No change", inarch.label.ll_tz); + yywarn(mess); + } + } + else { + strncpy(global.tz, $3, sizeof(global.tz)); + global.flags |= GLOBAL_CHANGE_TZ; + } + free($3); + } + | TOK_TIME TOK_ASSIGN signtime + { + if (global.flags & GLOBAL_CHANGE_TIME) { + snprintf(mess, sizeof(mess), "Duplicate global time clause"); + yyerror(mess); + } + if (global.time.tv_sec == 0 && global.time.tv_usec == 0) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Global time: No change"); + yywarn(mess); + } + } + else + global.flags |= GLOBAL_CHANGE_TIME; + } + | TOK_HOSTNAME TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting hostname in hostname clause"); + yyerror(mess); + } + | TOK_HOSTNAME + { + snprintf(mess, sizeof(mess), "Expecting -> in hostname clause"); + yyerror(mess); + } + | TOK_TZ TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting timezone string in tz clause"); + yyerror(mess); + } + | TOK_TZ + { + snprintf(mess, sizeof(mess), "Expecting -> in tz clause"); + yyerror(mess); + } + | TOK_TIME TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting delta of the form [+-][HH:[MM:]]SS[.d...] in time clause"); + yyerror(mess); + } + | TOK_TIME + { + snprintf(mess, sizeof(mess), "Expecting -> in time clause"); + yyerror(mess); + } + ; + + /* + * ambiguity in lexical scanner ... handle here + * abc.def - is TOK_HNAME or TOK_GNAME + * 123 - is TOK_HNAME or TOK_NUMBER + * 123.456 - is TOK_HNAME or TOK_FLOAT + */ +hname : TOK_HNAME + | TOK_GNAME + | TOK_NUMBER + | TOK_FLOAT + ; + +signnumber : TOK_PLUS TOK_NUMBER + { + $$ = atoi($2); + free($2); + } + | TOK_MINUS TOK_NUMBER + { + $$ = -atoi($2); + free($2); + } + | TOK_NUMBER + { + $$ = atoi($1); + free($1); + } + ; + +number : TOK_NUMBER + { + $$ = atoi($1); + free($1); + } + ; + +float : TOK_FLOAT + { + $$ = atof($1); + free($1); + } + ; + +signtime : TOK_PLUS time + | TOK_MINUS time { global.time.tv_sec = -global.time.tv_sec; } + | time + ; + +time : number TOK_COLON number TOK_COLON float /* HH:MM:SS.d.. format */ + { + if ($3 > 59) { + snprintf(mess, sizeof(mess), "Minutes (%d) in time clause more than 59", $3); + yywarn(mess); + } + if ($5 > 59) { + snprintf(mess, sizeof(mess), "Seconds (%.6f) in time clause more than 59", $5); + yywarn(mess); + } + global.time.tv_sec = $1 * 3600 + $3 * 60 + (int)$5; + global.time.tv_usec = (int)(1000000*(($5 - (int)$5))+0.5); + } + | number TOK_COLON number TOK_COLON number /* HH:MM:SS format */ + { + if ($3 > 59) { + snprintf(mess, sizeof(mess), "Minutes (%d) in time clause more than 59", $3); + yywarn(mess); + } + if ($5 > 59) { + snprintf(mess, sizeof(mess), "Seconds (%d) in time clause more than 59", $5); + yywarn(mess); + } + global.time.tv_sec = $1 * 3600 + $3 * 60 + $5; + } + | number TOK_COLON float /* MM:SS.d.. format */ + { + if ($1 > 59) { + snprintf(mess, sizeof(mess), "Minutes (%d) in time clause more than 59", $1); + yywarn(mess); + } + if ($3 > 59) { + snprintf(mess, sizeof(mess), "Seconds (%.6f) in time clause more than 59", $3); + yywarn(mess); + } + global.time.tv_sec = $1 * 60 + (int)$3; + global.time.tv_usec = (int)(1000000*(($3 - (int)$3))+0.5); + } + | number TOK_COLON number /* MM:SS format */ + { + if ($1 > 59) { + snprintf(mess, sizeof(mess), "Minutes (%d) in time clause more than 59", $1); + yywarn(mess); + } + if ($3 > 59) { + snprintf(mess, sizeof(mess), "Seconds (%d) in time clause more than 59", $3); + yywarn(mess); + } + global.time.tv_sec = $1 * 60 + $3; + } + | float /* SS.d.. format */ + { + if ($1 > 59) { + snprintf(mess, sizeof(mess), "Seconds (%.6f) in time clause more than 59", $1); + yywarn(mess); + } + global.time.tv_sec = (int)$1; + global.time.tv_usec = (int)(1000000*(($1 - (int)$1))+0.5); + } + | number /* SS format */ + { + if ($1 > 59) { + snprintf(mess, sizeof(mess), "Seconds (%d) in time clause more than 59", $1); + yywarn(mess); + } + global.time.tv_sec = $1; + global.time.tv_usec = 0; + } + ; + +indomspec : TOK_INDOM indom_int + { + if (current_star_indom) { + __pmContext *ctxp; + __pmHashCtl *hcp; + __pmHashNode *node; + + ctxp = __pmHandleToPtr(pmWhichContext()); + assert(ctxp != NULL); + hcp = &ctxp->c_archctl->ac_log->l_hashindom; + star_domain = pmInDom_domain($2); + for (node = __pmHashWalk(hcp, PM_HASH_WALK_START); + node != NULL; + node = __pmHashWalk(hcp, PM_HASH_WALK_NEXT)) { + if (pmInDom_domain((pmInDom)(node->key)) == star_domain) + current_indomspec = start_indom((pmInDom)(node->key)); + } + do_walk_indom = 1; + } + else { + current_indomspec = start_indom($2); + do_walk_indom = 0; + } + } + TOK_LBRACE optindomopt TOK_RBRACE + | TOK_INDOM + { + snprintf(mess, sizeof(mess), "Expecting <domain>.<serial> or <domain>.* in indom rule"); + yyerror(mess); + } + ; + +indom_int : TOK_FLOAT + { + int domain; + int serial; + int sts; + sts = sscanf($1, "%d.%d", &domain, &serial); + if (sts < 2) { + snprintf(mess, sizeof(mess), "Missing serial field for indom"); + yyerror(mess); + } + if (domain < 1 || domain >= DYNAMIC_PMID) { + snprintf(mess, sizeof(mess), "Illegal domain field (%d) for indom", domain); + yyerror(mess); + } + if (serial < 0 || serial >= 4194304) { + snprintf(mess, sizeof(mess), "Illegal serial field (%d) for indom", serial); + yyerror(mess); + } + current_star_indom = 0; + free($1); + $$ = pmInDom_build(domain, serial); + } + | TOK_INDOM_STAR + { + int domain; + sscanf($1, "%d.", &domain); + if (domain < 1 || domain >= DYNAMIC_PMID) { + snprintf(mess, sizeof(mess), "Illegal domain field (%d) for indom", domain); + yyerror(mess); + } + current_star_indom = 1; + free($1); + $$ = pmInDom_build(domain, 0); + } + ; + +optindomopt : indomoptlist + | + ; + +indomoptlist : indomopt + | indomopt indomoptlist + ; + +indomopt : TOK_INDOM TOK_ASSIGN duplicateopt indom_int + { + indomspec_t *ip; + for (ip = walk_indom(W_START); ip != NULL; ip = walk_indom(W_NEXT)) { + pmInDom indom; + if (indom_root->new_indom != indom_root->old_indom) { + snprintf(mess, sizeof(mess), "Duplicate indom clause for indom %s", pmInDomStr(indom_root->old_indom)); + yyerror(mess); + } + if (current_star_indom) + indom = pmInDom_build(pmInDom_domain($4), pmInDom_serial(ip->old_indom)); + else + indom = $4; + if (indom != ip->old_indom) + ip->new_indom = indom; + else { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Instance domain %s: indom: No change", pmInDomStr(ip->old_indom)); + yywarn(mess); + } + } + ip->indom_flags |= $3; + } + } + | TOK_INAME TOK_STRING TOK_ASSIGN TOK_STRING + { + indomspec_t *ip; + for (ip = walk_indom(W_START); ip != NULL; ip = walk_indom(W_NEXT)) { + if (change_inst_by_name(ip->old_indom, $2, $4) < 0) + yyerror(mess); + } + free($2); + /* Note: $4 referenced from new_iname[] */ + } + | TOK_INAME TOK_STRING TOK_ASSIGN TOK_DELETE + { + indomspec_t *ip; + for (ip = walk_indom(W_START); ip != NULL; ip = walk_indom(W_NEXT)) { + if (change_inst_by_name(ip->old_indom, $2, NULL) < 0) + yyerror(mess); + } + free($2); + } + | TOK_INST number TOK_ASSIGN number + { + indomspec_t *ip; + for (ip = walk_indom(W_START); ip != NULL; ip = walk_indom(W_NEXT)) { + if (change_inst_by_inst(ip->old_indom, $2, $4) < 0) + yyerror(mess); + } + } + | TOK_INST number TOK_ASSIGN TOK_DELETE + { + indomspec_t *ip; + for (ip = walk_indom(W_START); ip != NULL; ip = walk_indom(W_NEXT)) { + if (change_inst_by_inst(ip->old_indom, $2, PM_IN_NULL) < 0) + yyerror(mess); + } + } + | TOK_INDOM TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting <domain>.<serial> or <domain>.* in indom clause"); + yyerror(mess); + } + | TOK_INDOM + { + snprintf(mess, sizeof(mess), "Expecting -> in indom clause"); + yyerror(mess); + } + | TOK_INAME TOK_STRING TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting new external instance name string or DELETE in iname clause"); + yyerror(mess); + } + | TOK_INAME TOK_STRING + { + snprintf(mess, sizeof(mess), "Expecting -> in iname clause"); + yyerror(mess); + } + | TOK_INAME + { + snprintf(mess, sizeof(mess), "Expecting old external instance name string in iname clause"); + yyerror(mess); + } + | TOK_INST number TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting new internal instance identifier or DELETE in inst clause"); + yyerror(mess); + } + | TOK_INST number + { + snprintf(mess, sizeof(mess), "Expecting -> in inst clause"); + yyerror(mess); + } + | TOK_INST + { + snprintf(mess, sizeof(mess), "Expecting old internal instance identifier in inst clause"); + yyerror(mess); + } + ; + +duplicateopt : TOK_DUPLICATE { $$ = INDOM_DUPLICATE; } + | { $$ = 0; } + ; + +metricspec : TOK_METRIC pmid_or_name + { + if (current_star_metric) { + __pmContext *ctxp; + __pmHashCtl *hcp; + __pmHashNode *node; + + ctxp = __pmHandleToPtr(pmWhichContext()); + assert(ctxp != NULL); + hcp = &ctxp->c_archctl->ac_log->l_hashpmid; + star_domain = pmid_domain($2); + if (current_star_metric == 1) + star_cluster = pmid_cluster($2); + else + star_cluster = PM_ID_NULL; + for (node = __pmHashWalk(hcp, PM_HASH_WALK_START); + node != NULL; + node = __pmHashWalk(hcp, PM_HASH_WALK_NEXT)) { + if (pmid_domain((pmID)(node->key)) == star_domain && + (star_cluster == PM_ID_NULL || + star_cluster == pmid_cluster((pmID)(node->key)))) + current_metricspec = start_metric((pmID)(node->key)); + } + do_walk_metric = 1; + } + else { + if ($2 == PM_ID_NULL) + /* metric not in archive */ + current_metricspec = NULL; + else + current_metricspec = start_metric($2); + do_walk_metric = 0; + } + } + TOK_LBRACE optmetricoptlist TOK_RBRACE + | TOK_METRIC + { + snprintf(mess, sizeof(mess), "Expecting metric name or <domain>.<cluster>.<item> or <domain>.<cluster>.* or <domain>.*.* in metric rule"); + yyerror(mess); + } + ; + +pmid_or_name : pmid_int + | TOK_GNAME + { + int sts; + pmID pmid; + sts = pmLookupName(1, &$1, &pmid); + if (sts < 0) { + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s: %s", $1, pmErrStr(sts)); + yywarn(mess); + } + pmid = PM_ID_NULL; + } + current_star_metric = 0; + free($1); + $$ = pmid; + } + ; + +pmid_int : TOK_PMID_INT + { + int domain; + int cluster; + int item; + int sts; + sts = sscanf($1, "%d.%d.%d", &domain, &cluster, &item); + assert(sts == 3); + if (domain < 1 || domain >= DYNAMIC_PMID) { + snprintf(mess, sizeof(mess), "Illegal domain field (%d) for pmid", domain); + yyerror(mess); + } + if (cluster < 0 || cluster >= 4096) { + snprintf(mess, sizeof(mess), "Illegal cluster field (%d) for pmid", cluster); + yyerror(mess); + } + if (item < 0 || item >= 1024) { + snprintf(mess, sizeof(mess), "Illegal item field (%d) for pmid", item); + yyerror(mess); + } + current_star_metric = 0; + free($1); + $$ = pmid_build(domain, cluster, item); + } + | TOK_PMID_STAR + { + int domain; + int cluster; + int sts; + sts = sscanf($1, "%d.%d.", &domain, &cluster); + if (domain < 1 || domain >= DYNAMIC_PMID) { + snprintf(mess, sizeof(mess), "Illegal domain field (%d) for pmid", domain); + yyerror(mess); + } + if (sts == 2) { + if (cluster >= 4096) { + snprintf(mess, sizeof(mess), "Illegal cluster field (%d) for pmid", cluster); + yyerror(mess); + } + current_star_metric = 1; + } + else { + cluster = 0; + current_star_metric = 2; + } + free($1); + $$ = pmid_build(domain, cluster, 0); + } + ; + +optmetricoptlist : metricoptlist + | /* nothing */ + ; + +metricoptlist : metricopt + | metricopt metricoptlist + ; + +metricopt : TOK_PMID TOK_ASSIGN pmid_int + { + metricspec_t *mp; + pmID pmid; + for (mp = walk_metric(W_START, METRIC_CHANGE_PMID, "pmid"); mp != NULL; mp = walk_metric(W_NEXT, METRIC_CHANGE_PMID, "pmid")) { + if (current_star_metric == 1) + pmid = pmid_build(pmid_domain($3), pmid_cluster($3), pmid_item(mp->old_desc.pmid)); + else if (current_star_metric == 2) + pmid = pmid_build(pmid_domain($3), pmid_cluster(mp->old_desc.pmid), pmid_item(mp->old_desc.pmid)); + else + pmid = $3; + if (pmid == mp->old_desc.pmid) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s (%s): pmid: No change", mp->old_name, pmIDStr(mp->old_desc.pmid)); + yywarn(mess); + } + } + else { + mp->new_desc.pmid = pmid; + mp->flags |= METRIC_CHANGE_PMID; + } + } + } + | TOK_NAME TOK_ASSIGN TOK_GNAME + { + metricspec_t *mp; + for (mp = walk_metric(W_START, METRIC_CHANGE_NAME, "name"); mp != NULL; mp = walk_metric(W_NEXT, METRIC_CHANGE_NAME, "name")) { + if (strcmp($3, mp->old_name) == 0) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s (%s): name: No change", mp->old_name, pmIDStr(mp->old_desc.pmid)); + yywarn(mess); + } + } + else { + int sts; + pmID pmid; + sts = pmLookupName(1, &$3, &pmid); + if (sts >= 0) { + snprintf(mess, sizeof(mess), "Metric name %s already assigned for PMID %s", $3, pmIDStr(pmid)); + yyerror(mess); + } + mp->new_name = $3; + mp->flags |= METRIC_CHANGE_NAME; + } + } + } + | TOK_TYPE TOK_ASSIGN TOK_TYPE_NAME + { + metricspec_t *mp; + for (mp = walk_metric(W_START, METRIC_CHANGE_TYPE, "type"); mp != NULL; mp = walk_metric(W_NEXT, METRIC_CHANGE_TYPE, "type")) { + if ($3 == mp->old_desc.type) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s (%s): type: PM_TYPE_%s: No change", mp->old_name, pmIDStr(mp->old_desc.pmid), pmTypeStr(mp->old_desc.type)); + yywarn(mess); + } + } + else { + if (mp->old_desc.type == PM_TYPE_32 || + mp->old_desc.type == PM_TYPE_U32 || + mp->old_desc.type == PM_TYPE_64 || + mp->old_desc.type == PM_TYPE_U64 || + mp->old_desc.type == PM_TYPE_FLOAT || + mp->old_desc.type == PM_TYPE_DOUBLE) { + mp->new_desc.type = $3; + mp->flags |= METRIC_CHANGE_TYPE; + } + else { + snprintf(mess, sizeof(mess), "Old type (PM_TYPE_%s) must be numeric", pmTypeStr(mp->old_desc.type)); + yyerror(mess); + } + } + } + } + | TOK_INDOM TOK_ASSIGN null_or_indom pick + { + metricspec_t *mp; + pmInDom indom; + for (mp = walk_metric(W_START, METRIC_CHANGE_INDOM, "indom"); mp != NULL; mp = walk_metric(W_NEXT, METRIC_CHANGE_INDOM, "indom")) { + if (current_star_indom) + indom = pmInDom_build(pmInDom_domain($3), pmInDom_serial(mp->old_desc.indom)); + else + indom = $3; + if (indom == mp->old_desc.indom) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s (%s): indom: %s: No change", mp->old_name, pmIDStr(mp->old_desc.pmid), pmInDomStr(mp->old_desc.indom)); + yywarn(mess); + } + } + else { + if ((output == OUTPUT_MIN || + output == OUTPUT_MAX || + output == OUTPUT_SUM || + output == OUTPUT_AVG) && + mp->old_desc.type != PM_TYPE_32 && + mp->old_desc.type != PM_TYPE_U32 && + mp->old_desc.type != PM_TYPE_64 && + mp->old_desc.type != PM_TYPE_U64 && + mp->old_desc.type != PM_TYPE_FLOAT && + mp->old_desc.type != PM_TYPE_DOUBLE) { + snprintf(mess, sizeof(mess), "OUTPUT option MIN, MAX, AVG or SUM requires type to be numeric, not PM_TYPE_%s", pmTypeStr(mp->old_desc.type)); + yyerror(mess); + } + mp->new_desc.indom = indom; + mp->flags |= METRIC_CHANGE_INDOM; + mp->output = output; + if (output == OUTPUT_ONE) { + mp->one_name = one_name; + mp->one_inst = one_inst; + if (mp->old_desc.indom == PM_INDOM_NULL) + /* + * singular input, pick first (only) + * value, not one_inst matching ... + * one_inst used for output instance + * id + */ + mp->output = OUTPUT_FIRST; + } + if (output == OUTPUT_ALL) { + /* + * No OUTPUT clause, set up the defaults + * based on indom types: + * non-NULL -> NULL + * OUTPUT_FIRST, inst PM_IN_NULL + * NULL -> non-NULL + * OUTPUT_FIRST, inst 0 + * non-NULL -> non-NULL + * all instances selected + * (nothing to do for defaults) + * NULL -> NULL + * caught above in no change case + */ + if (mp->old_desc.indom != PM_INDOM_NULL && + mp->new_desc.indom == PM_INDOM_NULL) { + mp->output = OUTPUT_FIRST; + mp->one_inst = PM_IN_NULL; + } + else if (mp->old_desc.indom == PM_INDOM_NULL && + mp->new_desc.indom != PM_INDOM_NULL) { + mp->output = OUTPUT_FIRST; + mp->one_inst = 0; + } + } + } + } + output = OUTPUT_ALL; /* for next time */ + } + | TOK_SEM TOK_ASSIGN TOK_SEM_NAME + { + metricspec_t *mp; + for (mp = walk_metric(W_START, METRIC_CHANGE_SEM, "sem"); mp != NULL; mp = walk_metric(W_NEXT, METRIC_CHANGE_SEM, "sem")) { + if ($3 == mp->old_desc.sem) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s (%s): sem: %s: No change", mp->old_name, pmIDStr(mp->old_desc.pmid), SemStr(mp->old_desc.sem)); + yywarn(mess); + } + } + else { + mp->new_desc.sem = $3; + mp->flags |= METRIC_CHANGE_SEM; + } + } + } + | TOK_UNITS TOK_ASSIGN signnumber TOK_COMMA signnumber TOK_COMMA signnumber TOK_COMMA TOK_SPACE_NAME TOK_COMMA TOK_TIME_NAME TOK_COMMA TOK_COUNT_NAME rescaleopt + { + metricspec_t *mp; + for (mp = walk_metric(W_START, METRIC_CHANGE_UNITS, "units"); mp != NULL; mp = walk_metric(W_NEXT, METRIC_CHANGE_UNITS, "units")) { + if ($3 == mp->old_desc.units.dimSpace && + $5 == mp->old_desc.units.dimTime && + $7 == mp->old_desc.units.dimCount && + $9 == mp->old_desc.units.scaleSpace && + $11 == mp->old_desc.units.scaleTime && + $13 == mp->old_desc.units.scaleCount) { + /* no change ... */ + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s (%s): units: %s: No change", mp->old_name, pmIDStr(mp->old_desc.pmid), pmUnitsStr(&mp->old_desc.units)); + yywarn(mess); + } + } + else { + mp->new_desc.units.dimSpace = $3; + mp->new_desc.units.dimTime = $5; + mp->new_desc.units.dimCount = $7; + mp->new_desc.units.scaleSpace = $9; + mp->new_desc.units.scaleTime = $11; + mp->new_desc.units.scaleCount = $13; + mp->flags |= METRIC_CHANGE_UNITS; + if ($14 == 1) { + if ($3 == mp->old_desc.units.dimSpace && + $5 == mp->old_desc.units.dimTime && + $7 == mp->old_desc.units.dimCount) + /* OK, no dim changes */ + mp->flags |= METRIC_RESCALE; + else { + if (wflag) { + snprintf(mess, sizeof(mess), "Metric: %s (%s): Dimension changed, cannot rescale", mp->old_name, pmIDStr(mp->old_desc.pmid)); + yywarn(mess); + } + } + } + else if (sflag) { + if ($3 == mp->old_desc.units.dimSpace && + $5 == mp->old_desc.units.dimTime && + $7 == mp->old_desc.units.dimCount) + mp->flags |= METRIC_RESCALE; + } + } + } + } + | TOK_DELETE + { + metricspec_t *mp; + for (mp = walk_metric(W_START, METRIC_DELETE, "delete"); mp != NULL; mp = walk_metric(W_NEXT, METRIC_DELETE, "delete")) { + mp->flags |= METRIC_DELETE; + } + } + | TOK_PMID TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting <domain>.<cluster>.<item> or <domain>.<cluster>.* or <domain>.*.* in pmid clause"); + yyerror(mess); + } + | TOK_NAME TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting metric name in iname clause"); + yyerror(mess); + } + | TOK_TYPE TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting XXX (from PM_TYPE_XXX) in type clause"); + yyerror(mess); + } + | TOK_INDOM TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting <domain>.<serial> or NULL in indom clause"); + yyerror(mess); + } + | TOK_SEM TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting XXX (from PM_SEM_XXX) in sem clause"); + yyerror(mess); + } + | TOK_UNITS TOK_ASSIGN + { + snprintf(mess, sizeof(mess), "Expecting 3 numeric values for dim* fields of units"); + yyerror(mess); + } + | TOK_UNITS TOK_ASSIGN signnumber TOK_COMMA signnumber TOK_COMMA signnumber TOK_COMMA + { + snprintf(mess, sizeof(mess), "Expecting 0 or XXX (from PM_SPACE_XXX) for scaleSpace field of units"); + yyerror(mess); + } + | TOK_UNITS TOK_ASSIGN signnumber TOK_COMMA signnumber TOK_COMMA signnumber TOK_COMMA TOK_SPACE_NAME TOK_COMMA + { + snprintf(mess, sizeof(mess), "Expecting 0 or XXX (from PM_TIME_XXX) for scaleTime field of units"); + yyerror(mess); + } + | TOK_UNITS TOK_ASSIGN signnumber TOK_COMMA signnumber TOK_COMMA signnumber TOK_COMMA TOK_SPACE_NAME TOK_COMMA TOK_TIME_NAME TOK_COMMA + { + snprintf(mess, sizeof(mess), "Expecting 0 or ONE for scaleCount field of units"); + yyerror(mess); + } + ; + +null_or_indom : indom_int + | TOK_NULL_INT + { + $$ = PM_INDOM_NULL; + } + ; + +pick : TOK_OUTPUT TOK_INST number + { + output = OUTPUT_ONE; + one_inst = $3; + one_name = NULL; + } + | TOK_OUTPUT TOK_INAME TOK_STRING + { + output = OUTPUT_ONE; + one_inst = PM_IN_NULL; + one_name = $3; + } + | TOK_OUTPUT TOK_OUTPUT_TYPE + { + output = $2; + } + | TOK_OUTPUT + { + snprintf(mess, sizeof(mess), "Expecting FIRST or LAST or INST or INAME or MIN or MAX or AVG for OUTPUT instance option"); + yyerror(mess); + } + | /* nothing */ + ; + +rescaleopt : TOK_RESCALE { $$ = 1; } + | /* nothing */ + { $$ = 0; } + ; + +%% |