%{ /* ** L2 - OSSP Logging Library ** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) ** ** This file is part of OSSP L2, a flexible logging library which ** can be found at http://www.ossp.org/pkg/l2/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** l2_spec_parse.y: GNU Bison (Yacc-style) parser specification ** ** ATTENTION: This requires GNU Bison 1.30 or newer! */ #include "l2.h" /* for l2_xxx() API */ #include "l2_spec.h" /* for l2_spec_ctx_t */ /* make sure yyparse() accepts a context pointer and passes through its inlined scanner context to yylex() */ #define CTX ((l2_spec_ctx_t *)ctx) #define YYPARSE_PARAM ctx #define YYLEX_PARAM CTX->yyscan /* provide an explicit prototype for the yylex() function but use "void *" instead of correct type because at this point in the generation process we have the types still not available */ extern int yylex(/*YYSTYPE*/ void *lvalp, /*YYLTYPE*/ void *llocp, l2_spec_ctx_t *ctx); /* generate verbose error messages and remember them inside the context */ #undef yyerror #define yyerror(msg) \ l2_spec_error(CTX, L2_ERR_SYN, &yylloc, msg) #define YYERROR_VERBOSE /* scanner state transition */ extern void l2_spec_scan_push(l2_spec_ctx_t *, const char *state); extern void l2_spec_scan_pop(l2_spec_ctx_t *); %} /* parser options */ %pure_parser %locations %defines /* the YYSTYPE: parser token value */ %union { char *cpValue; l2_channel_t *chChannel; unsigned int nLevels; } /* assign YYSTYPE elements to parser rules */ %type stream %type streams %type channel %type channel_cons %type channel_level %type channel_level_mask /* list of scanner tokens */ %token T_ID %token T_PARAM %token T_STRING %token T_OP_ARROW /* operator association */ %right T_OP_ARROW /* grammar start rule (technically redundant but explicit to be sure) */ %start tree %% /* channel tree */ tree : stream { CTX->ch = $1; } ; /* stream of channels */ stream : channel { $$ = $1; } | channel T_OP_ARROW stream { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $3, NULL)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link parent with child"); YYERROR; } } | channel T_OP_ARROW '{' streams '}' { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $4, NULL)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link parent with child list"); YYERROR; } } ; /* list of sibling streams */ streams : stream { $$ = $1; } | stream ';' streams { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_SIBLING, $3, NULL)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link childs together"); YYERROR; } } ; /* channel */ channel : channel_level '/' channel_level ':' channel_cons { $$ = $5; if ((CTX->rv = l2_channel_levels($5, $1, $3)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to set channel write and flush levels"); YYERROR; } } | channel_level ':' channel_cons { $$ = $3; if ((CTX->rv = l2_channel_levels($3, $1, L2_LEVEL_NONE)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to set channel write levels"); YYERROR; } } | channel_cons { $$ = $1; } ; /* channel level */ channel_level : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); YYERROR; } $$ = L2_LEVEL_UPTO(levelmask); } | '(' channel_level_mask ')' { $$ = $2; } ; /* channel level mask */ channel_level_mask : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); YYERROR; } $$ = levelmask; } | T_ID '|' channel_level_mask { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); YYERROR; } $$ = levelmask | $3; } ; /* channel constructor */ channel_cons : T_ID { l2_channel_t *ch; if ((CTX->rv = l2_channel_create(&ch, CTX->env, $1)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to create channel '%s'", $1); YYERROR; } $$ = ch; /* provide channel to channel_param rule below because it does not know where on the token stack our $$ is because it is a sub-rule of the recursive channel_param_list rule and hence cannot use "$-n". */ CTX->chTmp = ch; } channel_params { $$ = $2; /* pass-through result */ CTX->chTmp = NULL; } ; /* channel parameters */ channel_params : /* empty */ | '(' ')' | '(' channel_param_list ')' ; /* channel parameter list */ channel_param_list : channel_param | channel_param ',' channel_param_list ; /* channel parameter */ channel_param : T_ID '=' { l2_spec_scan_push(CTX, "SS_PARAM"); } T_PARAM { l2_spec_scan_pop(CTX); } { if ((CTX->rv = l2_channel_configure(CTX->chTmp, "%s=\"%s\"", $1, $4)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to configure channel with '%s=\"%s\"'", $1, $4); YYERROR; } } ; %%