Tokenizer: improve the new 'skipTernaryOp' function by supporting GCC '{(var|num;)}' statement expression extension; improve 'Tokenizer::simplifyQuestionMark' by supporting simplification with 'case' before ternary operation, using skipTernaryOp to get colon and, most importantly, supporting indented '?:' operations.
This commit is contained in:
parent
d4a3c1617a
commit
1951d1cdc5
|
@ -2370,6 +2370,11 @@ static Token *skipTernaryOp(Token *tok)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//allow GCC '({ %var%|%num% ; })' statement expression extension
|
||||||
|
if (Token::Match(tok, "( { %any% ; } )") &&
|
||||||
|
(tok->tokAt(2)->isNumber() || tok->tokAt(2)->isName())) {
|
||||||
|
tok = tok->link();
|
||||||
|
}
|
||||||
if (Token::Match(tok->next(), "[{};]"))
|
if (Token::Match(tok->next(), "[{};]"))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4426,7 +4431,7 @@ bool Tokenizer::simplifyQuestionMark()
|
||||||
if (!tok->tokAt(-2))
|
if (!tok->tokAt(-2))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!Token::Match(tok->tokAt(-2), "[=,(]"))
|
if (!Token::Match(tok->tokAt(-2), "=|,|(|case"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!tok->previous()->isBoolean() &&
|
if (!tok->previous()->isBoolean() &&
|
||||||
|
@ -4434,19 +4439,10 @@ bool Tokenizer::simplifyQuestionMark()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Find the ":" token..
|
// Find the ":" token..
|
||||||
Token *semicolon = 0;
|
Token *semicolon = skipTernaryOp(tok);
|
||||||
for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
|
if (!semicolon || semicolon->previous()->str() != ":" || !semicolon->next())
|
||||||
if (tok2->str() == "(" || tok2->str() == "[")
|
|
||||||
tok2 = tok2->link();
|
|
||||||
else if (tok2->str() == ")" || tok2->str() == "]")
|
|
||||||
break;
|
|
||||||
else if (tok2->str() == ":") {
|
|
||||||
semicolon = tok2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!semicolon || !semicolon->next())
|
|
||||||
continue;
|
continue;
|
||||||
|
semicolon = semicolon->previous();
|
||||||
|
|
||||||
if (tok->previous()->str() == "false" ||
|
if (tok->previous()->str() == "false" ||
|
||||||
tok->previous()->str() == "0") {
|
tok->previous()->str() == "0") {
|
||||||
|
@ -4480,24 +4476,18 @@ bool Tokenizer::simplifyQuestionMark()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ind = 0;
|
unsigned int colonlevel = 0;
|
||||||
for (const Token *endTok = semicolon; endTok; endTok = endTok->next()) {
|
for (const Token *endTok = semicolon->next(); endTok; endTok = endTok->next()) {
|
||||||
if (endTok->str() == ";") {
|
if (endTok->str() == "(" || endTok->str() == "[" || endTok->str() == "{") {
|
||||||
//we can remove the semicolon if after it there's at least another token
|
endTok = endTok->link();
|
||||||
if (endTok->next())
|
|
||||||
endTok = endTok->next();
|
|
||||||
Token::eraseTokens(semicolon->previous(), endTok);
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Token::Match(endTok, "[({[]")) {
|
else if (endTok->str() == "?")
|
||||||
++ind;
|
++colonlevel;
|
||||||
}
|
else if (Token::Match(endTok, ")|}|]|;|:")) {
|
||||||
|
if (endTok->str() == ":" && colonlevel)
|
||||||
else if (Token::Match(endTok, "[)}]]")) {
|
--colonlevel;
|
||||||
--ind;
|
else {
|
||||||
if (ind < 0) {
|
|
||||||
Token::eraseTokens(semicolon->previous(), endTok);
|
Token::eraseTokens(semicolon->previous(), endTok);
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2759,6 +2759,21 @@ private:
|
||||||
ASSERT_EQUALS("( 0 )", tok(code));
|
ASSERT_EQUALS("( 0 )", tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char code[] = "void f () { switch(n) { case 1?0:foo(): break; }}";
|
||||||
|
ASSERT_EQUALS("void f ( ) { switch ( n ) { case 0 : ; break ; } }", tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char code[] = "void f () { switch(n) { case 1?0?1:0:foo(): break; }}";
|
||||||
|
ASSERT_EQUALS("void f ( ) { switch ( n ) { case 0 : ; break ; } }", tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char code[] = "void f () { switch(n) { case 0?foo():1: break; }}";
|
||||||
|
ASSERT_EQUALS("void f ( ) { switch ( n ) { case 1 : ; break ; } }", tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char code[] = "( true ? a ( ) : b ( ) )";
|
const char code[] = "( true ? a ( ) : b ( ) )";
|
||||||
ASSERT_EQUALS("( a ( ) )", tok(code));
|
ASSERT_EQUALS("( a ( ) )", tok(code));
|
||||||
|
|
|
@ -738,6 +738,10 @@ private:
|
||||||
tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}");
|
tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
//allow GCC '({ %var%|%num%|%bool% ; })' statement expression extension
|
||||||
|
tokenizeAndStringify("void f() {switch (n) { case 0?({0;}):1: z(); break;}}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
//'b' can be or a macro or an undefined enum
|
//'b' can be or a macro or an undefined enum
|
||||||
tokenizeAndStringify("void f() {switch (n) { case b: z(); break;}}");
|
tokenizeAndStringify("void f() {switch (n) { case b: z(); break;}}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
Loading…
Reference in New Issue