condparser.cpp
Go to the documentation of this file.
1 /**
2  * Copyright (C) 1997-2015 by Dimitri van Heesch.
3  *
4  * Permission to use, copy, modify, and distribute this software and its
5  * documentation under the terms of the GNU General Public License is hereby
6  * granted. No representations are made about the suitability of this software
7  * for any purpose. It is provided "as is" without express or implied warranty.
8  * See the GNU General Public License for more details.
9  *
10  * Documents produced by Doxygen are derivative works derived from the
11  * input used in their production; they are not affected by this license.
12  *
13  * C++ Expression parser for ENABLED_SECTIONS in Doxygen
14  *
15  * Features used:
16  * Operators:
17  * && AND operator
18  * || OR operator
19  * ! NOT operator
20  */
21 
22 #include "condparser.h"
23 #include "config.h"
24 #include "message.h"
25 
26 // declarations
27 
28 /**
29  * parses and evaluates the given expression.
30  * @returns
31  * - On error, an error message is returned.
32  * - On success, the result of the expression is either "1" or "0".
33  */
34 bool CondParser::parse(const char *fileName,int lineNr,const char *expr)
35 {
36  m_expr = expr;
38 
39  // initialize all variables
40  m_e = m_expr; // let m_e point to the start of the expression
41 
42  bool answer=FALSE;
43  getToken();
45  {
46  // empty expression: answer==FALSE
47  }
48  else if (m_err.isEmpty())
49  {
50  answer = parseLevel1();
51 
52 #if 0
53  // check for garbage at the end of the expression
54  // an expression ends with a character '\0' and token_type = delimeter
56  {
57  if (m_tokenType == DELIMITER)
58  {
59  if (m_token=="(" || m_token==")")
60  {
61  m_err=QCString("Unexpected parenthesis ")+m_token+"'";
62  }
63  else
64  {
65  // user entered a not existing operator like "//"
66  m_err=QCString("Unexpected operator ")+m_token+"'";
67  }
68  }
69  else
70  {
71  m_err=QCString("Unexpected part '")+m_token+"'";
72  }
73  }
74 #endif
75  }
76  if (m_err)
77  {
78  warn(fileName,lineNr,"problem evaluating expression '%s': %s",
79  expr,m_err.data());
80  }
81  //printf("expr='%s' answer=%d\n",expr,answer);
82  return answer;
83 }
84 
85 
86 /**
87  * checks if the given char c is a delimeter
88  * minus is checked apart, can be unary minus
89  */
90 static bool isDelimiter(const char c)
91 {
92  return c=='&' || c=='|' || c=='!';
93 }
94 
95 /**
96  * checks if the given char c is a letter or underscore
97  */
98 static bool isAlpha(const char c)
99 {
100  return (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='_';
101 }
102 
103 static bool isAlphaNum(const char c)
104 {
105  return isAlpha(c) || (c>='0' && c<='9');
106 }
107 
108 /**
109  * returns the id of the given operator
110  * returns -1 if the operator is not recognized
111  */
113 {
114  // level 2
115  if (opName=="&&") { return AND; }
116  if (opName=="||") { return OR; }
117 
118  // not operator
119  if (opName=="!") { return NOT; }
120 
121  return UNKNOWN_OP;
122 }
123 
124 /**
125  * Get next token in the current string expr.
126  * Uses the data in m_expr pointed to by m_e to
127  * produce m_tokenType and m_token, set m_err in case of an error
128  */
130 {
132  m_token.resize(0);
133 
134  //printf("\tgetToken e:{%c}, ascii=%i, col=%i\n", *e, *e, e-expr);
135 
136  // skip over whitespaces
137  while (*m_e == ' ' || *m_e == '\t') // space or tab
138  {
139  m_e++;
140  }
141 
142  // check for end of expression
143  if (*m_e=='\0')
144  {
145  // token is still empty
147  return;
148  }
149 
150  // check for parentheses
151  if (*m_e == '(' || *m_e == ')')
152  {
154  m_token += *m_e++;
155  return;
156  }
157 
158  // check for operators (delimeters)
159  if (isDelimiter(*m_e))
160  {
162  while (isDelimiter(*m_e))
163  {
164  m_token += *m_e++;
165  }
166  return;
167  }
168 
169  // check for variables
170  if (isAlpha(*m_e))
171  {
173  while (isAlphaNum(*m_e))
174  {
175  m_token += *m_e++;
176  }
177  return;
178  }
179 
180  // something unknown is found, wrong characters -> a syntax error
182  while (*m_e)
183  {
184  m_token += *m_e++;
185  }
186  m_err = QCString("Syntax error in part '")+m_token+"'";
187  return;
188 }
189 
190 
191 /**
192  * conditional operators AND and OR
193  */
195 {
196  bool ans = parseLevel2();
197  int opId = getOperatorId(m_token);
198 
199  while (opId==AND || opId==OR)
200  {
201  getToken();
202  ans = evalOperator(opId, ans, parseLevel2());
203  opId = getOperatorId(m_token);
204  }
205 
206  return ans;
207 }
208 
209 /**
210  * NOT
211  */
213 {
214  bool ans;
215  int opId = getOperatorId(m_token);
216  if (opId == NOT)
217  {
218  getToken();
219  ans = !parseLevel3();
220  }
221  else
222  {
223  ans = parseLevel3();
224  }
225 
226  return ans;
227 }
228 
229 
230 /**
231  * parenthesized expression or variable
232  */
234 {
235  // check if it is a parenthesized expression
236  if (m_tokenType == DELIMITER)
237  {
238  if (m_token=="(")
239  {
240  getToken();
241  int ans = parseLevel1();
242  if (m_tokenType!=DELIMITER || m_token!=")")
243  {
244  m_err="Parenthesis ) missing";
245  return FALSE;
246  }
247  getToken();
248  return ans;
249  }
250  }
251 
252  // if not parenthesized then the expression is a variable
253  return parseVar();
254 }
255 
256 
258 {
259  bool ans = 0;
260  switch (m_tokenType)
261  {
262  case VARIABLE:
263  // this is a variable
264  ans = evalVariable(m_token);
265  getToken();
266  break;
267 
268  default:
269  // syntax error or unexpected end of expression
270  if (m_token.isEmpty())
271  {
272  m_err="Unexpected end of expression";
273  return FALSE;
274  }
275  else
276  {
277  m_err="Value expected";
278  return FALSE;
279  }
280  break;
281  }
282  return ans;
283 }
284 
285 /**
286  * evaluate an operator for given valuess
287  */
288 bool CondParser::evalOperator(int opId, bool lhs, bool rhs)
289 {
290  switch (opId)
291  {
292  // level 2
293  case AND: return lhs && rhs;
294  case OR: return lhs || rhs;
295  }
296 
297  m_err = "Internal error unknown operator: id="+QCString().setNum(opId);
298  return FALSE;
299 }
300 
301 /**
302  * evaluate a variable
303  */
305 {
306  if (Config_getList("ENABLED_SECTIONS").find(varName)==-1) return FALSE;
307  return TRUE;
308 }
309 
TOKENTYPE m_tokenType
type of the token
Definition: condparser.h:59
bool resize(uint newlen)
Definition: qcstring.h:225
bool parseLevel2()
Definition: condparser.cpp:212
bool evalOperator(const int opId, bool lhs, bool rhs)
Definition: condparser.cpp:288
static QCString varName
static bool isAlpha(const char c)
Definition: condparser.cpp:98
bool isEmpty() const
Definition: qcstring.h:189
const bool FALSE
Definition: qglobal.h:370
#define Config_getList(val)
Definition: config.cpp:662
bool parseVar()
Definition: condparser.cpp:257
static bool isDelimiter(const char c)
Definition: condparser.cpp:90
QCString m_token
holds the token
Definition: condparser.h:58
fileName
Definition: dumpTree.py:9
const char * data() const
Definition: qcstring.h:207
static bool isAlphaNum(const char c)
Definition: condparser.cpp:103
void warn(const char *file, int line, const char *fmt,...)
Definition: message.cpp:183
bool parseLevel3()
Definition: condparser.cpp:233
QCString & setNum(short n)
Definition: qcstring.cpp:469
bool parseLevel1()
Definition: condparser.cpp:194
void getToken()
Definition: condparser.cpp:129
QCString m_expr
holds the expression
Definition: condparser.h:55
bool evalVariable(const char *varName)
Definition: condparser.cpp:304
bool parse(const char *fileName, int lineNr, const char *expr)
Definition: condparser.cpp:34
const bool TRUE
Definition: qglobal.h:371
QCString m_err
error state
Definition: condparser.h:54
const char * m_e
points to a character in expr
Definition: condparser.h:56
int getOperatorId(const QCString &opName)
Definition: condparser.cpp:112