Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsrastercalcparser.yy
3 : : Bison file for raster calculation parser
4 : : --------------------
5 : : begin : 2010-10-25
6 : : copyright : (C) 2010 by Marco Hugentobler
7 : : email : marco dot hugentobler at sourcepole dot ch
8 : : ***************************************************************************/
9 : :
10 : : /***************************************************************************
11 : : * *
12 : : * This program is free software; you can redistribute it and/or modify *
13 : : * it under the terms of the GNU General Public License as published by *
14 : : * the Free Software Foundation; either version 2 of the License, or *
15 : : * (at your option) any later version. *
16 : : * *
17 : : ***************************************************************************/
18 : :
19 : : %{
20 : : #include "qgsrastercalcnode.h"
21 : :
22 : : #ifdef _MSC_VER
23 : : # pragma warning( disable: 4065 ) // switch statement contains 'default' but no 'case' labels
24 : : # pragma warning( disable: 4701 ) // Potentially uninitialized local variable 'name' used
25 : : #endif
26 : :
27 : : // don't redeclare malloc/free
28 : : #define YYINCLUDED_STDLIB_H 1
29 : :
30 : : QgsRasterCalcNode* parseRasterCalcString(const QString& str, QString& parserErrorMsg);
31 : :
32 : : //! from lex.yy.c
33 : : extern int rasterlex();
34 : : extern char* rastertext;
35 : : extern void set_raster_input_buffer(const char* buffer);
36 : :
37 : : //! variable where the parser error will be stored
38 : 2 : QString rParserErrorMsg;
39 : :
40 : : //! sets gParserErrorMsg
41 : : void rastererror(const char* msg);
42 : :
43 : : //! temporary list for nodes without parent (if parsing fails these nodes are removed)
44 : 2 : QList<QgsRasterCalcNode*> gTmpNodes;
45 : : void joinTmpNodes(QgsRasterCalcNode* parent, QgsRasterCalcNode* left, QgsRasterCalcNode* right);
46 : : void addToTmpNodes(QgsRasterCalcNode* node);
47 : :
48 : : // we want verbose error messages
49 : : #define YYERROR_VERBOSE 1
50 : : %}
51 : :
52 : : %union { QgsRasterCalcNode* node; double number; QgsRasterCalcNode::Operator op;}
53 : :
54 : : %start root
55 : :
56 : : %token RASTER_BAND_REF
57 : : %token<number> NUMBER
58 : : %token<op> FUNCTION
59 : : %token<op> FUNCTION_2_ARGS
60 : :
61 : : %type <node> root
62 : : %type <node> raster_exp
63 : :
64 : : %left AND
65 : : %left OR
66 : : %left NE
67 : : %left GE
68 : : %left LE
69 : :
70 : : %left '=' '<' '>'
71 : : %left '+' '-'
72 : : %left '*' '/'
73 : : %left '^'
74 : : %left UMINUS // fictitious symbol (for unary minus)
75 : :
76 : : %%
77 : :
78 : : root: raster_exp{}
79 : : ;
80 : :
81 : : raster_exp:
82 : : FUNCTION '(' raster_exp ')' { $$ = new QgsRasterCalcNode($1, $3, 0); joinTmpNodes($$, $3, 0);}
83 : : | FUNCTION_2_ARGS '(' raster_exp ',' raster_exp ')' { $$ = new QgsRasterCalcNode($1, $3, $5); joinTmpNodes($$, $3, $5);}
84 : : | raster_exp AND raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opAND, $1, $3 ); joinTmpNodes($$,$1,$3); }
85 : : | raster_exp OR raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opOR, $1, $3 ); joinTmpNodes($$,$1,$3); }
86 : : | raster_exp '=' raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opEQ, $1, $3 ); joinTmpNodes($$,$1,$3); }
87 : : | raster_exp NE raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opNE, $1, $3 ); joinTmpNodes($$,$1,$3); }
88 : : | raster_exp '>' raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opGT, $1, $3 ); joinTmpNodes($$, $1, $3); }
89 : : | raster_exp '<' raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opLT, $1, $3 ); joinTmpNodes($$, $1, $3); }
90 : : | raster_exp GE raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opGE, $1, $3 ); joinTmpNodes($$, $1, $3); }
91 : : | raster_exp LE raster_exp { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opLE, $1, $3 ); joinTmpNodes($$, $1, $3); }
92 : : | raster_exp '^' raster_exp { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opPOW, $1, $3); joinTmpNodes($$,$1,$3); }
93 : : | raster_exp '*' raster_exp { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opMUL, $1, $3); joinTmpNodes($$,$1,$3); }
94 : : | raster_exp '/' raster_exp { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opDIV, $1, $3); joinTmpNodes($$,$1,$3); }
95 : : | raster_exp '+' raster_exp { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opPLUS, $1, $3); joinTmpNodes($$,$1,$3); }
96 : : | raster_exp '-' raster_exp { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opMINUS, $1, $3); joinTmpNodes($$,$1,$3); }
97 : : | '(' raster_exp ')' { $$ = $2; }
98 : : | '+' raster_exp %prec UMINUS { $$ = $2; }
99 : : | '-' raster_exp %prec UMINUS { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opSIGN, $2, 0 ); joinTmpNodes($$, $2, 0); }
100 : : | NUMBER { $$ = new QgsRasterCalcNode($1); addToTmpNodes($$); }
101 : : | RASTER_BAND_REF { $$ = new QgsRasterCalcNode(QString::fromUtf8(rastertext)); addToTmpNodes($$); }
102 : : ;
103 : :
104 : : %%
105 : :
106 : 0 : void addToTmpNodes(QgsRasterCalcNode* node)
107 : : {
108 : 0 : gTmpNodes.append(node);
109 : 0 : }
110 : :
111 : :
112 : 0 : void joinTmpNodes(QgsRasterCalcNode* parent, QgsRasterCalcNode* left, QgsRasterCalcNode* right)
113 : : {
114 : : bool res;
115 : : Q_UNUSED(res)
116 : :
117 : 0 : if (left)
118 : : {
119 : 0 : res = gTmpNodes.removeAll(left) != 0;
120 : : Q_ASSERT(res);
121 : 0 : }
122 : :
123 : 0 : if (right)
124 : : {
125 : 0 : res = gTmpNodes.removeAll(right) != 0;
126 : : Q_ASSERT(res);
127 : 0 : }
128 : :
129 : 0 : gTmpNodes.append(parent);
130 : 0 : }
131 : :
132 : :
133 : 0 : QgsRasterCalcNode* localParseRasterCalcString(const QString& str, QString& parserErrorMsg)
134 : : {
135 : : // list should be empty when starting
136 : : Q_ASSERT(gTmpNodes.count() == 0);
137 : :
138 : 0 : set_raster_input_buffer(str.toUtf8().constData());
139 : 0 : int res = rasterparse();
140 : :
141 : : // list should be empty when parsing was OK
142 : 0 : if (res == 0) // success?
143 : : {
144 : : Q_ASSERT(gTmpNodes.count() == 1);
145 : 0 : return gTmpNodes.takeFirst();
146 : : }
147 : : else // error?
148 : : {
149 : 0 : parserErrorMsg = rParserErrorMsg;
150 : : // remove nodes without parents - to prevent memory leaks
151 : 0 : while (gTmpNodes.size() > 0)
152 : 0 : delete gTmpNodes.takeFirst();
153 : 0 : return nullptr;
154 : : }
155 : 0 : }
156 : :
157 : 0 : void rastererror(const char* msg)
158 : : {
159 : 0 : rParserErrorMsg = msg;
160 : 0 : }
161 : :
162 : :
163 : :
|