/***************************************************************************** Copyright (c) 2007, 2014, Oracle and/or its affiliates. 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; version 2 of the License. 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *****************************************************************************/ /** * @file fts/fts0pars.y * FTS parser: input file for the GNU Bison parser generator * * Created 2007/5/9 Sunny Bains */ %{ #include "ha_prototypes.h" #include "mem0mem.h" #include "fts0ast.h" #include "fts0blex.h" #include "fts0tlex.h" #include "fts0pars.h" #include extern int fts_lexer(YYSTYPE*, fts_lexer_t*); extern int fts_blexer(YYSTYPE*, yyscan_t); extern int fts_tlexer(YYSTYPE*, yyscan_t); extern int ftserror(const char* p); /* Required for reentrant parser */ #define ftslex fts_lexer #define YYERROR_VERBOSE /* For passing an argument to yyparse() */ #define YYPARSE_PARAM state #define YYLEX_PARAM ((fts_ast_state_t*) state)->lexer typedef int (*fts_scanner)(YYSTYPE* val, yyscan_t yyscanner); struct fts_lexer_struct { fts_scanner scanner; void* yyscanner; }; %} %union { int oper; fts_ast_string_t* token; fts_ast_node_t* node; }; /* Enable re-entrant parser */ %pure_parser %token FTS_OPER %token FTS_TEXT FTS_TERM FTS_NUMB %type prefix term text expr sub_expr expr_lst query %nonassoc '+' '-' '~' '<' '>' %% query : expr_lst { $$ = $1; ((fts_ast_state_t*) state)->root = $$; } ; expr_lst: /* Empty */ { $$ = NULL; } | expr_lst expr { $$ = $1; if (!$$) { $$ = fts_ast_create_node_list(state, $2); } else { fts_ast_add_node($$, $2); } } | expr_lst sub_expr { $$ = $1; $$ = fts_ast_create_node_list(state, $1); if (!$$) { $$ = $2; } else { fts_ast_add_node($$, $2); } } ; sub_expr: '(' expr_lst ')' { $$ = $2; if ($$) { $$ = fts_ast_create_node_subexp_list(state, $$); } } | prefix '(' expr_lst ')' { $$ = fts_ast_create_node_list(state, $1); if ($3) { fts_ast_add_node($$, fts_ast_create_node_subexp_list(state, $3)); } } ; expr : term { $$ = $1; } | text { $$ = $1; } | term '*' { fts_ast_term_set_wildcard($1); } | text '@' FTS_NUMB { fts_ast_text_set_distance($1, fts_ast_string_to_ul($3, 10)); fts_ast_string_free($3); } | prefix term '*' { $$ = fts_ast_create_node_list(state, $1); fts_ast_add_node($$, $2); fts_ast_term_set_wildcard($2); } | prefix term { $$ = fts_ast_create_node_list(state, $1); fts_ast_add_node($$, $2); } | prefix text '@' FTS_NUMB { $$ = fts_ast_create_node_list(state, $1); fts_ast_add_node($$, $2); fts_ast_text_set_distance($2, fts_ast_string_to_ul($4, 10)); fts_ast_string_free($4); } | prefix text { $$ = fts_ast_create_node_list(state, $1); fts_ast_add_node($$, $2); } ; prefix : '-' { $$ = fts_ast_create_node_oper(state, FTS_IGNORE); } | '+' { $$ = fts_ast_create_node_oper(state, FTS_EXIST); } | '~' { $$ = fts_ast_create_node_oper(state, FTS_NEGATE); } | '<' { $$ = fts_ast_create_node_oper(state, FTS_DECR_RATING); } | '>' { $$ = fts_ast_create_node_oper(state, FTS_INCR_RATING); } ; term : FTS_TERM { $$ = fts_ast_create_node_term(state, $1); fts_ast_string_free($1); } | FTS_NUMB { $$ = fts_ast_create_node_term(state, $1); fts_ast_string_free($1); } /* Ignore leading '*' */ | '*' term { $$ = $2; } ; text : FTS_TEXT { $$ = fts_ast_create_node_text(state, $1); fts_ast_string_free($1); } ; %% /******************************************************************** */ int ftserror( /*=====*/ const char* p) { fprintf(stderr, "%s\n", p); return(0); } /******************************************************************** Create a fts_lexer_t instance.*/ fts_lexer_t* fts_lexer_create( /*=============*/ ibool boolean_mode, const byte* query, ulint query_len) { fts_lexer_t* fts_lexer = static_cast( ut_malloc_nokey(sizeof(fts_lexer_t))); if (boolean_mode) { fts0blex_init(&fts_lexer->yyscanner); fts0b_scan_bytes((char*) query, (int) query_len, fts_lexer->yyscanner); fts_lexer->scanner = fts_blexer; /* FIXME: Debugging */ /* fts0bset_debug(1 , fts_lexer->yyscanner); */ } else { fts0tlex_init(&fts_lexer->yyscanner); fts0t_scan_bytes((char*) query, (int) query_len, fts_lexer->yyscanner); fts_lexer->scanner = fts_tlexer; } return(fts_lexer); } /******************************************************************** Free an fts_lexer_t instance.*/ void fts_lexer_free( /*===========*/ fts_lexer_t* fts_lexer) { if (fts_lexer->scanner == fts_blexer) { fts0blex_destroy(fts_lexer->yyscanner); } else { fts0tlex_destroy(fts_lexer->yyscanner); } ut_free(fts_lexer); } /******************************************************************** Call the appropaiate scanner.*/ int fts_lexer( /*======*/ YYSTYPE* val, fts_lexer_t* fts_lexer) { fts_scanner func_ptr; func_ptr = fts_lexer->scanner; return(func_ptr(val, fts_lexer->yyscanner)); } /******************************************************************** Parse the query.*/ int fts_parse( /*======*/ fts_ast_state_t* state) { return(ftsparse(state)); }