Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsexpressionparser.yy
3 : : --------------------
4 : : begin : August 2011
5 : : copyright : (C) 2011 by Martin Dobias
6 : : email : wonder.sk at gmail dot com
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : :
16 : : %{
17 : : #include <qglobal.h>
18 : : #include <QList>
19 : : #include <cstdlib>
20 : : #include "qgslogger.h"
21 : : #include "expression/qgsexpression.h"
22 : : #include "expression/qgsexpressionnode.h"
23 : : #include "expression/qgsexpressionnodeimpl.h"
24 : : #include "expression/qgsexpressionfunction.h"
25 : :
26 : : #ifdef _MSC_VER
27 : : # pragma warning( disable: 4065 ) // switch statement contains 'default' but no 'case' labels
28 : : # pragma warning( disable: 4702 ) // unreachable code
29 : : #endif
30 : :
31 : : // don't redeclare malloc/free
32 : : #define YYINCLUDED_STDLIB_H 1
33 : :
34 : : // maximum number of errors encountered before parser aborts
35 : : #define MAX_ERRORS 10
36 : :
37 : : struct expression_parser_context;
38 : : #include "qgsexpressionparser.hpp"
39 : :
40 : : //! from lexer
41 : : typedef void* yyscan_t;
42 : : typedef struct yy_buffer_state* YY_BUFFER_STATE;
43 : : extern int exp_lex_init(yyscan_t* scanner);
44 : : extern int exp_lex_destroy(yyscan_t scanner);
45 : : extern int exp_lex(YYSTYPE* yylval_param, YYLTYPE* yyloc, yyscan_t yyscanner);
46 : : extern YY_BUFFER_STATE exp__scan_string(const char* buffer, yyscan_t scanner);
47 : :
48 : : /** returns parsed tree, otherwise returns nullptr and sets parserErrorMsg
49 : : (interface function to be called from QgsExpression)
50 : : */
51 : : QgsExpressionNode* parseExpression(const QString& str, QString& parserErrorMsg, QList<QgsExpression::ParserError>& parserError);
52 : :
53 : : /** error handler for bison */
54 : : void exp_error(YYLTYPE* yyloc, expression_parser_context* parser_ctx, const char* msg);
55 : :
56 : 0 : struct expression_parser_context
57 : : {
58 : : // lexer context
59 : : yyscan_t flex_scanner;
60 : :
61 : : // List of all errors.
62 : : QList<QgsExpression::ParserError> parserErrors;
63 : : QString errorMsg;
64 : : // Current parser error.
65 : 0 : QgsExpression::ParserError::ParserErrorType currentErrorType = QgsExpression::ParserError::Unknown;
66 : : // root node of the expression
67 : : QgsExpressionNode* rootNode;
68 : : };
69 : :
70 : : #define scanner parser_ctx->flex_scanner
71 : :
72 : : // we want verbose error messages
73 : : #define YYERROR_VERBOSE 1
74 : :
75 : : #define BINOP(x, y, z) new QgsExpressionNodeBinaryOperator(x, y, z)
76 : :
77 : 0 : void addParserLocation(YYLTYPE* yyloc, QgsExpressionNode *node)
78 : : {
79 : 0 : node->parserFirstLine = yyloc->first_line;
80 : 0 : node->parserFirstColumn = yyloc->first_column;
81 : 0 : node->parserLastLine = yyloc->last_line;
82 : 0 : node->parserLastColumn = yyloc->last_column;
83 : 0 : }
84 : :
85 : : %}
86 : :
87 : : // make the parser reentrant
88 : : %locations
89 : : %define api.pure
90 : : %lex-param {void * scanner}
91 : : %parse-param {expression_parser_context* parser_ctx}
92 : :
93 : : %union
94 : : {
95 : : QgsExpressionNode* node;
96 : : QgsExpressionNode::NodeList* nodelist;
97 : : QgsExpressionNode::NamedNode* namednode;
98 : : double numberFloat;
99 : : int numberInt;
100 : : qlonglong numberInt64;
101 : : bool boolVal;
102 : : QString* text;
103 : : QgsExpressionNodeBinaryOperator::BinaryOperator b_op;
104 : : QgsExpressionNodeUnaryOperator::UnaryOperator u_op;
105 : : QgsExpressionNodeCondition::WhenThen* whenthen;
106 : : QgsExpressionNodeCondition::WhenThenList* whenthenlist;
107 : : }
108 : :
109 : : %start root
110 : :
111 : :
112 : : //
113 : : // token definitions
114 : : //
115 : :
116 : : // operator tokens
117 : : %token <b_op> OR AND EQ NE LE GE LT GT REGEXP LIKE IS PLUS MINUS MUL DIV INTDIV MOD CONCAT POW
118 : : %token <u_op> NOT
119 : : %token IN
120 : :
121 : : // literals
122 : : %token <numberFloat> NUMBER_FLOAT
123 : : %token <numberInt> NUMBER_INT
124 : : %token <numberInt64> NUMBER_INT64
125 : : %token <boolVal> BOOLEAN
126 : : %token NULLVALUE
127 : :
128 : : // tokens for conditional expressions
129 : : %token CASE WHEN THEN ELSE END
130 : :
131 : : %token <text> STRING QUOTED_COLUMN_REF NAME SPECIAL_COL VARIABLE NAMED_NODE
132 : :
133 : : %token COMMA
134 : :
135 : : %token Unknown_CHARACTER
136 : :
137 : : //
138 : : // definition of non-terminal types
139 : : //
140 : :
141 : : %type <node> expression
142 : : %type <nodelist> exp_list
143 : : %type <whenthen> when_then_clause
144 : : %type <whenthenlist> when_then_clauses
145 : : %type <namednode> named_node
146 : :
147 : : // debugging
148 : : %define parse.error verbose
149 : :
150 : : //
151 : : // operator precedence
152 : : //
153 : :
154 : : // left associativity means that 1+2+3 translates to (1+2)+3
155 : : // the order of operators here determines their precedence
156 : :
157 : : %left OR
158 : : %left AND
159 : : %right NOT
160 : : %left EQ NE LE GE LT GT REGEXP LIKE IS IN
161 : : %left PLUS MINUS
162 : : %left MUL DIV INTDIV MOD
163 : : %right POW
164 : : %left CONCAT
165 : :
166 : : %right UMINUS // fictitious symbol (for unary minus)
167 : :
168 : : %left COMMA
169 : : %left '['
170 : :
171 : : %destructor { delete $$; } <node>
172 : : %destructor { delete $$; } <nodelist>
173 : : %destructor { delete $$; } <namednode>
174 : : %destructor { delete $$; } <text>
175 : : %destructor { delete $$; } <whenthen>
176 : : %destructor { delete $$; } <whenthenlist>
177 : :
178 : : %%
179 : :
180 : : root: expression { parser_ctx->rootNode = $1; }
181 : : | error expression
182 : : {
183 : : delete $2;
184 : : if ( parser_ctx->parserErrors.count() < MAX_ERRORS )
185 : : yyerrok;
186 : : else
187 : : YYABORT;
188 : : }
189 : : ;
190 : :
191 : : expression:
192 : : expression AND expression { $$ = BINOP($2, $1, $3); }
193 : : | expression OR expression { $$ = BINOP($2, $1, $3); }
194 : : | expression EQ expression { $$ = BINOP($2, $1, $3); }
195 : : | expression NE expression { $$ = BINOP($2, $1, $3); }
196 : : | expression LE expression { $$ = BINOP($2, $1, $3); }
197 : : | expression GE expression { $$ = BINOP($2, $1, $3); }
198 : : | expression LT expression { $$ = BINOP($2, $1, $3); }
199 : : | expression GT expression { $$ = BINOP($2, $1, $3); }
200 : : | expression REGEXP expression { $$ = BINOP($2, $1, $3); }
201 : : | expression LIKE expression { $$ = BINOP($2, $1, $3); }
202 : : | expression IS expression { $$ = BINOP($2, $1, $3); }
203 : : | expression PLUS expression { $$ = BINOP($2, $1, $3); }
204 : : | expression MINUS expression { $$ = BINOP($2, $1, $3); }
205 : : | expression MUL expression { $$ = BINOP($2, $1, $3); }
206 : : | expression INTDIV expression { $$ = BINOP($2, $1, $3); }
207 : : | expression DIV expression { $$ = BINOP($2, $1, $3); }
208 : : | expression MOD expression { $$ = BINOP($2, $1, $3); }
209 : : | expression POW expression { $$ = BINOP($2, $1, $3); }
210 : : | expression CONCAT expression { $$ = BINOP($2, $1, $3); }
211 : : | NOT expression { $$ = new QgsExpressionNodeUnaryOperator($1, $2); }
212 : : | '(' expression ')' { $$ = $2; }
213 : : | NAME '(' exp_list ')'
214 : : {
215 : : int fnIndex = QgsExpression::functionIndex(*$1);
216 : : delete $1;
217 : : if (fnIndex == -1)
218 : : {
219 : : QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionUnknown;
220 : : parser_ctx->currentErrorType = errorType;
221 : : exp_error(&yyloc, parser_ctx, QObject::tr( "Function is not known" ).toUtf8().constData() );
222 : : delete $3;
223 : : YYERROR;
224 : : }
225 : : QString paramError;
226 : : if ( !QgsExpressionNodeFunction::validateParams( fnIndex, $3, paramError ) )
227 : : {
228 : : QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionInvalidParams;
229 : : parser_ctx->currentErrorType = errorType;
230 : : exp_error( &yyloc, parser_ctx, paramError.toLocal8Bit().constData() );
231 : : delete $3;
232 : : YYERROR;
233 : : }
234 : : QgsExpressionFunction* func = QgsExpression::Functions()[fnIndex];
235 : : if ( func->params() != -1
236 : : && !( func->params() >= $3->count()
237 : : && func->minParams() <= $3->count() ) )
238 : : {
239 : : QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionWrongArgs;
240 : : parser_ctx->currentErrorType = errorType;
241 : : QString expectedMessage;
242 : : if ( func->params() == func->minParams() )
243 : : {
244 : : expectedMessage = QObject::tr( "Expected %1 but got %2." ).arg( QString::number( func->params() ), QString::number( $3->count() ) );
245 : : }
246 : : else
247 : : {
248 : : expectedMessage = QObject::tr( "Expected between %1 and %2 parameters but %3 were provided." ).arg( QString::number( func->minParams() ), QString::number( func->params() ), QString::number( $3->count() ) );
249 : : }
250 : : exp_error(&yyloc, parser_ctx, QObject::tr( "%1 function is called with wrong number of arguments. %2" ).arg( QgsExpression::Functions()[fnIndex]->name(), expectedMessage ).toUtf8().constData() );
251 : : delete $3;
252 : : YYERROR;
253 : : }
254 : :
255 : : $$ = new QgsExpressionNodeFunction(fnIndex, $3);
256 : : addParserLocation(&@1, $$);
257 : : }
258 : :
259 : : | NAME '(' ')'
260 : : {
261 : : int fnIndex = QgsExpression::functionIndex(*$1);
262 : : delete $1;
263 : : if (fnIndex == -1)
264 : : {
265 : : QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionUnknown;
266 : : parser_ctx->currentErrorType = errorType;
267 : : exp_error(&yyloc, parser_ctx, QObject::tr( "Function is not known" ).toUtf8().constData() );
268 : : YYERROR;
269 : : }
270 : : // 0 parameters is expected, -1 parameters means leave it to the
271 : : // implementation
272 : : if ( QgsExpression::Functions()[fnIndex]->minParams() > 0 )
273 : : {
274 : :
275 : : QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionWrongArgs;
276 : : parser_ctx->currentErrorType = errorType;
277 : : exp_error(&yyloc, parser_ctx, QObject::tr( "%1 function is called with wrong number of arguments" ).arg( QgsExpression::Functions()[fnIndex]->name() ).toLocal8Bit().constData() );
278 : : YYERROR;
279 : : }
280 : : $$ = new QgsExpressionNodeFunction(fnIndex, new QgsExpressionNode::NodeList());
281 : : addParserLocation(&@1, $$);
282 : : }
283 : :
284 : : | expression IN '(' exp_list ')' { $$ = new QgsExpressionNodeInOperator($1, $4, false); }
285 : : | expression NOT IN '(' exp_list ')' { $$ = new QgsExpressionNodeInOperator($1, $5, true); }
286 : :
287 : : | expression '[' expression ']' { $$ = new QgsExpressionNodeIndexOperator( $1, $3 ); }
288 : :
289 : : | PLUS expression %prec UMINUS { $$ = $2; }
290 : : | MINUS expression %prec UMINUS { $$ = new QgsExpressionNodeUnaryOperator( QgsExpressionNodeUnaryOperator::uoMinus, $2); }
291 : :
292 : : | CASE when_then_clauses END { $$ = new QgsExpressionNodeCondition($2); }
293 : : | CASE when_then_clauses ELSE expression END { $$ = new QgsExpressionNodeCondition($2,$4); }
294 : :
295 : : // columns
296 : : | NAME { $$ = new QgsExpressionNodeColumnRef( *$1 ); delete $1; }
297 : : | QUOTED_COLUMN_REF { $$ = new QgsExpressionNodeColumnRef( *$1 ); delete $1; }
298 : :
299 : : // special columns (actually functions with no arguments)
300 : : | SPECIAL_COL
301 : : {
302 : : int fnIndex = QgsExpression::functionIndex(*$1);
303 : : if (fnIndex >= 0)
304 : : {
305 : : $$ = new QgsExpressionNodeFunction( fnIndex, nullptr );
306 : : }
307 : : else
308 : : {
309 : : QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionUnknown;
310 : : parser_ctx->currentErrorType = errorType;
311 : : exp_error(&yyloc, parser_ctx, QObject::tr( "%1 function is not known" ).arg( *$1 ).toLocal8Bit().constData());
312 : : YYERROR;
313 : : }
314 : : delete $1;
315 : : }
316 : :
317 : : // variables
318 : : | VARIABLE
319 : : {
320 : : // @var is equivalent to var( "var" )
321 : : QgsExpressionNode::NodeList* args = new QgsExpressionNode::NodeList();
322 : : QgsExpressionNodeLiteral* literal = new QgsExpressionNodeLiteral( QString( *$1 ).mid( 1 ) );
323 : : args->append( literal );
324 : : $$ = new QgsExpressionNodeFunction( QgsExpression::functionIndex( "var" ), args );
325 : : delete $1;
326 : : }
327 : :
328 : : // literals
329 : : | NUMBER_FLOAT { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
330 : : | NUMBER_INT { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
331 : : | NUMBER_INT64 { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
332 : : | BOOLEAN { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
333 : : | STRING { $$ = new QgsExpressionNodeLiteral( QVariant(*$1) ); delete $1; }
334 : : | NULLVALUE { $$ = new QgsExpressionNodeLiteral( QVariant() ); }
335 : : ;
336 : :
337 : : named_node:
338 : : NAMED_NODE expression { $$ = new QgsExpressionNode::NamedNode( *$1, $2 ); delete $1; }
339 : : ;
340 : :
341 : : exp_list:
342 : : exp_list COMMA expression
343 : : {
344 : : if ( $1->hasNamedNodes() )
345 : : {
346 : : QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionNamedArgsError;
347 : : parser_ctx->currentErrorType = errorType;
348 : : exp_error(&yyloc, parser_ctx, QObject::tr( "All parameters following a named parameter must also be named." ).toUtf8().constData() );
349 : : delete $1;
350 : : YYERROR;
351 : : }
352 : : else
353 : : {
354 : : $$ = $1; $1->append($3);
355 : : }
356 : : }
357 : : | exp_list COMMA named_node { $$ = $1; $1->append($3); }
358 : : | expression { $$ = new QgsExpressionNode::NodeList(); $$->append($1); }
359 : : | named_node { $$ = new QgsExpressionNode::NodeList(); $$->append($1); }
360 : : ;
361 : :
362 : : when_then_clauses:
363 : : when_then_clauses when_then_clause { $$ = $1; $1->append($2); }
364 : : | when_then_clause { $$ = new QgsExpressionNodeCondition::WhenThenList(); $$->append($1); }
365 : : ;
366 : :
367 : : when_then_clause:
368 : : WHEN expression THEN expression { $$ = new QgsExpressionNodeCondition::WhenThen($2,$4); }
369 : : ;
370 : :
371 : : %%
372 : :
373 : :
374 : : // returns parsed tree, otherwise returns nullptr and sets parserErrorMsg
375 : 0 : QgsExpressionNode* parseExpression(const QString& str, QString& parserErrorMsg, QList<QgsExpression::ParserError> &parserErrors)
376 : : {
377 : 0 : expression_parser_context ctx;
378 : 0 : ctx.rootNode = 0;
379 : :
380 : 0 : exp_lex_init(&ctx.flex_scanner);
381 : 0 : exp__scan_string(str.toUtf8().constData(), ctx.flex_scanner);
382 : 0 : int res = exp_parse(&ctx);
383 : 0 : exp_lex_destroy(ctx.flex_scanner);
384 : :
385 : : // list should be empty when parsing was OK
386 : 0 : if (res == 0 && ctx.parserErrors.count() == 0) // success?
387 : : {
388 : 0 : return ctx.rootNode;
389 : : }
390 : : else // error?
391 : : {
392 : 0 : parserErrorMsg = ctx.errorMsg;
393 : 0 : parserErrors = ctx.parserErrors;
394 : 0 : delete ctx.rootNode;
395 : 0 : return nullptr;
396 : : }
397 : 0 : }
398 : :
399 : :
400 : 0 : void exp_error(YYLTYPE* yyloc,expression_parser_context* parser_ctx, const char* msg)
401 : : {
402 : 0 : QgsExpression::ParserError error = QgsExpression::ParserError();
403 : 0 : error.firstColumn = yyloc->first_column;
404 : 0 : error.firstLine = yyloc->first_line;
405 : 0 : error.lastColumn = yyloc->last_column;
406 : 0 : error.lastLine = yyloc->last_line;
407 : 0 : error.errorMsg = msg;
408 : 0 : error.errorType = parser_ctx->currentErrorType;
409 : 0 : parser_ctx->parserErrors.append(error);
410 : : // Reset the current error type for the next error.
411 : 0 : parser_ctx->currentErrorType = QgsExpression::ParserError::Unknown;
412 : :
413 : 0 : parser_ctx->errorMsg = parser_ctx->errorMsg + "\n" + msg;
414 : 0 : }
|