1 /*  $Id: query_parser_bison.y 526090 2017-01-31 15:50:30Z asztalos $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Anatoliy Kuznetsov, Mike DiCuccio
27  *
28  * File Description:
29  *   Bison grammar description for simple query language.
30  *
31  */
32 
33 %{
34 
35 #define YYSTYPE         CQueryParseTree::TNode*
36 #define YYPARSE_PARAM   parm
37 #define YYLEX_PARAM     parm
38 #define YYMAXDEPTH      100000
39 
40 #define YYDEBUG         1
41 #define YYERROR_VERBOSE 1
42 
43 
44 /// Add child node(s) to the parent
45 /// @internal
46 ///
47 inline static
QTreeAddNode(void * parm,CQueryParseTree::TNode * rnode,CQueryParseTree::TNode * node1,CQueryParseTree::TNode * node2)48 void QTreeAddNode(void*                   parm,
49                   CQueryParseTree::TNode* rnode,
50                   CQueryParseTree::TNode* node1,
51                   CQueryParseTree::TNode* node2)
52 {
53     if (node1)
54         rnode->AddNode(node1);
55     if (node2)
56         rnode->AddNode(node2);
57 
58     CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
59     env->AttachQueryTree(rnode);
60     env->ForgetPoolNodes(node1, node2);
61 }
62 
63 
64 /// Add node to a list if parser environment is in the list parsing context
65 /// @internal
66 ///
67 inline static
AddFunc_Arg(void * parm,CQueryParseTree::TNode * node)68 void AddFunc_Arg(void*                   parm,
69                CQueryParseTree::TNode* node)
70 {
71     CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
72     CQueryParseTree::TNode* func_node = env->GetContext();
73 
74     if (func_node) {
75         func_node->AddNode(node);
76     }
77     env->ForgetPoolNodes(node, 0);
78 }
79 
80 inline static
AddIn_Arg(void * parm,CQueryParseTree::TNode * node)81 void AddIn_Arg(void*                   parm,
82                CQueryParseTree::TNode* node)
83 {
84     CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
85     CQueryParseTree::TNode* in_node = env->GetIN_Context();
86 
87     if (in_node) {
88         in_node->AddNode(node);
89     }
90     env->ForgetPoolNodes(node, 0);
91 }
92 
93 %}
94 
95 %pure_parser   /* Reentrant parser */
96 
97 %token IDENT
98 %token STRING
99 %token NUM_INT
100 %token SELECT
101 %token FROM
102 %token WHERE
103 %token FUNCTION
104 
105 
106 %left AND
107 %left NOT
108 %left OR
109 %left SUB
110 %left XOR
111 %left RANGE
112 %left EQ
113 %left NOTEQ
114 %left GT
115 %left GE
116 %left LT
117 %left LE
118 %left BETWEEN
119 %left NOT_BETWEEN
120 %left LIKE
121 %left NOT_LIKE
122 %left IN
123 %left NOT_IN
124 
125 %%
126 
127 input :
128     exp
129     | select_clause
130 ;
131 
132 
133 
134 select_clause :
135     /* select clause */
136     SELECT obj_list FROM obj_list opt_where
137     {
138     CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
139 
140     /* create a pseudo node to isolate select list in a dedicated subtree */
141     //CQueryParseTree::TNode* qnode = 0;
142     //qnode = env->QTree().CreateNode(CQueryParseNode::eList, 0, 0, "LIST");
143     //qnode->MoveSubnodes($2);
144     CQueryParseTree::TNode* qnode = env->GetContext();
145     if (qnode) {
146         qnode->InsertNode(qnode->SubNodeBegin(), $2);
147     }
148 
149     //$1->InsertNode($1->SubNodeBegin(),qnode);
150 
151     $1->AddNode($3);
152     $3->MoveSubnodes($4);
153     $3->InsertNode($3->SubNodeBegin(), $4);
154     if ($5) {
155         $1->AddNode($5);
156     }
157 
158     env->ForgetPoolNode($1);
159     env->ForgetPoolNode($2);
160     env->ForgetPoolNode($3);
161     env->ForgetPoolNode($4);
162     env->ForgetPoolNode($5);
163 
164     env->SetSELECT_Context(0);
165     env->SetContext(0);
166     env->SetFROM_Context(0);
167 
168     $$ = $1;
169     env->AttachQueryTree($$);
170 
171     }
172 ;
173 
174 opt_where :
175     /* empty */
176     {
177     $$=0;
178     }
179     |
180     WHERE exp
181     {
182     CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
183     $1->AddNode($2);
184     env->ForgetPoolNode($2);
185     $$ = $1;
186     }
187 ;
188 
189 functional:
190     FUNCTION '(' exp_list ')'
191     {
192         $$ = $1;
193         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
194         env->AttachQueryTree($$);
195         $$->InsertNode($$->SubNodeBegin(), $3);
196         env->SetContext(0);
197         env->ForgetPoolNodes($1, $3);
198     }
199     | FUNCTION '(' ')'
200     {
201         $$ = $1;
202         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
203         env->AttachQueryTree($$);
204         env->SetContext(0);
205         env->ForgetPoolNode($1);
206     }
207 ;
208 
209 obj_list:
210     scalar_value
211     {
212         $$ = $1;
213     }
214     | obj_list ',' scalar_value
215     {
216         $$ = $1;
217         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
218         AddFunc_Arg(parm, $3);
219         //$$->AddNode($3);
220         env->ForgetPoolNode($3);
221     }
222 ;
223 
224 scalar_value :
225     /* integer constant */
226     NUM_INT
227     {
228         $$ = $1;
229     }
230     /* text */
231     | STRING
232     {
233         $$ = $1;
234     }
235     /* pure string identifier */
236     | IDENT
237     {
238         $$ = $1;
239     }
240     | functional
241     {
242         $$ = $1;
243     }
244 ;
245 
246 scalar_list:
247     scalar_value
248     {
249         $$ = $1;
250     }
251     | scalar_list ',' scalar_value
252     {
253         $$ = $1;
254         AddIn_Arg(parm, $3);
255     }
256 ;
257 
258 exp_list:
259     exp
260     {
261         $$ = $1;
262     }
263     | exp_list ',' exp
264     {
265         $$ = $1;
266         AddFunc_Arg(parm, $3);
267     }
268 ;
269 
270 /* IN sub-expression */
271 in_sub_expr:
272     scalar_list
273     |
274     select_clause
275 ;
276 
277 exp :
278     scalar_value
279     {
280         $$ = $1;
281     }
282     /* Function call */
283     |  functional
284     {
285         $$ = $1;
286     }
287     /* Field search */
288     | STRING IDENT
289     {
290         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
291         $$ = env->QTree().CreateNode(CQueryParseNode::eFieldSearch, $1, $2);
292         env->AttachQueryTree($$);
293         env->ForgetPoolNodes($1, $2);
294     }
295     /* concatenated expressions are implicit ANDs */
296     | exp exp
297     {
298         yyerrok;
299         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
300         $$ = env->QTree().CreateNode(CQueryParseNode::eAnd, $1, $2);
301         $$->GetValue().SetExplicit(false);
302         env->AttachQueryTree($$);
303         env->ForgetPoolNodes($1, $2);
304     }
305 
306     /* parenthetical balanced expressions */
307     | '(' exp ')'
308     {
309         $$ = $2;
310     }
311 
312     /*
313      * LOGICAL OPS
314      */
315 
316     /* AND */
317     | exp AND exp
318     {
319         QTreeAddNode(parm, $$ = $2, $1, $3);
320     }
321     /* MINUS */
322     | exp SUB exp
323     {
324         QTreeAddNode(parm, $$ = $2, $1, $3);
325     }
326     /* OR */
327     | exp OR exp
328     {
329         QTreeAddNode(parm, $$ = $2, $1, $3);
330     }
331     /* XOR */
332     | exp XOR exp
333     {
334         QTreeAddNode(parm, $$ = $2, $1, $3);
335     }
336     /* BETWEEN */
337     | scalar_value BETWEEN scalar_value AND scalar_value
338     {
339         $$ = $2;
340         $$->AddNode($1);
341         $$->AddNode($3);
342         $$->AddNode($5);
343 
344         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
345         env->AttachQueryTree($$);
346         env->ForgetPoolNodes($1, $3);
347         env->ForgetPoolNodes($1, $5);
348     }
349     /* NOT BETWEEN */
350     | scalar_value NOT_BETWEEN scalar_value AND scalar_value
351     {
352         $$ = $2;
353         $$->AddNode($1);
354         $$->AddNode($3);
355         $$->AddNode($5);
356 
357         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
358         env->AttachQueryTree($$);
359         env->ForgetPoolNodes($1, $3);
360         env->ForgetPoolNodes($1, $5);
361     }
362 
363     /* RANGE */
364     | exp RANGE exp
365     {
366         QTreeAddNode(parm, $$ = $2, $1, $3);
367     }
368     /* LIKE */
369     | scalar_value LIKE scalar_value
370     {
371         QTreeAddNode(parm, $$ = $2, $1, $3);
372     }
373     /* NOT LIKE */
374     | scalar_value NOT_LIKE scalar_value
375     {
376         QTreeAddNode(parm, $$ = $2, $1, $3);
377     }
378     /* IN */
379     | scalar_value IN '(' in_sub_expr ')'
380     {
381         $$ = $2;
382         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
383         env->AttachQueryTree($$);
384         env->ForgetPoolNodes($1, $4);
385         $$->InsertNode($$->SubNodeBegin(), $4);
386         $$->InsertNode($$->SubNodeBegin(), $1);
387         env->SetIN_Context(0);
388     }
389     /* NOT IN */
390     | scalar_value NOT_IN '(' in_sub_expr ')'
391     {
392         $$ = $2;
393         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
394         env->AttachQueryTree($$);
395         env->ForgetPoolNodes($1, $4);
396         $$->InsertNode($$->SubNodeBegin(), $4);
397         $$->InsertNode($$->SubNodeBegin(), $1);
398         env->SetIN_Context(0);
399     }
400     /* == */
401     | exp EQ exp
402     {
403         QTreeAddNode(parm, $$ = $2, $1, $3);
404     }
405     /* != */
406     | exp NOTEQ exp
407     {
408         QTreeAddNode(parm, $$ = $2, $1, $3);
409     }
410     | exp GT exp
411     {
412         QTreeAddNode(parm, $$ = $2, $1, $3);
413     }
414     | exp GE exp
415     {
416         QTreeAddNode(parm, $$ = $2, $1, $3);
417     }
418     | exp LT exp
419     {
420         QTreeAddNode(parm, $$ = $2, $1, $3);
421     }
422     | exp LE exp
423     {
424         QTreeAddNode(parm, $$ = $2, $1, $3);
425     }
426     /* NOT
427     | exp NOT exp
428     {
429         QTreeAddNode(parm, $$ = $2, $1, $3);
430     }
431 */
432     /* unary NOT */
433     | NOT exp
434     {
435         QTreeAddNode(parm, $$ = $1, $2, 0);
436     }
437 
438     /*
439      * error cases
440      */
441 
442     | error STRING
443     {
444         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
445         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
446             NCBI_THROW(CQueryParseException, eParserError,
447                        "Syntax error.");
448         }
449         QTreeAddNode(parm, $$ = $2, 0, 0);
450     }
451     | error IDENT
452     {
453         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
454         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
455             NCBI_THROW(CQueryParseException, eParserError,
456                        "Syntax error.");
457         }
458         QTreeAddNode(parm, $$ = $2, 0, 0);
459     }
460     | error NUM_INT
461     {
462         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
463         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
464             NCBI_THROW(CQueryParseException, eParserError,
465                        "Syntax error.");
466         }
467         QTreeAddNode(parm, $$ = $2, 0, 0);
468     }
469     | exp error
470     {
471         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
472         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
473             NCBI_THROW(CQueryParseException, eParserError,
474                        "Syntax error.");
475         }
476         QTreeAddNode(parm, $$ = $1, 0, 0);
477     }
478 
479     /* unbalanced parenthesis at the end-of-input */
480 
481     | '(' exp error
482     {
483         yyerrok;
484         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
485         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
486             NCBI_THROW(CQueryParseException, eParserError,
487                        "Syntax error. Unbalanced parenthesis");
488         }
489         QTreeAddNode(parm, $$ = $2, 0, 0);
490     }
491     | exp OR error
492     {
493         yyerrok;
494         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
495         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
496             NCBI_THROW(CQueryParseException, eParserError,
497                        "Syntax error.");
498         }
499         QTreeAddNode(parm, $$ = $1, 0, 0);
500     }
501     | exp XOR error
502     {
503         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
504         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
505             NCBI_THROW(CQueryParseException, eParserError,
506                        "Syntax error.");
507         }
508         yyerrok;
509         QTreeAddNode(parm, $$ = $1, 0, 0);
510     }
511     | exp NOT error
512     {
513         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
514         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
515             NCBI_THROW(CQueryParseException, eParserError,
516                        "Syntax error.");
517         }
518         yyerrok;
519         QTreeAddNode(parm, $$ = $1, 0, 0);
520     }
521     | exp AND error
522     {
523         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
524         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
525             NCBI_THROW(CQueryParseException, eParserError,
526                        "Syntax error.");
527         }
528         yyerrok;
529         QTreeAddNode(parm, $$ = $1, 0, 0);
530     }
531     | exp SUB error
532     {
533         CQueryParserEnv* env = reinterpret_cast<CQueryParserEnv*>(parm);
534         if (env->GetParserTolerance() == CQueryParseTree::eSyntaxCheck) {
535             NCBI_THROW(CQueryParseException, eParserError,
536                        "Syntax error.");
537         }
538         yyerrok;
539         QTreeAddNode(parm, $$ = $1, 0, 0);
540     }
541 
542 /**
543     | AND exp error
544     {
545         $$ = CQueryParseTree::CreateOpNode(CQueryParseNode::eAnd, 0, $2);
546     }
547     | OR exp error
548     {
549         $$ = CQueryParseTree::CreateOpNode(CQueryParseNode::eOr, 0, $2);
550     }
551 **/
552 ;
553 
554 %%
555 
556