ossp-pkg/l2/l2_spec_parse.y
1.2
%{
/*
** 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) \
do { l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", msg); \
CTX->rv = L2_ERR_ARG; } while (0)
#define YYERROR_VERBOSE
%}
/* 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 <chChannel> stream
%type <chChannel> streams
%type <chChannel> channel
%type <chChannel> channel_spec
%type <nLevels> channel_mask
%type <nLevels> channel_levels
/* list of scanner tokens */
%token <cpValue> T_ID
%token <cpValue> T_STRING
%token T_OP_ARROW
/* operator association */
%right T_OP_ARROW
/* grammar start rule */
%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_env_errorinfo(CTX->env, CTX->rv, "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_env_errorinfo(CTX->env, CTX->rv, "unable to link parent with child list");
YYERROR;
}
}
;
/* list of sibling streams */
streams : stream
{ $$ = $1; }
| stream ';' streams
{ $$ = $1; l2_channel_link($1, L2_LINK_SIBLING, $3, NULL); }
;
/* single channel */
channel : channel_mask '/' channel_mask ':' channel_spec
{ $$ = $5; l2_channel_levels($5, $1, $3); }
| channel_mask ':' channel_spec
{ $$ = $3; l2_channel_levels($3, $1, L2_LEVEL_NONE); }
| channel_spec
{ $$ = $1; }
;
/* channel write or flush mask */
channel_mask : T_ID
{
unsigned int levelmask;
if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) {
l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1);
YYERROR;
}
$$ = L2_LEVEL_UPTO(levelmask);
}
| '(' channel_levels ')'
{
$$ = $2;
}
;
/* list of channels in a mask */
channel_levels : T_ID
{
unsigned int levelmask;
if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) {
l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1);
YYERROR;
}
$$ = levelmask;
}
| T_ID '|' channel_levels
{
unsigned int levelmask;
if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) {
l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1);
YYERROR;
}
$$ = levelmask | $3;
}
;
/* specifcation of a single channel */
channel_spec : T_ID
{
l2_channel_t *ch;
if ((CTX->rv = l2_channel_create(&ch, CTX->env, $1)) != L2_OK) {
l2_env_errorinfo(CTX->env, CTX->rv, "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
"$<chChannel>-n". */
CTX->chTmp = ch;
}
channel_params
{
$$ = $<chChannel>2; /* pass result */
CTX->chTmp = NULL;
}
;
/* channel parameters */
channel_params : /* empty */
| '(' channel_param_list ')'
;
channel_param_list : /* empty */
| channel_param
| channel_param ',' channel_param_list
;
channel_param : T_ID '=' T_STRING
{
if ((CTX->rv = l2_channel_configure(CTX->chTmp, "%s=\"%s\"", $1, $3)) != L2_OK) {
l2_env_errorinfo(CTX->env, CTX->rv, "failed to configure channel with '%s=\"%s\"'", $1, $3);
YYERROR;
}
}
;
%%