2 * Copyright (C) 1997-2015 by Dimitri van Heesch.
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.
10 * Documents produced by Doxygen are derivative works derived from the
11 * input used in their production; they are not affected by this license.
13 * C++ Expression parser for ENABLED_SECTIONS in Doxygen
24 #include "condparser.h"
31 * parses and evaluates the given expression.
33 * - On error, an error message is returned.
34 * - On success, the result of the expression is either "1" or "0".
36 bool CondParser::parse(const QCString &fileName,int lineNr,const QCString &expr)
38 if (expr.isEmpty()) return false;
40 m_tokenType = NOTHING;
42 // initialize all variables
43 m_e = m_expr.data(); // let m_e point to the start of the expression
47 if (m_tokenType==DELIMITER && m_token.isEmpty())
49 // empty expression: answer==FALSE
51 else if (m_err.isEmpty())
53 answer = parseLevel1();
57 warn(fileName,lineNr,"problem evaluating expression '%s': %s",
58 qPrint(expr),qPrint(m_err));
60 //printf("expr='%s' answer=%d\n",expr,answer);
66 * checks if the given char c is a delimiter
67 * minus is checked apart, can be unary minus
69 static bool isDelimiter(const char c)
71 return c=='&' || c=='|' || c=='!';
75 * checks if the given char c is a letter or underscore
77 static bool isAlpha(const char c)
79 return (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='_';
82 static bool isAlphaNumSpec(const char c)
84 return isAlpha(c) || (c>='0' && c<='9') || c=='-' || c=='.' || (static_cast<unsigned char>(c)>=0x80);
88 * returns the id of the given operator
89 * returns -1 if the operator is not recognized
91 int CondParser::getOperatorId(const QCString &opName)
94 if (opName=="&&") { return AND; }
95 if (opName=="||") { return OR; }
98 if (opName=="!") { return NOT; }
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
108 void CondParser::getToken()
110 m_tokenType = NOTHING;
113 //printf("\tgetToken e:{%c}, ascii=%i, col=%i\n", *e, *e, e-expr);
115 // skip over whitespaces
116 while (*m_e == ' ' || *m_e == '\t' || *m_e == '\n') // space or tab or newline
121 // check for end of expression
124 // token is still empty
125 m_tokenType = DELIMITER;
129 // check for parentheses
130 if (*m_e == '(' || *m_e == ')')
132 m_tokenType = DELIMITER;
137 // check for operators (delimiters)
138 if (isDelimiter(*m_e))
140 m_tokenType = DELIMITER;
141 while (isDelimiter(*m_e))
148 // check for variables
151 m_tokenType = VARIABLE;
152 while (isAlphaNumSpec(*m_e))
159 // something unknown is found, wrong characters -> a syntax error
160 m_tokenType = UNKNOWN;
165 m_err = QCString("Syntax error in part '")+m_token+"'";
171 * conditional operators AND and OR
173 bool CondParser::parseLevel1()
175 bool ans = parseLevel2();
176 int opId = getOperatorId(m_token);
178 while (opId==AND || opId==OR)
181 ans = evalOperator(opId, ans, parseLevel2());
182 opId = getOperatorId(m_token);
191 bool CondParser::parseLevel2()
194 int opId = getOperatorId(m_token);
198 ans = !parseLevel3();
210 * parenthesized expression or variable
212 bool CondParser::parseLevel3()
214 // check if it is a parenthesized expression
215 if (m_tokenType == DELIMITER)
220 bool ans = parseLevel1();
221 if (m_tokenType!=DELIMITER || m_token!=")")
223 m_err="Parenthesis ) missing";
231 // if not parenthesized then the expression is a variable
236 bool CondParser::parseVar()
242 // this is a variable
243 ans = evalVariable(m_token);
248 // syntax error or unexpected end of expression
249 if (m_token.isEmpty())
251 m_err="Unexpected end of expression";
256 m_err="Value expected";
265 * evaluate an operator for given values
267 bool CondParser::evalOperator(int opId, bool lhs, bool rhs)
272 case AND: return lhs && rhs;
273 case OR: return lhs || rhs;
276 m_err = "Internal error unknown operator: id="+QCString().setNum(opId);
281 * evaluate a variable
283 bool CondParser::evalVariable(const QCString &varName)
285 const StringVector &list = Config_getList(ENABLED_SECTIONS);
286 return std::find(list.begin(),list.end(),varName.str())!=list.end();