1
0
Fork 0
arangodb/3rdParty/iresearch.build/core/iql/parser.yy

409 lines
17 KiB
Plaintext

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 by EMC Corporation, All Rights Reserved
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is EMC Corporation
///
/// @author Andrey Abramov
/// @author Vasiliy Nabatchikov
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief request C++ API and customize names and arguments
////////////////////////////////////////////////////////////////////////////////
%skeleton "glr.cc" // required since "lalr1.cc" does not suppot %glr-parser
%require "2.4"
%glr-parser
%defines
%define namespace "iresearch::iql"
%expect 7 // expect +7 shift/reduce as per bison generation of grammer below
%expect-rr 9 // expect +9 reduce/reduce as per bison generation of grammer below
%parse-param { iresearch::iql::context& ctx }
////////////////////////////////////////////////////////////////////////////////
/// @brief add to start of HH file
////////////////////////////////////////////////////////////////////////////////
%code requires {
#define YYSTYPE size_t
#if YYDEBUG
#define YYERROR_VERBOSE 1
// this is required only for %skeleton "glr.cc" since it lacks default init
// not needed for %skeleton "lalr1.cc" or without %skeleton
#define YYLTYPE iresearch::iql::location_type1
#endif
namespace iresearch {
namespace iql {
class context;
}
}
// Suppress warnings due to Bison generated code (push section, pop just below)
#if defined(_MSC_VER)
#pragma warning(disable : 4512)
#endif
// ALWAYS!!! define YYDEBUG 1 for the length of the header so as to avoid
// alignment issues when linkning without YYDEBUG agains a library that was
// built with YYDEBUG or vice versa, reverse at end of header
#undef YYDEBUG_REQUESTED
#if YYDEBUG
#define YYDEBUG_REQUESTED
#else
#undef YYDEBUG
#define YYDEBUG 1
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add to end of HH file
////////////////////////////////////////////////////////////////////////////////
%code provides {
// ALWAYS!!! define YYDEBUG 1 for the length of the header so as to avoid
// alignment issues when linkning without YYDEBUG agains a library that was
// built with YYDEBUG or vice versa, reverse at end of header
#ifdef YYDEBUG_REQUESTED
#undef YYDEBUG_REQUESTED
#else
#undef YYDEBUG
#define YYDEBUG 0
#endif
// end of suppress of warnings due to Bison generated code (pop section, push just above)
#if defined(_MSC_VER)
#pragma warning(default : 4512)
#endif
namespace iresearch {
namespace iql {
class context {
public:
// destructor
virtual ~context() = default;
// parser operations
virtual void yyerror(parser::location_type const& location, std::string const& sError) = 0;
virtual parser::token_type yylex(parser::semantic_type& value, parser::location_type& location) = 0;
// value operations
virtual parser::semantic_type sequence(parser::location_type const& location) = 0;
// node operations
virtual parser::semantic_type append(parser::semantic_type const& value, parser::location_type const& location) = 0;
virtual parser::semantic_type boost(parser::semantic_type const& value, parser::location_type const& location) = 0;
virtual parser::semantic_type function(parser::semantic_type const& name, parser::semantic_type const& args) = 0;
virtual parser::semantic_type list(parser::semantic_type const& value1, parser::semantic_type const& value2) = 0;
virtual parser::semantic_type negation(parser::semantic_type const& value) = 0;
virtual parser::semantic_type range(parser::semantic_type const& value1, bool bInclusive1, parser::semantic_type const& value2, bool bInclusive2) = 0;
// comparison operations
virtual parser::semantic_type op_eq(parser::semantic_type const& value1, parser::semantic_type const& value2) = 0;
virtual parser::semantic_type op_like(parser::semantic_type const& value1, parser::semantic_type const& value2) = 0;
// filter operations
virtual parser::semantic_type op_and(parser::semantic_type const& value1, parser::semantic_type const& value2) = 0;
virtual parser::semantic_type op_or(parser::semantic_type const& value1, parser::semantic_type const& value2) = 0;
// query operations
virtual bool addOrder(parser::semantic_type const& value, bool bAscending = true) = 0;
virtual bool setLimit(parser::semantic_type const& value) = 0;
virtual bool setQuery(parser::semantic_type const& value) = 0;
};
void debug(parser& parser, bool bEnable);
// this is required only for %skeleton "glr.cc" since it lacks default init
// not needed for %skeleton "lalr1.cc" or without %skeleton
#if YYDEBUG
class location_type1: public location {};
#endif
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add to CC file
////////////////////////////////////////////////////////////////////////////////
%code {
#define yylex(pValue, pLocation) ctx.yylex(*pValue, *pLocation)
namespace iresearch {
namespace iql {
void parser::error(parser::location_type const& location, std::string const& sError) {
ctx.yyerror(location, sError);
}
}
}
// this is required only for %skeleton "glr.cc" since it lacks default init
// but yy_symbol_print uses yylocationp->[begin|end].filename and segfaults
// not needed for %skeleton "lalr1.cc" or without %skeleton
#if YYDEBUG
static void yy_symbol_print(FILE*, int, iresearch::iql::parser::semantic_type const*, iresearch::iql::parser::location_type const*, iresearch::iql::parser&, iresearch::iql::context&);
static void yy_symbol_print(FILE* filep, int yytype, YYSTYPE const* yyvaluep, YYLTYPE const* yylocationp, iresearch::iql::parser& yyparser, iresearch::iql::context& ctx) {
iresearch::iql::parser::location_type yylocation = *yylocationp;
yylocation.begin.filename = nullptr;
yylocation.end.filename = nullptr;
yy_symbol_print(filep, yytype, yyvaluep, &yylocation, yyparser, ctx);
}
#endif
// ALWAYS!!! define YYDEBUG 1 for the length of the header so as to avoid
// alignment issues when linkning without YYDEBUG agains a library that was
// built with YYDEBUG or vice versa
// add method stub implementations here for debug methods declared in header
// since they are masked out in Bison generated code by !YYDEBUG
#if !YYDEBUG
namespace iresearch {
namespace iql {
inline void parser::yy_symbol_value_print_(int /* yytype */, const semantic_type* /* yyvaluep */, const location_type* /* yylocationp */) {}
inline void parser::yy_symbol_print_(int /* yytype */, const semantic_type* /* yyvaluep */, const location_type* /* yylocationp */) {}
}
}
#endif
// Suppress warnings due to Bison generated code (push section, pop at end of file)
#if defined(_MSC_VER)
#pragma warning(disable : 4100)
#pragma warning(disable : 4127)
#pragma warning(disable : 4244)
#pragma warning(disable : 4505)
#pragma warning(disable : 4611)
#pragma warning(disable : 4706)
#endif
}
// -----------------------------------------------------------------------------
// --SECTION-- Bison declarations
// -----------------------------------------------------------------------------
// basic tokens
%token IQL_EOF 0
%token IQL_UNKNOWN "unknown token marker"
%token IQL_SEP "token separator"
%token IQL_SEQUENCE "data sub-sequence"
// logical operators
%token IQL_NOT "negation operator"
%token IQL_EXCLAIM "exclamation mark"
%token IQL_AND "logical AND operator"
%token IQL_AMPAMP "double ampersand"
%token IQL_OR "logical OR operator"
%token IQL_PIPEPIPE "double pipe"
// comparison operators
%token IQL_NE "not equal operator"
%token IQL_LE "less than or equal operator"
%token IQL_EQ "equal operator"
%token IQL_GE "greater than or equal operator"
%token IQL_LIKE "similar operator"
// modification operators
%token IQL_ASTERISK "asterisk operator"
%token IQL_ASC "ascending sort order"
%token IQL_DESC "descending sort order"
// grammer delimiters
%token IQL_COMMA "comma"
%token IQL_SQUOTE "single quote"
%token IQL_DQUOTE "double quote"
%token IQL_LCHEVRON "left chevron '<' delimiter"
%token IQL_RCHEVRON "right chevron '>' delimiter"
%token IQL_LPAREN "left parentheses '(' delimiter"
%token IQL_RPAREN "right parentheses ')' delimiter"
%token IQL_LSBRACKET "left square bracket '[' delimiter"
%token IQL_RSBRACKET "right square bracket ']' delimiter"
// grammer tokens
%token IQL_LIMIT "result limit section header"
%token IQL_ORDER "sort order section header"
%start input
// -----------------------------------------------------------------------------
// --SECTION-- Grammar rules
// -----------------------------------------------------------------------------
%%
input:
optional_sep union order limit optional_sep { if (!ctx.setQuery($2)) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
;
optional_sep:
// empty since it is optional
| optional_sep IQL_SEP
;
union:
intersection
| union IQL_SEP IQL_OR IQL_SEP intersection { if (!($$ = ctx.op_or($1, $5))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| union optional_sep IQL_PIPEPIPE optional_sep intersection { if (!($$ = ctx.op_or($1, $5))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
;
intersection:
expression
| intersection IQL_SEP IQL_AND IQL_SEP expression { if (!($$ = ctx.op_and($1, $5))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| intersection optional_sep IQL_AMPAMP optional_sep expression { if (!($$ = ctx.op_and($1, $5))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
;
expression:
boost
| compare
| negation
| subexpression
;
boost:
plain_literal optional_sep IQL_ASTERISK optional_sep subexpression { if (!($$ = ctx.boost($5, @1))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| subexpression optional_sep IQL_ASTERISK optional_sep plain_literal { if (!($$ = ctx.boost($1, @5))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
;
negation:
IQL_NOT optional_sep subexpression { if (!($$ = ctx.negation($3))) YYERROR; @$.begin = @1.begin; @$.end = @3.end; }
| IQL_EXCLAIM optional_sep subexpression { if (!($$ = ctx.negation($3))) YYERROR; @$.begin = @1.begin; @$.end = @3.end; }
;
subexpression:
IQL_LPAREN optional_sep union optional_sep IQL_RPAREN { $$ = $3; @$.begin = @1.begin; @$.end = @5.end; }
| function
;
function:
sequence IQL_LPAREN optional_sep IQL_RPAREN { if (!($$ = ctx.function($1, $3))) YYERROR; @$.begin = @1.begin; @$.end = @4.end; }
| sequence IQL_LPAREN optional_sep function_arg_list optional_sep IQL_RPAREN { if (!($$ = ctx.function($1, $4))) YYERROR; @$.begin = @1.begin; @$.end = @6.end; }
;
function_arg:
sequence
| expression
;
function_arg_list:
function_arg
| function_arg_list list_sep function_arg { if (!($$ = ctx.list($1, $3))) YYERROR; @$.begin = @1.begin; @$.end = @3.end; }
compare:
term optional_sep IQL_LIKE optional_sep term { if (!($$ = ctx.op_like($1, $5))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_NE optional_sep term { if (!($$ = ctx.negation($$ = ctx.op_eq($1, $$ = ctx.range($5, true, $5, true))))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_LCHEVRON optional_sep term { if (!($$ = ctx.op_eq($1, $$ = ctx.range($3, true, $5, false)))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_LE optional_sep term { if (!($$ = ctx.op_eq($1, $$ = ctx.range($3, true, $5, true)))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_EQ optional_sep term { if (!($$ = ctx.op_eq($1, $$ = ctx.range($5, true, $5, true)))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_GE optional_sep term { if (!($$ = ctx.op_eq($1, $$ = ctx.range($5, true, $3, true)))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_RCHEVRON optional_sep term { if (!($$ = ctx.op_eq($1, $$ = ctx.range($5, false, $3, true)))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_NE optional_sep range { if (!($$ = ctx.negation($$ = ctx.op_eq($1, $5)))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
| term optional_sep IQL_EQ optional_sep range { if (!($$ = ctx.op_eq($1, $5))) YYERROR; @$.begin = @1.begin; @$.end = @5.end; }
;
range:
IQL_LSBRACKET optional_sep term list_sep term optional_sep IQL_RSBRACKET { if (!($$ = ctx.range($3, true, $5, true))) YYERROR; @$.begin = @1.begin; @$.end = @7.end; }
| IQL_LSBRACKET optional_sep term list_sep term optional_sep IQL_RPAREN { if (!($$ = ctx.range($3, true, $5, false))) YYERROR; @$.begin = @1.begin; @$.end = @7.end; }
| IQL_LPAREN optional_sep term list_sep term optional_sep IQL_RPAREN { if (!($$ = ctx.range($3, false, $5, false))) YYERROR; @$.begin = @1.begin; @$.end = @7.end; }
| IQL_LPAREN optional_sep term list_sep term optional_sep IQL_RSBRACKET { if (!($$ = ctx.range($3, false, $5, true))) YYERROR; @$.begin = @1.begin; @$.end = @7.end; }
;
term:
sequence
| function
;
list_sep:
optional_sep IQL_COMMA optional_sep
;
sequence:
plain_literal
| dquoted_literal
| squoted_literal
;
plain_literal:
IQL_SEQUENCE { if (!($$ = ctx.sequence(@1))) YYERROR; @$.begin = @1.begin; @$.end = @1.end; }
| plain_literal IQL_SEQUENCE { if (!($$ = ctx.append($1, @2))) YYERROR; @$.begin = @1.begin; @$.end = @2.end; }
;
dquoted_literal:
IQL_DQUOTE IQL_SEQUENCE IQL_DQUOTE { if (!($$ = ctx.sequence(@2))) YYERROR; @$.begin = @1.begin; @$.end = @3.end; }
| dquoted_literal IQL_DQUOTE IQL_SEQUENCE IQL_DQUOTE { if (!($$ = ctx.append($$ = ctx.append($1, @2), @3))) YYERROR; @$.begin = @1.begin; @$.end = @4.end; }
;
squoted_literal:
IQL_SQUOTE IQL_SEQUENCE IQL_SQUOTE { if (!($$ = ctx.sequence(@2))) YYERROR; @$.begin = @1.begin; @$.end = @3.end; }
| squoted_literal IQL_SQUOTE IQL_SEQUENCE IQL_SQUOTE { if (!($$ = ctx.append($$ = ctx.append($1, @2), @3))) YYERROR; @$.begin = @1.begin; @$.end = @4.end; }
;
limit:
// empty since it is optional
| IQL_SEP IQL_LIMIT IQL_SEP term { if (!ctx.setLimit($4)) YYERROR; @$.begin = @1.begin; @$.end = @4.end; };
;
order:
// empty since it is optional
| IQL_SEP IQL_ORDER IQL_SEP order_list
;
order_list:
order_term
| order_list list_sep order_term
;
order_term:
term { if (!ctx.addOrder($1)) YYERROR; @$.begin = @1.begin; @$.end = @1.end; }
| term IQL_SEP IQL_ASC { if (!ctx.addOrder($1, true)) YYERROR; @$.begin = @1.begin; @$.end = @3.end; }
| term IQL_SEP IQL_DESC { if (!ctx.addOrder($1, false)) YYERROR; @$.begin = @1.begin; @$.end = @3.end; }
;
%%
// -----------------------------------------------------------------------------
// --SECTION-- Epilogue
// -----------------------------------------------------------------------------
// define after 'yydebug' is declared by bison
namespace iresearch {
namespace iql {
void debug(parser& parser, bool bEnable) {
#if YYDEBUG
// suppress MSVC C4505 warnings ('#pragma warning(disable:4505)' is ignored by MSVS)
// defined here only for the sake of being inside some function
#if defined(_MSC_VER)
if (false) yypstack(nullptr, 0);
if (false) yypdumpstack(nullptr);
#endif
yydebug = bEnable ? 1 : 0;
parser.set_debug_level(bEnable ? 1 : 0);
#endif
}
}
}
// end of suppress of warnings due to Bison generated code (pop section, push at start of file)
#if defined(_MSC_VER)
#pragma warning(default : 4706)
#pragma warning(default : 4611)
#pragma warning(default : 4505)
#pragma warning(default : 4244)
#pragma warning(default : 4127)
#pragma warning(default : 4100)
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------