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) void Token::astOperand1(Token *tok)
{ {
if (_astOperand1)
_astOperand1->_astParent = nullptr;
// goto parent operator // goto parent operator
while (tok->_astParent) if (tok) {
tok = tok->_astParent; while (tok->_astParent)
tok->_astParent = this; tok = tok->_astParent;
tok->_astParent = this;
}
_astOperand1 = tok; _astOperand1 = tok;
} }
void Token::astOperand2(Token *tok) void Token::astOperand2(Token *tok)
{ {
if (_astOperand2)
_astOperand2->_astParent = nullptr;
// goto parent operator // goto parent operator
while (tok->_astParent) if (tok) {
tok = tok->_astParent; while (tok->_astParent)
tok->_astParent = this; tok = tok->_astParent;
tok->_astParent = this;
}
_astOperand2 = tok; _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) static bool isPrefixUnary(const Token* tok)
{ {
if (!tok->previous() 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))) && (tok->previous()->type() != Token::eIncDecOp || tok->type() == Token::eIncDecOp)))
return true; return true;
@ -486,7 +486,7 @@ static void compilePrecedence2(Token *&tok, std::stack<Token*> &op, unsigned int
while (tok) { while (tok) {
if (tok->type() == Token::eIncDecOp && !isPrefixUnary(tok)) { if (tok->type() == Token::eIncDecOp && !isPrefixUnary(tok)) {
compileUnaryOp(tok, compileScope, op, depth); compileUnaryOp(tok, compileScope, op, depth);
} else if (tok->str() == ".") { } else if (tok->str() == "." && tok->strAt(1) != "*") {
compileBinOp(tok, compileScope, op, depth); compileBinOp(tok, compileScope, op, depth);
} else if (tok->str() == "[") { } else if (tok->str() == "[") {
Token* tok2 = tok; 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); 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) { while (tok) {
if (Token::Match(tok, "[*/%]")) { if (Token::Match(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() == "*") while (tok2->next() && tok2->str() == "*")
tok2 = tok2->next(); tok2 = tok2->next();
if (Token::Match(tok2, "[,)]")) { if (Token::Match(tok2, "[,)]")) {
//tok = tok2->next();
break; break;
} }
} }
compileBinOp(tok, compilePrecedence3, op, depth); compileBinOp(tok, compilePointerToElem, op, depth);
} else break; } 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: // 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." // "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->isAssignmentOp() || Token::Match(tok, "[?:]")) {
if (tok->str() == "?" && tok->strAt(1) == ":") {
op.push(0);
}
compileBinOp(tok, compileAssignTernary, op, depth); compileBinOp(tok, compileAssignTernary, op, depth);
} else break; } else break;
} }

View File

@ -10384,7 +10384,7 @@ private:
// Basic AST validation // Basic AST validation
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { 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(); 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^=", 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 // assignments are executed from right to left
ASSERT_EQUALS("abc==", testAst("a=b=c;")); 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( 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("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("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 void astpar() const { // parentheses