Statistics
| Branch: | Tag: | Revision:

qgis / src / analysis / raster / qgsrastercalcparser.yy @ master

History | View | Annotate | Download (6.23 KB)

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 raster_lex();
34
  extern char* raster_text;
35
  extern void set_raster_input_buffer(const char* buffer);
36

    
37
  //! variable where the parser error will be stored
38
  QString rParserErrorMsg;
39

    
40
  //! sets gParserErrorMsg
41
  void raster_error(const char* msg);
42

    
43
  //! temporary list for nodes without parent (if parsing fails these nodes are removed)
44
  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
%token IF
62

    
63
%type <node> root
64
%type <node> raster_exp
65

    
66
%left AND
67
%left OR
68
%left NE
69
%left GE
70
%left LE
71

    
72
%left '=' '<' '>'
73
%left '+' '-'
74
%left '*' '/'
75
%left '^'
76
%left UMINUS  // fictitious symbol (for unary minus)
77

    
78
%%
79

    
80
root: raster_exp{}
81
;
82

    
83
raster_exp:
84
  FUNCTION '(' raster_exp ')'   { $$ = new QgsRasterCalcNode($1, $3, 0); joinTmpNodes($$, $3, 0);}
85
  | FUNCTION_2_ARGS '(' raster_exp ',' raster_exp ')' { $$ = new QgsRasterCalcNode($1, $3, $5); joinTmpNodes($$, $3, $5);}
86
  | IF '(' raster_exp ',' raster_exp ',' raster_exp ')' { QVector <QgsRasterCalcNode *> tmpVect;
87
                                                            tmpVect<< $3<< $5<< $7;
88
                                                            $$ = new QgsRasterCalcNode("if", tmpVect);
89
                                                            joinTmpNodes($$, $3, $5);
90
                                                            gTmpNodes.removeAll($7);
91
                                                          }
92
  | raster_exp AND raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opAND, $1, $3 ); joinTmpNodes($$,$1,$3); }
93
  | raster_exp OR raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opOR, $1, $3 ); joinTmpNodes($$,$1,$3); }
94
  | raster_exp '=' raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opEQ, $1, $3 ); joinTmpNodes($$,$1,$3); }
95
  | raster_exp NE raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opNE, $1, $3 ); joinTmpNodes($$,$1,$3); }
96
  | raster_exp '>' raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opGT, $1, $3 ); joinTmpNodes($$, $1, $3); }
97
  | raster_exp '<' raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opLT, $1, $3 ); joinTmpNodes($$, $1, $3); }
98
  | raster_exp GE raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opGE, $1, $3 ); joinTmpNodes($$, $1, $3); }
99
  | raster_exp LE raster_exp   { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opLE, $1, $3 ); joinTmpNodes($$, $1, $3); }
100
  | raster_exp '^' raster_exp   { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opPOW, $1, $3); joinTmpNodes($$,$1,$3); }
101
  | raster_exp '*' raster_exp   { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opMUL, $1, $3); joinTmpNodes($$,$1,$3); }
102
  | raster_exp '/' raster_exp   { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opDIV, $1, $3); joinTmpNodes($$,$1,$3); }
103
  | raster_exp '+' raster_exp   { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opPLUS, $1, $3); joinTmpNodes($$,$1,$3); }
104
  | raster_exp '-' raster_exp   { $$ = new QgsRasterCalcNode(QgsRasterCalcNode::opMINUS, $1, $3); joinTmpNodes($$,$1,$3); }
105
  | '(' raster_exp ')'          { $$ = $2; }
106
  | '+' raster_exp %prec UMINUS { $$ = $2; }
107
  | '-' raster_exp %prec UMINUS { $$ = new QgsRasterCalcNode( QgsRasterCalcNode::opSIGN, $2, 0 ); joinTmpNodes($$, $2, 0); }
108
  | NUMBER { $$ = new QgsRasterCalcNode($1); addToTmpNodes($$); }
109
  | RASTER_BAND_REF { $$ = new QgsRasterCalcNode(QString::fromUtf8(raster_text)); addToTmpNodes($$); }
110
;
111

    
112
%%
113

    
114
void addToTmpNodes(QgsRasterCalcNode* node)
115
{
116
  gTmpNodes.append(node);
117
}
118

    
119

    
120
void joinTmpNodes(QgsRasterCalcNode* parent, QgsRasterCalcNode* left, QgsRasterCalcNode* right)
121
{
122
  bool res;
123
  Q_UNUSED(res)
124

    
125
  if (left)
126
  {
127
    res = gTmpNodes.removeAll(left) != 0;
128
    Q_ASSERT(res);
129
  }
130

    
131
  if (right)
132
  {
133
    res = gTmpNodes.removeAll(right) != 0;
134
    Q_ASSERT(res);
135
  }
136

    
137
  gTmpNodes.append(parent);
138
}
139

    
140

    
141
QgsRasterCalcNode* localParseRasterCalcString(const QString& str, QString& parserErrorMsg)
142
{
143
  // list should be empty when starting
144
  Q_ASSERT(gTmpNodes.count() == 0);
145

    
146
  set_raster_input_buffer(str.toUtf8().constData());
147
  int res = raster_parse();
148

    
149
  // list should be empty when parsing was OK
150
  if (res == 0) // success?
151
  {
152
    Q_ASSERT(gTmpNodes.count() == 1);
153
    return gTmpNodes.takeFirst();
154
  }
155
  else // error?
156
  {
157
    parserErrorMsg = rParserErrorMsg;
158
    // remove nodes without parents - to prevent memory leaks
159
    while (gTmpNodes.size() > 0)
160
      delete gTmpNodes.takeFirst();
161
    return nullptr;
162
  }
163
}
164

    
165
void raster_error(const char* msg)
166
{
167
  rParserErrorMsg = msg;
168
}
169

    
170

    
171