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