Doxygen
condparser.cpp
浏览该文件的文档.
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 <algorithm>
23 
24 #include "condparser.h"
25 #include "config.h"
26 #include "message.h"
27 
28 // declarations
29 
30 /**
31  * parses and evaluates the given expression.
32  * @returns
33  * - On error, an error message is returned.
34  * - On success, the result of the expression is either "1" or "0".
35  */
36 bool CondParser::parse(const QCString &fileName,int lineNr,const QCString &expr)
37 {
38  if (expr.isEmpty()) return false;
39  m_expr = expr;
41 
42  // initialize all variables
43  m_e = m_expr.data(); // let m_e point to the start of the expression
44 
45  bool answer=false;
46  getToken();
48  {
49  // empty expression: answer==FALSE
50  }
51  else if (m_err.isEmpty())
52  {
53  answer = parseLevel1();
54  }
55  if (!m_err.isEmpty())
56  {
57  warn(fileName,lineNr,"problem evaluating expression '%s': %s",
58  qPrint(expr),qPrint(m_err));
59  }
60  //printf("expr='%s' answer=%d\n",expr,answer);
61  return answer;
62 }
63 
64 
65 /**
66  * checks if the given char c is a delimiter
67  * minus is checked apart, can be unary minus
68  */
69 static bool isDelimiter(const char c)
70 {
71  return c=='&' || c=='|' || c=='!';
72 }
73 
74 /**
75  * checks if the given char c is a letter or underscore
76  */
77 static bool isAlpha(const char c)
78 {
79  return (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='_';
80 }
81 
82 static bool isAlphaNumSpec(const char c)
83 {
84  return isAlpha(c) || (c>='0' && c<='9') || c=='-' || c=='.' || (((unsigned char)c)>=0x80);
85 }
86 
87 /**
88  * returns the id of the given operator
89  * returns -1 if the operator is not recognized
90  */
92 {
93  // level 2
94  if (opName=="&&") { return AND; }
95  if (opName=="||") { return OR; }
96 
97  // not operator
98  if (opName=="!") { return NOT; }
99 
100  return UNKNOWN_OP;
101 }
102 
103 /**
104  * Get next token in the current string expr.
105  * Uses the data in m_expr pointed to by m_e to
106  * produce m_tokenType and m_token, set m_err in case of an error
107  */
109 {
111  m_token.resize(0);
112 
113  //printf("\tgetToken e:{%c}, ascii=%i, col=%i\n", *e, *e, e-expr);
114 
115  // skip over whitespaces
116  while (*m_e == ' ' || *m_e == '\t' || *m_e == '\n') // space or tab or newline
117  {
118  m_e++;
119  }
120 
121  // check for end of expression
122  if (*m_e=='\0')
123  {
124  // token is still empty
126  return;
127  }
128 
129  // check for parentheses
130  if (*m_e == '(' || *m_e == ')')
131  {
133  m_token += *m_e++;
134  return;
135  }
136 
137  // check for operators (delimiters)
138  if (isDelimiter(*m_e))
139  {
141  while (isDelimiter(*m_e))
142  {
143  m_token += *m_e++;
144  }
145  return;
146  }
147 
148  // check for variables
149  if (isAlpha(*m_e))
150  {
152  while (isAlphaNumSpec(*m_e))
153  {
154  m_token += *m_e++;
155  }
156  return;
157  }
158 
159  // something unknown is found, wrong characters -> a syntax error
161  while (*m_e)
162  {
163  m_token += *m_e++;
164  }
165  m_err = QCString("Syntax error in part '")+m_token+"'";
166  return;
167 }
168 
169 
170 /**
171  * conditional operators AND and OR
172  */
174 {
175  bool ans = parseLevel2();
176  int opId = getOperatorId(m_token);
177 
178  while (opId==AND || opId==OR)
179  {
180  getToken();
181  ans = evalOperator(opId, ans, parseLevel2());
182  opId = getOperatorId(m_token);
183  }
184 
185  return ans;
186 }
187 
188 /**
189  * NOT
190  */
192 {
193  bool ans;
194  int opId = getOperatorId(m_token);
195  if (opId == NOT)
196  {
197  getToken();
198  ans = !parseLevel3();
199  }
200  else
201  {
202  ans = parseLevel3();
203  }
204 
205  return ans;
206 }
207 
208 
209 /**
210  * parenthesized expression or variable
211  */
213 {
214  // check if it is a parenthesized expression
215  if (m_tokenType == DELIMITER)
216  {
217  if (m_token=="(")
218  {
219  getToken();
220  int ans = parseLevel1();
221  if (m_tokenType!=DELIMITER || m_token!=")")
222  {
223  m_err="Parenthesis ) missing";
224  return FALSE;
225  }
226  getToken();
227  return ans;
228  }
229  }
230 
231  // if not parenthesized then the expression is a variable
232  return parseVar();
233 }
234 
235 
237 {
238  bool ans = false;
239  switch (m_tokenType)
240  {
241  case VARIABLE:
242  // this is a variable
243  ans = evalVariable(m_token);
244  getToken();
245  break;
246 
247  default:
248  // syntax error or unexpected end of expression
249  if (m_token.isEmpty())
250  {
251  m_err="Unexpected end of expression";
252  return FALSE;
253  }
254  else
255  {
256  m_err="Value expected";
257  return FALSE;
258  }
259  break;
260  }
261  return ans;
262 }
263 
264 /**
265  * evaluate an operator for given values
266  */
267 bool CondParser::evalOperator(int opId, bool lhs, bool rhs)
268 {
269  switch (opId)
270  {
271  // level 2
272  case AND: return lhs && rhs;
273  case OR: return lhs || rhs;
274  }
275 
276  m_err = "Internal error unknown operator: id="+QCString().setNum(opId);
277  return FALSE;
278 }
279 
280 /**
281  * evaluate a variable
282  */
283 bool CondParser::evalVariable(const QCString &varName)
284 {
285  const StringVector &list = Config_getList(ENABLED_SECTIONS);
286  return std::find(list.begin(),list.end(),varName.str())!=list.end();
287 }
288 
StringVector
std::vector< std::string > StringVector
Definition: containers.h:32
CondParser::DELIMITER
@ DELIMITER
Definition: condparser.h:39
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
isAlphaNumSpec
static bool isAlphaNumSpec(const char c)
Definition: condparser.cpp:82
CondParser::UNKNOWN
@ UNKNOWN
Definition: condparser.h:41
QCString::str
std::string str() const
Definition: qcstring.h:442
CondParser::VARIABLE
@ VARIABLE
Definition: condparser.h:40
CondParser::parseVar
bool parseVar()
Definition: condparser.cpp:236
CondParser::UNKNOWN_OP
@ UNKNOWN_OP
Definition: condparser.h:45
CondParser::parseLevel1
bool parseLevel1()
conditional operators AND and OR
Definition: condparser.cpp:173
CondParser::parseLevel2
bool parseLevel2()
NOT
Definition: condparser.cpp:191
warn
void warn(const QCString &file, int line, const char *fmt,...)
Definition: message.cpp:151
CondParser::m_tokenType
TOKENTYPE m_tokenType
type of the token
Definition: condparser.h:59
CondParser::getToken
void getToken()
Get next token in the current string expr.
Definition: condparser.cpp:108
CondParser::m_token
QCString m_token
holds the token
Definition: condparser.h:58
CondParser::evalOperator
bool evalOperator(const int opId, bool lhs, bool rhs)
evaluate an operator for given values
Definition: condparser.cpp:267
CondParser::m_err
QCString m_err
error state
Definition: condparser.h:54
message.h
isAlpha
static bool isAlpha(const char c)
checks if the given char c is a letter or underscore
Definition: condparser.cpp:77
CondParser::evalVariable
bool evalVariable(const QCString &varName)
evaluate a variable
Definition: condparser.cpp:283
CondParser::m_expr
QCString m_expr
holds the expression
Definition: condparser.h:55
CondParser::m_e
const char * m_e
points to a character in expr
Definition: condparser.h:56
CondParser::parseLevel3
bool parseLevel3()
parenthesized expression or variable
Definition: condparser.cpp:212
CondParser::parse
bool parse(const QCString &fileName, int lineNr, const QCString &expr)
Copyright (C) 1997-2015 by Dimitri van Heesch.
Definition: condparser.cpp:36
CondParser::getOperatorId
int getOperatorId(const QCString &opName)
returns the id of the given operator returns -1 if the operator is not recognized
Definition: condparser.cpp:91
QCString::setNum
QCString & setNum(short n)
Definition: qcstring.h:372
CondParser::NOTHING
@ NOTHING
Definition: condparser.h:38
CondParser::OR
@ OR
Definition: condparser.h:47
isDelimiter
static bool isDelimiter(const char c)
checks if the given char c is a delimiter minus is checked apart, can be unary minus
Definition: condparser.cpp:69
CondParser::NOT
@ NOT
Definition: condparser.h:48
qPrint
const char * qPrint(const char *s)
Definition: qcstring.h:589
config.h
QCString::data
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string
Definition: qcstring.h:153
CondParser::AND
@ AND
Definition: condparser.h:46
condparser.h
QCString::resize
bool resize(size_t newlen)
Resizes the string to hold newlen characters (this value should also count the 0-terminator).
Definition: qcstring.h:164
Config_getList
#define Config_getList(name)
Definition: config.h:37
FALSE
#define FALSE
Definition: qcstring.h:33
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108