%{
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* or http://www.opensolaris.org/os/licensing.
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* FMA Event Injector language parser
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <inj.h>
#include <inj_err.h>
#include <inj_event.h>
#include <inj_hash.h>
#include <inj_lex.h>
%}
%union {
inj_decl_t *l_decl;
inj_declmem_t *l_declmem;
inj_defn_t *l_defn;
inj_defnmem_t *l_defnmem;
inj_cmd_t *l_command;
inj_randelem_t *l_randelem;
inj_hash_t *l_hash;
char *l_string;
uint_t l_number;
hrtime_t l_hrtime;
}
%type <l_decl> decl_memlist
%type <l_declmem> decl_mem
%type <l_declmem> decl_baremem
%type <l_declmem> decl_mem_intr
%type <l_number> decl_intr_type
%type <l_number> decl_arraydim
%type <l_declmem> decl_mem_cplx
%type <l_hash> decl_enumlist
%type <l_defn> defn_memlist
%type <l_defnmem> defn_memvals
%type <l_defnmem> defn_val
%type <l_command> command
%type <l_command> cmd_repeatable
%type <l_randelem> rand_problist
%type <l_randelem> rand_element
%type <l_defn> defined_event
%type <l_number> number
%type <l_hrtime> hrtime
%token INJ_TOK_EVDEF
%token INJ_TOK_FMRIDEF
%token INJ_TOK_AUTHDEF
%token INJ_TOK_LISTDEF
%token INJ_TOK_INT8
%token INJ_TOK_INT16
%token INJ_TOK_INT32
%token INJ_TOK_INT64
%token INJ_TOK_UINT8
%token INJ_TOK_UINT16
%token INJ_TOK_UINT32
%token INJ_TOK_UINT64
%token INJ_TOK_BOOLEAN
%token INJ_TOK_STRING
%token INJ_TOK_ENUM
%token INJ_TOK_EVENT
%token INJ_TOK_FMRI
%token INJ_TOK_AUTH
%token INJ_TOK_LIST
%token INJ_TOK_ADDHRT
%token INJ_TOK_ENDHRT
%token INJ_TOK_SLEEP
%token INJ_TOK_REPEAT
%token INJ_TOK_RANDOMIZE
%token <l_string> INJ_TOK_IDENT
%token <l_string> INJ_TOK_FMACLASS
%token <l_string> INJ_TOK_IMM
%token <l_string> INJ_TOK_QSTRING
%%
statement_list: /* EMPTY */
| statement_list statement ';'
;
statement: decl
| defn
| command {
if ($1 != NULL)
inj_cmds_add($1);
}
;
/*
* Event, FMRI, Authority, and list declarations
*/
decl: INJ_TOK_EVDEF INJ_TOK_FMACLASS '{' decl_memlist '}' {
if ($4 != NULL)
inj_decl_finish($4, $2, ITEMTYPE_EVENT);
}
| INJ_TOK_FMRIDEF INJ_TOK_IDENT '{' decl_memlist '}' {
if ($4 != NULL)
inj_decl_finish($4, $2, ITEMTYPE_FMRI);
}
| INJ_TOK_AUTHDEF INJ_TOK_IDENT '{' decl_memlist '}' {
if ($4 != NULL)
inj_decl_finish($4, $2, ITEMTYPE_AUTH);
}
| INJ_TOK_LISTDEF INJ_TOK_IDENT '{' decl_memlist '}' {
if ($4 != NULL)
inj_decl_finish($4, $2, ITEMTYPE_LIST);
}
;
decl_memlist: /* EMPTY */ { $$ = NULL; }
| decl_memlist decl_mem ';' {
if ($2 == NULL) {
$$ = $1;
} else if ($1 == NULL) {
$$ = inj_decl_create($2);
} else {
inj_decl_addmem($1, $2);
$$ = $1;
}
}
;
decl_mem: decl_baremem
| decl_baremem decl_arraydim {
if ($1 != NULL)
inj_decl_mem_make_array($1, $2);
$$ = $1;
}
;
decl_baremem: decl_mem_intr
| decl_mem_cplx
;
decl_mem_intr: decl_intr_type INJ_TOK_IDENT {
$$ = inj_decl_mem_create($2, $1);
}
;
decl_intr_type: INJ_TOK_INT8 { $$ = MEMTYPE_INT8; }
| INJ_TOK_INT16 { $$ = MEMTYPE_INT16; }
| INJ_TOK_INT32 { $$ = MEMTYPE_INT32; }
| INJ_TOK_INT64 { $$ = MEMTYPE_INT64; }
| INJ_TOK_UINT8 { $$ = MEMTYPE_UINT8; }
| INJ_TOK_UINT16 { $$ = MEMTYPE_UINT16; }
| INJ_TOK_UINT32 { $$ = MEMTYPE_UINT32; }
| INJ_TOK_UINT64 { $$ = MEMTYPE_UINT64; }
| INJ_TOK_BOOLEAN { $$ = MEMTYPE_BOOL; }
| INJ_TOK_STRING { $$ = MEMTYPE_STRING; }
;
decl_arraydim: '[' number ']' {
$$ = $2;
}
| '[' ']' {
$$ = 0;
}
;
decl_mem_cplx: INJ_TOK_ENUM INJ_TOK_IDENT '{' decl_enumlist '}' {
$$ = inj_decl_mem_create_enum($2, $4);
}
| INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT {
$$ = inj_decl_mem_create_defined($3, $2,
ITEMTYPE_EVENT);
}
| INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT {
$$ = inj_decl_mem_create_defined($3, $2,
ITEMTYPE_FMRI);
}
| INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT {
$$ = inj_decl_mem_create_defined($3, $2,
ITEMTYPE_AUTH);
}
| INJ_TOK_LIST INJ_TOK_IDENT INJ_TOK_IDENT {
$$ = inj_decl_mem_create_defined($3, $2,
ITEMTYPE_LIST);
}
;
decl_enumlist: INJ_TOK_IDENT {
$$ = inj_zalloc(sizeof (inj_hash_t));
inj_strhash_create($$);
inj_strhash_insert($$, $1, 1);
}
| decl_enumlist ',' INJ_TOK_IDENT {
if (inj_strhash_lookup($1, $3) != NULL)
yyerror("duplicate enum value \"%s\"", $3);
else
inj_strhash_insert($1, $3, 1);
$$ = $1;
}
;
/*
* Event, FMRI, Authority, and list definitions
*/
defn: INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT '='
'{' defn_memlist '}' {
inj_defn_finish($6, $2, $3, ITEMTYPE_EVENT);
inj_strfree($2);
}
| INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT '='
'{' defn_memlist '}' {
inj_defn_finish($6, $2, $3, ITEMTYPE_FMRI);
inj_strfree($2);
}
| INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT '='
'{' defn_memlist '}' {
inj_defn_finish($6, $2, $3, ITEMTYPE_AUTH);
inj_strfree($2);
}
;
defn_memlist: defn_memvals {
$$ = inj_defn_create($1);
}
| defn_memlist ',' defn_memvals {
inj_defn_addmem($1, $3);
$$ = $1;
}
;
defn_memvals: defn_val
| INJ_TOK_EVENT INJ_TOK_FMACLASS {
$$ = inj_defn_mem_create($2, DEFNMEM_EVENT);
}
| INJ_TOK_FMRI INJ_TOK_IDENT {
$$ = inj_defn_mem_create($2, DEFNMEM_FMRI);
}
| INJ_TOK_AUTH INJ_TOK_IDENT {
$$ = inj_defn_mem_create($2, DEFNMEM_AUTH);
}
| '[' defn_memlist ']' {
$$ = inj_defn_mem_create_list($2, DEFNMEM_ARRAY);
}
| '{' defn_memlist '}' {
$$ = inj_defn_mem_create_list($2, DEFNMEM_LIST);
}
;
defn_val: INJ_TOK_IMM {
$$ = inj_defn_mem_create($1, DEFNMEM_IMM);
}
| INJ_TOK_IDENT {
$$ = inj_defn_mem_create($1, DEFNMEM_IDENT);
}
| INJ_TOK_QSTRING {
$$ = inj_defn_mem_create($1, DEFNMEM_QSTRING);
}
;
/*
* Commands
*/
command: cmd_repeatable
| INJ_TOK_ADDHRT hrtime { $$ = inj_cmd_addhrt($2); }
| INJ_TOK_ENDHRT { $$ = inj_cmd_endhrt(); }
| INJ_TOK_SLEEP number { $$ = inj_cmd_sleep($2); }
| INJ_TOK_REPEAT number cmd_repeatable {
$$ = ($3 == NULL ? NULL : inj_cmd_repeat($3, $2));
}
;
cmd_repeatable: defined_event {
$$ = ($1 == NULL ? NULL : inj_cmd_send($1));
}
| INJ_TOK_RANDOMIZE '{' rand_problist '}' {
$$ = ($3 == NULL ? NULL : inj_cmd_rand($3));
}
;
rand_problist: rand_element
| rand_problist ',' rand_element {
$$ = ($1 == NULL || $3 == NULL) ?
NULL : inj_rand_add($1, $3);
}
;
rand_element: '{' defined_event ',' number '}' {
$$ = ($2 == NULL ? NULL : inj_rand_create($2, $4));
}
;
defined_event: INJ_TOK_IDENT {
inj_defn_t *ev;
if ((ev = inj_defn_lookup($1, MEMTYPE_EVENT)) ==
NULL) {
yyerror("unknown event \"%s\"\n", $1);
$$ = NULL;
} else
$$ = ev;
}
number: INJ_TOK_IMM {
u_longlong_t val;
if (inj_strtoull($1, 32, &val) < 0) {
yyerror("invalid number");
$$ = 0;
} else
$$ = (uint32_t)val;
}
hrtime: INJ_TOK_IMM INJ_TOK_IDENT {
longlong_t val;
if (inj_strtoll($1, 64, &val) < 0 ||
inj_strtime(&val, $2) < 0) {
yyerror("invalid time");
$$ = 0;
} else
$$ = val;
}
%%
inj_list_t *
inj_program_read(const char *file)
{
if (strcmp(file, "-") == 0) {
yyin = stdin;
yyinname = "stdin";
} else {
if ((yyin = fopen(file, "r")) == NULL)
die("failed to open %s", file);
yyinname = strrchr(file, '/');
if (yyinname != NULL)
yyinname++;
else
yyinname = file;
}
yyreset();
(void) yyparse();
if (yyin != stdin)
(void) fclose(yyin);
if (yynerrors != 0) {
die("parsing failed - %d error%s\n", yynerrors,
(yynerrors > 1 ? "s" : ""));
}
return (inj_cmds_get());
}