Fixed two bugs in AST compilation (#5830):

- Correctly parse operators .* and ->*
- Support empty branch in ternary expression (a?:c)
This commit is contained in:
PKEuS 2014-05-19 21:54:59 +02:00
parent 5c566e838c
commit d1c4777053
3 changed files with 37 additions and 12 deletions

View File

@ -1094,19 +1094,27 @@ std::string Token::stringifyList(bool varid) const
void Token::astOperand1(Token *tok)
{
if (_astOperand1)
_astOperand1->_astParent = nullptr;
// goto parent operator
while (tok->_astParent)
tok = tok->_astParent;
tok->_astParent = this;
if (tok) {
while (tok->_astParent)
tok = tok->_astParent;
tok->_astParent = this;
}
_astOperand1 = tok;
}
void Token::astOperand2(Token *tok)
{
if (_astOperand2)
_astOperand2->_astParent = nullptr;
// goto parent operator
while (tok->_astParent)
tok = tok->_astParent;
tok->_astParent = this;
if (tok) {
while (tok->_astParent)
tok = tok->_astParent;
tok->_astParent = this;
}
_astOperand2 = tok;
}

View File

@ -473,7 +473,7 @@ static void compileScope(Token *&tok, std::stack<Token*> &op, unsigned int depth
static bool isPrefixUnary(const Token* tok)
{
if (!tok->previous()
|| (Token::Match(tok->previous(), "(|[|{|%op%|;|}|?|:|,|return|throw")
|| (Token::Match(tok->previous(), "(|[|{|%op%|;|}|?|:|,|.|return|throw")
&& (tok->previous()->type() != Token::eIncDecOp || tok->type() == Token::eIncDecOp)))
return true;
@ -486,7 +486,7 @@ static void compilePrecedence2(Token *&tok, std::stack<Token*> &op, unsigned int
while (tok) {
if (tok->type() == Token::eIncDecOp && !isPrefixUnary(tok)) {
compileUnaryOp(tok, compileScope, op, depth);
} else if (tok->str() == ".") {
} else if (tok->str() == "." && tok->strAt(1) != "*") {
compileBinOp(tok, compileScope, op, depth);
} else if (tok->str() == "[") {
Token* tok2 = tok;
@ -530,9 +530,19 @@ static void compilePrecedence3(Token *&tok, std::stack<Token*> &op, unsigned int
}
}
static void compileMulDiv(Token *&tok, std::stack<Token*> &op, unsigned int depth)
static void compilePointerToElem(Token *&tok, std::stack<Token*> &op, unsigned int depth)
{
compilePrecedence3(tok, op, depth);
while (tok) {
if (Token::simpleMatch(tok, ". *")) {
compileBinOp(tok, compilePrecedence3, op, depth);
} else break;
}
}
static void compileMulDiv(Token *&tok, std::stack<Token*> &op, unsigned int depth)
{
compilePointerToElem(tok, op, depth);
while (tok) {
if (Token::Match(tok, "[*/%]")) {
if (Token::Match(tok, "* [*,)]")) {
@ -540,11 +550,10 @@ static void compileMulDiv(Token *&tok, std::stack<Token*> &op, unsigned int dept
while (tok2->next() && tok2->str() == "*")
tok2 = tok2->next();
if (Token::Match(tok2, "[,)]")) {
//tok = tok2->next();
break;
}
}
compileBinOp(tok, compilePrecedence3, op, depth);
compileBinOp(tok, compilePointerToElem, op, depth);
} else break;
}
}
@ -646,6 +655,9 @@ static void compileAssignTernary(Token *&tok, std::stack<Token*> &op, unsigned i
// TODO: http://en.cppreference.com/w/cpp/language/operator_precedence says:
// "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
if (tok->isAssignmentOp() || Token::Match(tok, "[?:]")) {
if (tok->str() == "?" && tok->strAt(1) == ":") {
op.push(0);
}
compileBinOp(tok, compileAssignTernary, op, depth);
} else break;
}

View File

@ -10384,7 +10384,7 @@ private:
// Basic AST validation
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (tok->astOperand2() && !tok->astOperand1() && tok->str() != ";")
if (tok->astOperand2() && !tok->astOperand1() && tok->str() != ";" && tok->str() != ":")
return "Op2 but no Op1 for token: " + tok->str();
}
@ -10433,6 +10433,8 @@ private:
ASSERT_EQUALS("ab|=", testAst("a|=b;"));
ASSERT_EQUALS("ab^=", testAst("a^=b;"));
ASSERT_EQUALS("ab*c*.(+return", testAst("return a + ((*b).*c)();"));
// assignments are executed from right to left
ASSERT_EQUALS("abc==", testAst("a=b=c;"));
@ -10465,6 +10467,9 @@ private:
ASSERT_EQUALS("ifx( i0= whilei(", testAst("if (x) { ({ int i = 0; while(i); }) };"));
ASSERT_EQUALS("ifx( BUG_ON{!( i0= whilei(", testAst("if (x) { BUG_ON(!({int i=0; while(i);})); }"));
ASSERT_EQUALS("v0= while{( v0= while{( v0=", testAst("({ v = 0; }); while (({ v = 0; }) != 0); while (({ v = 0; }) != 0);"));
ASSERT_EQUALS("abc.1:?1+bd.1:?+=", testAst("a =(b.c ? : 1) + 1 + (b.d ? : 1);"));
}
void astpar() const { // parentheses