From d1c4777053d0ebee51efe12f0ceba6525b9331da Mon Sep 17 00:00:00 2001 From: PKEuS Date: Mon, 19 May 2014 21:54:59 +0200 Subject: [PATCH] Fixed two bugs in AST compilation (#5830): - Correctly parse operators .* and ->* - Support empty branch in ternary expression (a?:c) --- lib/token.cpp | 20 ++++++++++++++------ lib/tokenlist.cpp | 22 +++++++++++++++++----- test/testtokenize.cpp | 7 ++++++- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/lib/token.cpp b/lib/token.cpp index cd0ceb4d4..43c00dddb 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -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; } diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 1569072f5..ce3981870 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -473,7 +473,7 @@ static void compileScope(Token *&tok, std::stack &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 &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 &op, unsigned int } } -static void compileMulDiv(Token *&tok, std::stack &op, unsigned int depth) +static void compilePointerToElem(Token *&tok, std::stack &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 &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 &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 &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; } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 698723a81..458109af7 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -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