1 : /******************************************************************************
2 : * $Id: ods_formula.cpp 23831 2012-01-30 23:12:23Z rouault $
3 : *
4 : * Component: ODS formula Engine
5 : * Purpose:
6 : * Author: Even Rouault <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
10 : * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include <ctype.h>
32 : #include <math.h>
33 :
34 : #include "cpl_conv.h"
35 : #include "ods_formula.h"
36 : #include "ods_formula_parser.hpp"
37 :
38 : #define YYSTYPE ods_formula_node*
39 :
40 : static const SingleOpStruct apsSingleOp[] =
41 : {
42 : { "ABS", ODS_ABS, fabs },
43 : { "SQRT", ODS_SQRT, sqrt },
44 : { "COS", ODS_COS, cos },
45 : { "SIN", ODS_SIN, sin },
46 : { "TAN", ODS_TAN, tan },
47 : { "ACOS", ODS_ACOS, acos },
48 : { "ASIN", ODS_ASIN, asin },
49 : { "ATAN", ODS_ATAN, atan },
50 : { "EXP", ODS_EXP, exp },
51 : { "LN", ODS_LN, log },
52 : { "LOG", ODS_LOG, log10 },
53 : { "LOG10", ODS_LOG, log10 },
54 : };
55 :
56 49 : const SingleOpStruct* ODSGetSingleOpEntry(const char* pszName)
57 : {
58 570 : for(size_t i = 0; i < sizeof(apsSingleOp) / sizeof(apsSingleOp[0]); i++)
59 : {
60 530 : if (EQUAL(pszName, apsSingleOp[i].pszName))
61 9 : return &apsSingleOp[i];
62 : }
63 40 : return NULL;
64 : }
65 :
66 9 : const SingleOpStruct* ODSGetSingleOpEntry(ods_formula_op eOp)
67 : {
68 50 : for(size_t i = 0; i < sizeof(apsSingleOp) / sizeof(apsSingleOp[0]); i++)
69 : {
70 50 : if (eOp == apsSingleOp[i].eOp)
71 9 : return &apsSingleOp[i];
72 : }
73 0 : return NULL;
74 : }
75 :
76 : /************************************************************************/
77 : /* swqlex() */
78 : /* */
79 : /* Read back a token from the input. */
80 : /************************************************************************/
81 :
82 818 : int ods_formulalex( YYSTYPE *ppNode, ods_formula_parse_context *context )
83 : {
84 818 : const char *pszInput = context->pszNext;
85 :
86 818 : *ppNode = NULL;
87 :
88 : /* -------------------------------------------------------------------- */
89 : /* Do we have a start symbol to return? */
90 : /* -------------------------------------------------------------------- */
91 818 : if( context->nStartToken != 0 )
92 : {
93 116 : int nRet = context->nStartToken;
94 116 : context->nStartToken = 0;
95 116 : return nRet;
96 : }
97 :
98 : /* -------------------------------------------------------------------- */
99 : /* Skip white space. */
100 : /* -------------------------------------------------------------------- */
101 1404 : while( *pszInput == ' ' || *pszInput == '\t'
102 : || *pszInput == 10 || *pszInput == 13 )
103 0 : pszInput++;
104 :
105 702 : if( *pszInput == '\0' )
106 : {
107 116 : context->pszNext = pszInput;
108 116 : return EOF;
109 : }
110 :
111 : /* -------------------------------------------------------------------- */
112 : /* Handle string constants. */
113 : /* -------------------------------------------------------------------- */
114 586 : if( *pszInput == '"' )
115 : {
116 : char *token;
117 : int i_token;
118 :
119 34 : pszInput++;
120 :
121 34 : token = (char *) CPLMalloc(strlen(pszInput)+1);
122 34 : i_token = 0;
123 :
124 102 : while( *pszInput != '\0' )
125 : {
126 68 : if( *pszInput == '\\' && pszInput[1] == '"' )
127 0 : pszInput++;
128 68 : else if( *pszInput == '\\' && pszInput[1] == '\'' )
129 0 : pszInput++;
130 68 : else if( *pszInput == '\'' && pszInput[1] == '\'' )
131 0 : pszInput++;
132 68 : else if( *pszInput == '"' )
133 : {
134 34 : pszInput++;
135 34 : break;
136 : }
137 34 : else if( *pszInput == '\'' )
138 : {
139 0 : pszInput++;
140 0 : break;
141 : }
142 :
143 34 : token[i_token++] = *(pszInput++);
144 : }
145 34 : token[i_token] = '\0';
146 :
147 34 : *ppNode = new ods_formula_node( token );
148 34 : CPLFree( token );
149 :
150 34 : context->pszNext = pszInput;
151 :
152 34 : return ODST_STRING;
153 : }
154 :
155 : /* -------------------------------------------------------------------- */
156 : /* Handle numbers. */
157 : /* -------------------------------------------------------------------- */
158 552 : else if( *pszInput >= '0' && *pszInput <= '9' )
159 : {
160 137 : CPLString osToken;
161 137 : const char *pszNext = pszInput + 1;
162 :
163 137 : osToken += *pszInput;
164 :
165 : // collect non-decimal part of number
166 278 : while( *pszNext >= '0' && *pszNext <= '9' )
167 4 : osToken += *(pszNext++);
168 :
169 : // collect decimal places.
170 137 : if( *pszNext == '.' )
171 : {
172 48 : osToken += *(pszNext++);
173 144 : while( *pszNext >= '0' && *pszNext <= '9' )
174 48 : osToken += *(pszNext++);
175 : }
176 :
177 : // collect exponent
178 137 : if( *pszNext == 'e' || *pszNext == 'E' )
179 : {
180 0 : osToken += *(pszNext++);
181 0 : if( *pszNext == '-' || *pszNext == '+' )
182 0 : osToken += *(pszNext++);
183 0 : while( *pszNext >= '0' && *pszNext <= '9' )
184 0 : osToken += *(pszNext++);
185 : }
186 :
187 137 : context->pszNext = pszNext;
188 :
189 137 : if( strstr(osToken,".")
190 : || strstr(osToken,"e")
191 : || strstr(osToken,"E") )
192 : {
193 48 : *ppNode = new ods_formula_node( CPLAtof(osToken) );
194 : }
195 : else
196 : {
197 89 : *ppNode = new ods_formula_node( atoi(osToken) );
198 : }
199 :
200 137 : return ODST_NUMBER;
201 : }
202 :
203 : /* -------------------------------------------------------------------- */
204 : /* Handle alpha-numerics. */
205 : /* -------------------------------------------------------------------- */
206 415 : else if( *pszInput == '.' || isalnum( *pszInput ) )
207 : {
208 106 : int nReturn = ODST_IDENTIFIER;
209 106 : CPLString osToken;
210 106 : const char *pszNext = pszInput + 1;
211 :
212 106 : osToken += *pszInput;
213 :
214 : // collect text characters
215 466 : while( isalnum( *pszNext ) || *pszNext == '_'
216 : || ((unsigned char) *pszNext) > 127 )
217 254 : osToken += *(pszNext++);
218 :
219 106 : context->pszNext = pszNext;
220 :
221 : /* Constants */
222 106 : if( EQUAL(osToken,"TRUE") )
223 : {
224 10 : *ppNode = new ods_formula_node( 1 );
225 10 : return ODST_NUMBER;
226 : }
227 96 : else if( EQUAL(osToken,"FALSE") )
228 : {
229 10 : *ppNode = new ods_formula_node( 0 );
230 10 : return ODST_NUMBER;
231 : }
232 :
233 86 : else if( EQUAL(osToken,"NOT") )
234 2 : nReturn = ODST_NOT;
235 84 : else if( EQUAL(osToken,"AND") )
236 4 : nReturn = ODST_AND;
237 80 : else if( EQUAL(osToken,"OR") )
238 4 : nReturn = ODST_OR;
239 76 : else if( EQUAL(osToken,"IF") )
240 4 : nReturn = ODST_IF;
241 :
242 : /* No-arg functions */
243 72 : else if( EQUAL(osToken,"PI") )
244 : {
245 1 : *ppNode = new ods_formula_node( ODS_PI );
246 1 : return ODST_FUNCTION_NO_ARG;
247 : }
248 :
249 : /* Single-arg functions */
250 71 : else if( EQUAL(osToken,"LEN") )
251 : {
252 1 : *ppNode = new ods_formula_node( ODS_LEN );
253 1 : return ODST_FUNCTION_SINGLE_ARG;
254 : }
255 : /*
256 : else if( EQUAL(osToken,"T") )
257 : {
258 : *ppNode = new ods_formula_node( ODS_T );
259 : return ODST_FUNCTION_SINGLE_ARG;
260 : }*/
261 :
262 : /* Tow-arg functions */
263 70 : else if( EQUAL(osToken,"MOD") )
264 : {
265 1 : *ppNode = new ods_formula_node( ODS_MODULUS );
266 1 : return ODST_FUNCTION_TWO_ARG;
267 : }
268 69 : else if( EQUAL(osToken,"LEFT") )
269 : {
270 3 : *ppNode = new ods_formula_node( ODS_LEFT );
271 3 : return ODST_FUNCTION_TWO_ARG;
272 : }
273 66 : else if( EQUAL(osToken,"RIGHT") )
274 : {
275 3 : *ppNode = new ods_formula_node( ODS_RIGHT );
276 3 : return ODST_FUNCTION_TWO_ARG;
277 : }
278 :
279 : /* Three-arg functions */
280 63 : else if( EQUAL(osToken,"MID") )
281 : {
282 8 : *ppNode = new ods_formula_node( ODS_MID );
283 8 : return ODST_FUNCTION_THREE_ARG;
284 : }
285 :
286 : /* Multiple-arg functions */
287 55 : else if( EQUAL(osToken,"SUM") )
288 : {
289 1 : *ppNode = new ods_formula_node( ODS_SUM );
290 1 : nReturn = ODST_FUNCTION_ARG_LIST;
291 : }
292 54 : else if( EQUAL(osToken,"AVERAGE") )
293 : {
294 1 : *ppNode = new ods_formula_node( ODS_AVERAGE );
295 1 : nReturn = ODST_FUNCTION_ARG_LIST;
296 : }
297 53 : else if( EQUAL(osToken,"MIN") )
298 : {
299 1 : *ppNode = new ods_formula_node( ODS_MIN );
300 1 : nReturn = ODST_FUNCTION_ARG_LIST;
301 : }
302 52 : else if( EQUAL(osToken,"MAX") )
303 : {
304 1 : *ppNode = new ods_formula_node( ODS_MAX );
305 1 : nReturn = ODST_FUNCTION_ARG_LIST;
306 : }
307 51 : else if( EQUAL(osToken,"COUNT") )
308 : {
309 1 : *ppNode = new ods_formula_node( ODS_COUNT );
310 1 : nReturn = ODST_FUNCTION_ARG_LIST;
311 : }
312 50 : else if( EQUAL(osToken,"COUNTA") )
313 : {
314 1 : *ppNode = new ods_formula_node( ODS_COUNTA );
315 1 : nReturn = ODST_FUNCTION_ARG_LIST;
316 : }
317 :
318 : else
319 : {
320 49 : const SingleOpStruct* psSingleOp = ODSGetSingleOpEntry(osToken);
321 49 : if (psSingleOp != NULL)
322 : {
323 9 : *ppNode = new ods_formula_node( psSingleOp->eOp );
324 9 : nReturn = ODST_FUNCTION_SINGLE_ARG;
325 : }
326 : else
327 : {
328 40 : *ppNode = new ods_formula_node( osToken );
329 40 : nReturn = ODST_IDENTIFIER;
330 : }
331 : }
332 :
333 69 : return nReturn;
334 : }
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Handle special tokens. */
338 : /* -------------------------------------------------------------------- */
339 : else
340 : {
341 309 : context->pszNext = pszInput+1;
342 309 : return *pszInput;
343 : }
344 : }
345 :
346 : /************************************************************************/
347 : /* ods_formula_compile() */
348 : /************************************************************************/
349 :
350 116 : ods_formula_node* ods_formula_compile( const char *expr )
351 :
352 : {
353 116 : ods_formula_parse_context context;
354 :
355 116 : context.pszInput = expr;
356 116 : context.pszNext = expr;
357 116 : context.nStartToken = ODST_START;
358 :
359 116 : if( ods_formulaparse( &context ) == 0 )
360 : {
361 116 : return context.poRoot;
362 : }
363 : else
364 : {
365 0 : delete context.poRoot;
366 0 : return NULL;
367 : }
368 : }
|