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 '{}': {}", expr, m_err);
58 }
59 //printf("expr='%s' answer=%d\n",expr,answer);
60 return answer;
61}
62
63
64/**
65 * checks if the given char c is a delimiter
66 * minus is checked apart, can be unary minus
67 */
68static bool isDelimiter(const char c)
69{
70 return c=='&' || c=='|' || c=='!';
71}
72
73/**
74 * checks if the given char c is a letter or underscore
75 */
76static bool isAlpha(const char c)
77{
78 return (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='_';
79}
80
81static bool isAlphaNumSpec(const char c)
82{
83 return isAlpha(c) || (c>='0' && c<='9') || c=='-' || c=='.' || (static_cast<unsigned char>(c)>=0x80);
84}
85
86/**
87 * returns the id of the given operator
88 * returns -1 if the operator is not recognized
89 */
91{
92 // level 2
93 if (opName=="&&") { return AND; }
94 if (opName=="||") { return OR; }
95
96 // not operator
97 if (opName=="!") { return NOT; }
98
99 return UNKNOWN_OP;
100}
101
102/**
103 * Get next token in the current string expr.
104 * Uses the data in m_expr pointed to by m_e to
105 * produce m_tokenType and m_token, set m_err in case of an error
106 */
108{
110 m_token.clear();
111
112 //printf("\tgetToken e:{%c}, ascii=%i, col=%i\n", *e, *e, e-expr);
113
114 // skip over whitespaces
115 while (*m_e == ' ' || *m_e == '\t' || *m_e == '\n') // space or tab or newline
116 {
117 m_e++;
118 }
119
120 // check for end of expression
121 if (*m_e=='\0')
122 {
123 // token is still empty
125 return;
126 }
127
128 // check for parentheses
129 if (*m_e == '(' || *m_e == ')')
130 {
132 m_token += *m_e++;
133 return;
134 }
135
136 // check for operators (delimiters)
137 if (isDelimiter(*m_e))
138 {
140 while (isDelimiter(*m_e))
141 {
142 m_token += *m_e++;
143 }
144 return;
145 }
146
147 // check for variables
148 if (isAlpha(*m_e))
149 {
151 while (isAlphaNumSpec(*m_e))
152 {
153 m_token += *m_e++;
154 }
155 return;
156 }
157
158 // something unknown is found, wrong characters -> a syntax error
160 while (*m_e)
161 {
162 m_token += *m_e++;
163 }
164 m_err = QCString("Syntax error in part '")+m_token+"'";
165 return;
166}
167
168
169/**
170 * conditional operators AND and OR
171 */
173{
174 bool ans = parseLevel2();
175 int opId = getOperatorId(m_token);
176
177 while (opId==AND || opId==OR)
178 {
179 getToken();
180 ans = evalOperator(opId, ans, parseLevel2());
181 opId = getOperatorId(m_token);
182 }
183
184 return ans;
185}
186
187/**
188 * NOT
189 */
191{
192 int opId = getOperatorId(m_token);
193 if (opId == NOT)
194 {
195 getToken();
196 return !parseLevel3();
197 }
198 else
199 {
200 return parseLevel3();
201 }
202}
203
204
205/**
206 * parenthesized expression or variable
207 */
209{
210 // check if it is a parenthesized expression
211 if (m_tokenType == DELIMITER)
212 {
213 if (m_token=="(")
214 {
215 getToken();
216 bool ans = parseLevel1();
217 if (m_tokenType!=DELIMITER || m_token!=")")
218 {
219 m_err="Parenthesis ) missing";
220 return FALSE;
221 }
222 getToken();
223 return ans;
224 }
225 }
226
227 // if not parenthesized then the expression is a variable
228 return parseVar();
229}
230
231
233{
234 bool ans = false;
235 switch (m_tokenType)
236 {
237 case VARIABLE:
238 // this is a variable
239 ans = evalVariable(m_token);
240 getToken();
241 break;
242
243 default:
244 // syntax error or unexpected end of expression
245 if (m_token.isEmpty())
246 {
247 m_err="Unexpected end of expression";
248 return FALSE;
249 }
250 else
251 {
252 m_err="Value expected";
253 return FALSE;
254 }
255 break;
256 }
257 return ans;
258}
259
260/**
261 * evaluate an operator for given values
262 */
263bool CondParser::evalOperator(int opId, bool lhs, bool rhs)
264{
265 switch (opId)
266 {
267 // level 2
268 case AND: return lhs && rhs;
269 case OR: return lhs || rhs;
270 }
271
272 m_err = "Internal error unknown operator: id="+QCString().setNum(opId);
273 return FALSE;
274}
275
276/**
277 * evaluate a variable
278 */
280{
281 const StringVector &list = Config_getList(ENABLED_SECTIONS);
282 return std::find(list.begin(),list.end(),varName.str())!=list.end();
283}
284
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:97
#define FALSE
Definition qcstring.h:34