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