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
22 #include "condparser.h"
29 * parses and evaluates the given expression.
31 * - On error, an error message is returned.
32 * - On success, the result of the expression is either "1" or "0".
34 bool CondParser::parse(const char *fileName,int lineNr,const char *expr)
37 m_tokenType = NOTHING;
39 // initialize all variables
40 m_e = m_expr; // let m_e point to the start of the expression
44 if (m_tokenType==DELIMITER && m_token.isEmpty())
46 // empty expression: answer==FALSE
48 else if (m_err.isEmpty())
50 answer = parseLevel1();
53 // check for garbage at the end of the expression
54 // an expression ends with a character '\0' and token_type = delimiter
55 if (m_tokenType!=DELIMITER || !m_token.isEmpty())
57 if (m_tokenType == DELIMITER)
59 if (m_token=="(" || m_token==")")
61 m_err=QCString("Unexpected parenthesis ")+m_token+"'";
65 // user entered a not existing operator like "//"
66 m_err=QCString("Unexpected operator ")+m_token+"'";
71 m_err=QCString("Unexpected part '")+m_token+"'";
78 warn(fileName,lineNr,"problem evaluating expression '%s': %s",
81 //printf("expr='%s' answer=%d\n",expr,answer);
87 * checks if the given char c is a delimiter
88 * minus is checked apart, can be unary minus
90 static bool isDelimiter(const char c)
92 return c=='&' || c=='|' || c=='!';
96 * checks if the given char c is a letter or underscore
98 static bool isAlpha(const char c)
100 return (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='_';
103 static bool isAlphaNumSpec(const char c)
105 return isAlpha(c) || (c>='0' && c<='9') || c=='-' || c=='.' ||
106 (((unsigned char)c)>=0x80 && ((unsigned char)c)<=0xFF);
110 * returns the id of the given operator
111 * returns -1 if the operator is not recognized
113 int CondParser::getOperatorId(const QCString &opName)
116 if (opName=="&&") { return AND; }
117 if (opName=="||") { return OR; }
120 if (opName=="!") { return NOT; }
126 * Get next token in the current string expr.
127 * Uses the data in m_expr pointed to by m_e to
128 * produce m_tokenType and m_token, set m_err in case of an error
130 void CondParser::getToken()
132 m_tokenType = NOTHING;
135 //printf("\tgetToken e:{%c}, ascii=%i, col=%i\n", *e, *e, e-expr);
137 // skip over whitespaces
138 while (*m_e == ' ' || *m_e == '\t') // space or tab
143 // check for end of expression
146 // token is still empty
147 m_tokenType = DELIMITER;
151 // check for parentheses
152 if (*m_e == '(' || *m_e == ')')
154 m_tokenType = DELIMITER;
159 // check for operators (delimiters)
160 if (isDelimiter(*m_e))
162 m_tokenType = DELIMITER;
163 while (isDelimiter(*m_e))
170 // check for variables
173 m_tokenType = VARIABLE;
174 while (isAlphaNumSpec(*m_e))
181 // something unknown is found, wrong characters -> a syntax error
182 m_tokenType = UNKNOWN;
187 m_err = QCString("Syntax error in part '")+m_token+"'";
193 * conditional operators AND and OR
195 bool CondParser::parseLevel1()
197 bool ans = parseLevel2();
198 int opId = getOperatorId(m_token);
200 while (opId==AND || opId==OR)
203 ans = evalOperator(opId, ans, parseLevel2());
204 opId = getOperatorId(m_token);
213 bool CondParser::parseLevel2()
216 int opId = getOperatorId(m_token);
220 ans = !parseLevel3();
232 * parenthesized expression or variable
234 bool CondParser::parseLevel3()
236 // check if it is a parenthesized expression
237 if (m_tokenType == DELIMITER)
242 int ans = parseLevel1();
243 if (m_tokenType!=DELIMITER || m_token!=")")
245 m_err="Parenthesis ) missing";
253 // if not parenthesized then the expression is a variable
258 bool CondParser::parseVar()
264 // this is a variable
265 ans = evalVariable(m_token);
270 // syntax error or unexpected end of expression
271 if (m_token.isEmpty())
273 m_err="Unexpected end of expression";
278 m_err="Value expected";
287 * evaluate an operator for given values
289 bool CondParser::evalOperator(int opId, bool lhs, bool rhs)
294 case AND: return lhs && rhs;
295 case OR: return lhs || rhs;
298 m_err = "Internal error unknown operator: id="+QCString().setNum(opId);
303 * evaluate a variable
305 bool CondParser::evalVariable(const char *varName)
307 if (Config_getList(ENABLED_SECTIONS).find(varName)==-1) return FALSE;