Doxygen
Loading...
Searching...
No Matches
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 <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 */
36bool 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();
47 if (m_tokenType==DELIMITER && m_token.isEmpty())
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 */
69static 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 */
77static bool isAlpha(const char c)
78{
79 return (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='_';
80}
81
82static bool isAlphaNumSpec(const char c)
83{
84 return isAlpha(c) || (c>='0' && c<='9') || c=='-' || c=='.' || (static_cast<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.clear();
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 int opId = getOperatorId(m_token);
194 if (opId == NOT)
195 {
196 getToken();
197 return !parseLevel3();
198 }
199 else
200 {
201 return parseLevel3();
202 }
203}
204
205
206/**
207 * parenthesized expression or variable
208 */
210{
211 // check if it is a parenthesized expression
212 if (m_tokenType == DELIMITER)
213 {
214 if (m_token=="(")
215 {
216 getToken();
217 bool ans = parseLevel1();
218 if (m_tokenType!=DELIMITER || m_token!=")")
219 {
220 m_err="Parenthesis ) missing";
221 return FALSE;
222 }
223 getToken();
224 return ans;
225 }
226 }
227
228 // if not parenthesized then the expression is a variable
229 return parseVar();
230}
231
232
234{
235 bool ans = false;
236 switch (m_tokenType)
237 {
238 case VARIABLE:
239 // this is a variable
240 ans = evalVariable(m_token);
241 getToken();
242 break;
243
244 default:
245 // syntax error or unexpected end of expression
246 if (m_token.isEmpty())
247 {
248 m_err="Unexpected end of expression";
249 return FALSE;
250 }
251 else
252 {
253 m_err="Value expected";
254 return FALSE;
255 }
256 break;
257 }
258 return ans;
259}
260
261/**
262 * evaluate an operator for given values
263 */
264bool CondParser::evalOperator(int opId, bool lhs, bool rhs)
265{
266 switch (opId)
267 {
268 // level 2
269 case AND: return lhs && rhs;
270 case OR: return lhs || rhs;
271 }
272
273 m_err = "Internal error unknown operator: id="+QCString().setNum(opId);
274 return FALSE;
275}
276
277/**
278 * evaluate a variable
279 */
281{
282 const StringVector &list = Config_getList(ENABLED_SECTIONS);
283 return std::find(list.begin(),list.end(),varName.str())!=list.end();
284}
285
QCString m_token
holds the token
Definition condparser.h:58
bool parseLevel2()
NOT.
QCString m_err
error state
Definition condparser.h:54
TOKENTYPE m_tokenType
type of the token
Definition condparser.h:59
bool evalVariable(const QCString &varName)
evaluate a variable
bool parseLevel1()
conditional operators AND and OR
void getToken()
Get next token in the current string expr.
QCString m_expr
holds the expression
Definition condparser.h:55
bool evalOperator(const int opId, bool lhs, bool rhs)
evaluate an operator for given values
const char * m_e
points to a character in expr
Definition condparser.h:56
bool parseVar()
bool parse(const QCString &fileName, int lineNr, const QCString &expr)
Copyright (C) 1997-2015 by Dimitri van Heesch.
bool parseLevel3()
parenthesized expression or variable
int getOperatorId(const QCString &opName)
returns the id of the given operator returns -1 if the operator is not recognized
This is an alternative implementation of QCString.
Definition qcstring.h:101
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
const std::string & str() const
Definition qcstring.h:537
QCString & setNum(short n)
Definition qcstring.h:444
static bool isDelimiter(const char c)
checks if the given char c is a delimiter minus is checked apart, can be unary minus
static bool isAlphaNumSpec(const char c)
static bool isAlpha(const char c)
checks if the given char c is a letter or underscore
#define Config_getList(name)
Definition config.h:38
std::vector< std::string > StringVector
Definition containers.h:33
#define warn(file, line, fmt,...)
Definition message.h:59
const char * qPrint(const char *s)
Definition qcstring.h:672
#define FALSE
Definition qcstring.h:34