1 %{
2 /******************************************************************************
3  * $Id: ods_formula_parser.y 27745 2014-09-27 16:38:57Z goatbar $
4  *
5  * Component: OGR ODS Formula Engine
6  * Purpose: expression and select parser grammar.
7  *          Requires Bison 2.4.0 or newer to process.  Use "make parser" target.
8  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
9  *
10  ******************************************************************************
11  * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
12  * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  ****************************************************************************/
32 
33 #include "cpl_conv.h"
34 #include "cpl_string.h"
35 #include "ods_formula.h"
36 
37 #define YYSTYPE  ods_formula_node*
38 
39 /* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */
40 /* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */
41 /* increase YYINITDEPTH instead, but this will consume memory. */
42 /* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */
43 /* it appears to be a non documented feature of Bison */
44 #define YYSTYPE_IS_TRIVIAL 1
45 
ods_formulaerror(CPL_UNUSED ods_formula_parse_context * context,const char * msg)46 static void ods_formulaerror( CPL_UNUSED ods_formula_parse_context *context,
47                               const char *msg )
48 {
49     CPLError( CE_Failure, CPLE_AppDefined,
50               "Formula Parsing Error: %s", msg );
51 }
52 
53 %}
54 
55 %define api.pure
56 %require "2.4.0"
57 
58 %parse-param {ods_formula_parse_context *context}
59 %lex-param {ods_formula_parse_context *context}
60 
61 %token ODST_NUMBER
62 %token ODST_STRING
63 %token ODST_IDENTIFIER
64 %token ODST_FUNCTION_NO_ARG
65 %token ODST_FUNCTION_SINGLE_ARG
66 %token ODST_FUNCTION_TWO_ARG
67 %token ODST_FUNCTION_THREE_ARG
68 %token ODST_FUNCTION_ARG_LIST
69 
70 %token ODST_START
71 
72 %left ODST_NOT
73 %left ODST_OR
74 %left ODST_AND
75 %left ODST_IF
76 
77 %left '+' '-' '&'
78 %left '*' '/' '%'
79 %left ODST_UMINUS
80 
81 /* Any grammar rule that does $$ =  must be listed afterwards */
82 /* as well as ODST_NUMBER ODST_STRING ODST_IDENTIFIER that are allocated by ods_formulalex() */
83 %destructor { delete $$; } ODST_NUMBER ODST_STRING ODST_IDENTIFIER ODST_FUNCTION_NO_ARG ODST_FUNCTION_SINGLE_ARG ODST_FUNCTION_TWO_ARG ODST_FUNCTION_THREE_ARG ODST_FUNCTION_ARG_LIST
84 %destructor { delete $$; } value_expr value_expr_list cell_range value_expr_and_cell_range_list
85 
86 %%
87 
88 input:
89     ODST_START value_expr
90         {
91             context->poRoot = $2;
92         }
93 
94 comma: ',' | ';'
95 
96 value_expr:
97 
98     ODST_NUMBER
99         {
100             $$ = $1;
101         }
102 
103     | ODST_STRING
104         {
105             $$ = $1;
106         }
107 
108     | ODST_FUNCTION_NO_ARG '(' ')'
109         {
110             $$ = $1;
111         }
112 
113     | ODST_FUNCTION_SINGLE_ARG '(' value_expr ')'
114         {
115             $$ = $1;
116             $$->PushSubExpression( $3 );
117         }
118 
119     | ODST_FUNCTION_TWO_ARG '(' value_expr comma value_expr ')'
120         {
121             $$ = $1;
122             $$->PushSubExpression( $3 );
123             $$->PushSubExpression( $5 );
124         }
125 
126     | ODST_FUNCTION_THREE_ARG '(' value_expr comma value_expr comma value_expr ')'
127         {
128             $$ = $1;
129             $$->PushSubExpression( $3 );
130             $$->PushSubExpression( $5 );
131             $$->PushSubExpression( $7 );
132         }
133 
134     | ODST_AND '(' value_expr_list ')'
135         {
136             $$ = new ods_formula_node( ODS_AND );
137             $3->ReverseSubExpressions();
138             $$->PushSubExpression( $3 );
139         }
140 
141     | ODST_OR '(' value_expr_list ')'
142         {
143             $$ = new ods_formula_node( ODS_OR );
144             $3->ReverseSubExpressions();
145             $$->PushSubExpression( $3 );
146         }
147 
148     | ODST_NOT '(' value_expr ')'
149         {
150             $$ = new ods_formula_node( ODS_NOT );
151             $$->PushSubExpression( $3 );
152         }
153 
154     | ODST_IF '(' value_expr comma value_expr ')'
155         {
156             $$ = new ods_formula_node( ODS_IF );
157             $$->PushSubExpression( $3 );
158             $$->PushSubExpression( $5 );
159         }
160 
161     | ODST_IF '(' value_expr comma value_expr comma value_expr ')'
162         {
163             $$ = new ods_formula_node( ODS_IF );
164             $$->PushSubExpression( $3 );
165             $$->PushSubExpression( $5 );
166             $$->PushSubExpression( $7 );
167         }
168 
169     | ODST_FUNCTION_ARG_LIST '(' value_expr_and_cell_range_list ')'
170         {
171             $$ = $1;
172             $3->ReverseSubExpressions();
173             $$->PushSubExpression( $3 );
174         }
175 
176     | '(' value_expr ')'
177         {
178             $$ = $2;
179         }
180 
181     | value_expr '=' value_expr
182         {
183             $$ = new ods_formula_node( ODS_EQ );
184             $$->PushSubExpression( $1 );
185             $$->PushSubExpression( $3 );
186         }
187 
188     | value_expr '<' '>' value_expr
189         {
190             $$ = new ods_formula_node( ODS_NE );
191             $$->PushSubExpression( $1 );
192             $$->PushSubExpression( $4 );
193         }
194 
195     | value_expr '!' '=' value_expr
196         {
197             $$ = new ods_formula_node( ODS_NE );
198             $$->PushSubExpression( $1 );
199             $$->PushSubExpression( $4 );
200         }
201 
202     | value_expr '<' value_expr
203         {
204             $$ = new ods_formula_node( ODS_LT );
205             $$->PushSubExpression( $1 );
206             $$->PushSubExpression( $3 );
207         }
208 
209     | value_expr '>' value_expr
210         {
211             $$ = new ods_formula_node( ODS_GT );
212             $$->PushSubExpression( $1 );
213             $$->PushSubExpression( $3 );
214         }
215 
216     | value_expr '<' '=' value_expr
217         {
218             $$ = new ods_formula_node( ODS_LE );
219             $$->PushSubExpression( $1 );
220             $$->PushSubExpression( $4 );
221         }
222 
223     | value_expr '=' '<' value_expr
224         {
225             $$ = new ods_formula_node( ODS_LE );
226             $$->PushSubExpression( $1 );
227             $$->PushSubExpression( $4 );
228         }
229 
230     | value_expr '=' '>' value_expr
231         {
232             $$ = new ods_formula_node( ODS_LE );
233             $$->PushSubExpression( $1 );
234             $$->PushSubExpression( $4 );
235         }
236 
237     | value_expr '>' '=' value_expr
238         {
239             $$ = new ods_formula_node( ODS_GE );
240             $$->PushSubExpression( $1 );
241             $$->PushSubExpression( $4 );
242         }
243 
244     | '-' value_expr %prec ODST_UMINUS
245         {
246             if ($2->eNodeType == SNT_CONSTANT)
247             {
248                 $$ = $2;
249                 $$->int_value *= -1;
250                 $$->float_value *= -1;
251             }
252             else
253             {
254                 $$ = new ods_formula_node( ODS_MULTIPLY );
255                 $$->PushSubExpression( new ods_formula_node(-1) );
256                 $$->PushSubExpression( $2 );
257             }
258         }
259 
260     | value_expr '+' value_expr
261         {
262             $$ = new ods_formula_node( ODS_ADD );
263             $$->PushSubExpression( $1 );
264             $$->PushSubExpression( $3 );
265         }
266 
267     | value_expr '-' value_expr
268         {
269             $$ = new ods_formula_node( ODS_SUBTRACT );
270             $$->PushSubExpression( $1 );
271             $$->PushSubExpression( $3 );
272         }
273 
274     | value_expr '&' value_expr
275         {
276             $$ = new ods_formula_node( ODS_CONCAT );
277             $$->PushSubExpression( $1 );
278             $$->PushSubExpression( $3 );
279         }
280 
281     | value_expr '*' value_expr
282         {
283             $$ = new ods_formula_node( ODS_MULTIPLY );
284             $$->PushSubExpression( $1 );
285             $$->PushSubExpression( $3 );
286         }
287 
288     | value_expr '/' value_expr
289         {
290             $$ = new ods_formula_node( ODS_DIVIDE );
291             $$->PushSubExpression( $1 );
292             $$->PushSubExpression( $3 );
293         }
294 
295     | value_expr '%' value_expr
296         {
297             $$ = new ods_formula_node( ODS_MODULUS );
298             $$->PushSubExpression( $1 );
299             $$->PushSubExpression( $3 );
300         }
301 
302      | '[' ODST_IDENTIFIER ']'
303         {
304             $$ = new ods_formula_node( ODS_CELL );
305             $$->PushSubExpression( $2 );
306         }
307 
308 value_expr_list:
309     value_expr comma value_expr_list
310         {
311             $$ = $3;
312             $3->PushSubExpression( $1 );
313         }
314 
315     | value_expr
316             {
317             $$ = new ods_formula_node( ODS_LIST );
318             $$->PushSubExpression( $1 );
319         }
320 
321 value_expr_and_cell_range_list:
322     value_expr comma value_expr_and_cell_range_list
323         {
324             $$ = $3;
325             $3->PushSubExpression( $1 );
326         }
327 
328     | value_expr
329             {
330             $$ = new ods_formula_node( ODS_LIST );
331             $$->PushSubExpression( $1 );
332         }
333     | cell_range comma value_expr_and_cell_range_list
334         {
335             $$ = $3;
336             $3->PushSubExpression( $1 );
337         }
338 
339     | cell_range
340             {
341             $$ = new ods_formula_node( ODS_LIST );
342             $$->PushSubExpression( $1 );
343         }
344 
345 cell_range:
346     '[' ODST_IDENTIFIER ':' ODST_IDENTIFIER ']'
347         {
348             $$ = new ods_formula_node( ODS_CELL_RANGE );
349             $$->PushSubExpression( $2 );
350             $$->PushSubExpression( $4 );
351         }
352