From 1951d1cdc596cf5cea8148324ad4cc146b332a4d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sat, 13 Oct 2012 02:32:43 +0200 Subject: [PATCH] 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. --- lib/tokenize.cpp | 48 +++++++++++++++---------------------- test/testsimplifytokens.cpp | 15 ++++++++++++ test/testtokenize.cpp | 4 ++++ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 046651cff..0c9ea7c0e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2370,6 +2370,11 @@ static Token *skipTernaryOp(Token *tok) 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(), "[{};]")) break; } @@ -4426,7 +4431,7 @@ bool Tokenizer::simplifyQuestionMark() if (!tok->tokAt(-2)) continue; - if (!Token::Match(tok->tokAt(-2), "[=,(]")) + if (!Token::Match(tok->tokAt(-2), "=|,|(|case")) continue; if (!tok->previous()->isBoolean() && @@ -4434,19 +4439,10 @@ bool Tokenizer::simplifyQuestionMark() continue; // Find the ":" token.. - Token *semicolon = 0; - for (Token *tok2 = tok; tok2; tok2 = tok2->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()) + Token *semicolon = skipTernaryOp(tok); + if (!semicolon || semicolon->previous()->str() != ":" || !semicolon->next()) continue; + semicolon = semicolon->previous(); if (tok->previous()->str() == "false" || tok->previous()->str() == "0") { @@ -4480,24 +4476,18 @@ bool Tokenizer::simplifyQuestionMark() continue; } - int ind = 0; - for (const Token *endTok = semicolon; endTok; endTok = endTok->next()) { - if (endTok->str() == ";") { - //we can remove the semicolon if after it there's at least another token - if (endTok->next()) - endTok = endTok->next(); - Token::eraseTokens(semicolon->previous(), endTok); - ret = true; - break; + unsigned int colonlevel = 0; + for (const Token *endTok = semicolon->next(); endTok; endTok = endTok->next()) { + if (endTok->str() == "(" || endTok->str() == "[" || endTok->str() == "{") { + endTok = endTok->link(); } - else if (Token::Match(endTok, "[({[]")) { - ++ind; - } - - else if (Token::Match(endTok, "[)}]]")) { - --ind; - if (ind < 0) { + else if (endTok->str() == "?") + ++colonlevel; + else if (Token::Match(endTok, ")|}|]|;|:")) { + if (endTok->str() == ":" && colonlevel) + --colonlevel; + else { Token::eraseTokens(semicolon->previous(), endTok); ret = true; break; diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index b564b0080..45a13a706 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -2759,6 +2759,21 @@ private: 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 ( ) )"; ASSERT_EQUALS("( a ( ) )", tok(code)); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 6c7a5b344..299d093fa 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -738,6 +738,10 @@ private: tokenizeAndStringify("void f() {switch (n) { case 0?(1?3:4):2 : z(); break;}}"); 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 tokenizeAndStringify("void f() {switch (n) { case b: z(); break;}}"); ASSERT_EQUALS("", errout.str());