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:
Edoardo Prezioso 2012-10-13 02:32:43 +02:00
parent d4a3c1617a
commit 1951d1cdc5
3 changed files with 38 additions and 29 deletions

View File

@ -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;

View File

@ -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));

View File

@ -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());