Replaced static variable isCPP in Token (was not threadsafe):

- Encapsulate parameters passed through AST compiler functions in a struct
-> Reduces maintenance overhead when changing them
-> Contains parameter indicating if the file is C or C++
- Added eKeyword Token type (at the moment, only true for C++ keyword "delete", but should be set for other keywords as well)
This commit is contained in:
PKEuS 2014-06-04 22:33:08 +02:00 committed by PKEuS
parent ad879320e5
commit 8b9daadd25
6 changed files with 157 additions and 137 deletions

View File

@ -31,7 +31,6 @@
#include <stack> #include <stack>
#include <algorithm> #include <algorithm>
bool Token::_isCPP = true;
Token::Token(Token **t) : Token::Token(Token **t) :
tokensBack(t), tokensBack(t),
@ -66,7 +65,7 @@ void Token::update_property_info()
else if (_str[0] == '_' || std::isalpha((unsigned char)_str[0])) { // Name else if (_str[0] == '_' || std::isalpha((unsigned char)_str[0])) { // Name
if (_varId) if (_varId)
_type = eVariable; _type = eVariable;
else if (_type != eVariable && _type != eFunction && _type != eType) else if (_type != eVariable && _type != eFunction && _type != eType && _type != eKeyword)
_type = eName; _type = eName;
} else if (std::isdigit((unsigned char)_str[0]) || (_str.length() > 1 && _str[0] == '-' && std::isdigit((unsigned char)_str[1]))) } else if (std::isdigit((unsigned char)_str[0]) || (_str.length() > 1 && _str[0] == '-' && std::isdigit((unsigned char)_str[1])))
_type = eNumber; _type = eNumber;
@ -565,7 +564,7 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
// Type (%type%) // Type (%type%)
{ {
p += 5; p += 5;
multicompare(p, tok->isName() && tok->varId() == 0 && (tok->str() != "delete" || !Token::isCPP()), ismulticomp); multicompare(p, tok->isName() && tok->varId() == 0 && !tok->isKeyword(), ismulticomp);
} }
break; break;
case 'a': case 'a':

View File

@ -58,7 +58,7 @@ private:
public: public:
enum Type { enum Type {
eVariable, eType, eFunction, eName, // Names: Variable (varId), Type (typeId, later), Function (FuncId, later), Name (unknown identifier) eVariable, eType, eFunction, eKeyword, eName, // Names: Variable (varId), Type (typeId, later), Function (FuncId, later), Language keyword, Name (unknown identifier)
eNumber, eString, eChar, eBoolean, eLiteral, // Literals: Number, String, Character, User defined literal (C++11) eNumber, eString, eChar, eBoolean, eLiteral, // Literals: Number, String, Character, User defined literal (C++11)
eArithmeticalOp, eComparisonOp, eAssignmentOp, eLogicalOp, eBitOp, eIncDecOp, eExtendedOp, // Operators: Arithmetical, Comparison, Assignment, Logical, Bitwise, ++/--, Extended eArithmeticalOp, eComparisonOp, eAssignmentOp, eLogicalOp, eBitOp, eIncDecOp, eExtendedOp, // Operators: Arithmetical, Comparison, Assignment, Logical, Bitwise, ++/--, Extended
eBracket, // {, }, <, >: < and > only if link() is set. Otherwise they are comparison operators. eBracket, // {, }, <, >: < and > only if link() is set. Otherwise they are comparison operators.
@ -213,8 +213,17 @@ public:
void type(Type t) { void type(Type t) {
_type = t; _type = t;
} }
void isKeyword(bool kwd) {
if (kwd)
_type = eKeyword;
else if (_type == eKeyword)
_type = eName;
}
bool isKeyword() const {
return _type == eKeyword;
}
bool isName() const { bool isName() const {
return _type == eName || _type == eType || _type == eVariable || _type == eFunction || return _type == eName || _type == eType || _type == eVariable || _type == eFunction || _type == eKeyword ||
_type == eBoolean; // TODO: "true"/"false" aren't really a name... _type == eBoolean; // TODO: "true"/"false" aren't really a name...
} }
bool isUpperCaseName() const; bool isUpperCaseName() const;
@ -754,8 +763,6 @@ private:
// original name like size_t // original name like size_t
std::string _originalName; std::string _originalName;
static bool _isCPP;
public: public:
void astOperand1(Token *tok); void astOperand1(Token *tok);
void astOperand2(Token *tok); void astOperand2(Token *tok);
@ -805,12 +812,6 @@ public:
void printAst(bool verbose) const; void printAst(bool verbose) const;
void printValueFlow() const; void printValueFlow() const;
static void isCPP(bool isCPP) {
_isCPP = isCPP;
}
static bool isCPP() {
return _isCPP;
}
}; };
/// @} /// @}

View File

@ -1597,7 +1597,6 @@ bool Tokenizer::tokenize(std::istream &code,
return false; return false;
} }
Token::isCPP(isCPP());
if (simplifyTokenList1(FileName)) { if (simplifyTokenList1(FileName)) {
if (!noSymbolDB_AST) { if (!noSymbolDB_AST) {
createSymbolDatabase(); createSymbolDatabase();

View File

@ -62,11 +62,15 @@ const std::string& TokenList::getSourceFilePath() const
bool TokenList::isC() const bool TokenList::isC() const
{ {
if (!_settings)
return Path::isC(getSourceFilePath());
return _settings->enforcedLang == Settings::C || (_settings->enforcedLang == Settings::None && Path::isC(getSourceFilePath())); return _settings->enforcedLang == Settings::C || (_settings->enforcedLang == Settings::None && Path::isC(getSourceFilePath()));
} }
bool TokenList::isCPP() const bool TokenList::isCPP() const
{ {
if (!_settings)
return Path::isCPP(getSourceFilePath());
return _settings->enforcedLang == Settings::CPP || (_settings->enforcedLang == Settings::None && Path::isCPP(getSourceFilePath())); return _settings->enforcedLang == Settings::CPP || (_settings->enforcedLang == Settings::None && Path::isCPP(getSourceFilePath()));
} }
@ -146,6 +150,8 @@ void TokenList::addtoken(const std::string & str, const unsigned int lineno, con
_back->str(str2); _back->str(str2);
} }
if (isCPP() && str == "delete")
_back->isKeyword(true);
_back->linenr(lineno); _back->linenr(lineno);
_back->fileIndex(fileno); _back->fileIndex(fileno);
} }
@ -394,6 +400,13 @@ bool TokenList::createTokens(std::istream &code, const std::string& file0)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
struct AST_state {
std::stack<Token*> op;
unsigned int depth;
bool cpp;
AST_state(bool cpp_) : depth(0), cpp(cpp_) {}
};
static bool iscast(const Token *tok) static bool iscast(const Token *tok)
{ {
if (!Token::Match(tok, "( %var%")) if (!Token::Match(tok, "( %var%"))
@ -424,74 +437,79 @@ static bool iscast(const Token *tok)
return false; return false;
} }
static void compileUnaryOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &, unsigned int depth), std::stack<Token*> &op, unsigned int depth) static void compileUnaryOp(Token *&tok, AST_state& state, void(*f)(Token *&tok, AST_state& state))
{ {
Token *unaryop = tok; Token *unaryop = tok;
if (f) { if (f) {
tok = tok->next(); tok = tok->next();
f(tok, op, depth); state.depth++;
if (tok && state.depth <= AST_MAX_DEPTH)
f(tok, state);
state.depth--;
} }
if (!op.empty()) { if (!state.op.empty()) {
unaryop->astOperand1(op.top()); unaryop->astOperand1(state.op.top());
op.pop(); state.op.pop();
} }
op.push(unaryop); state.op.push(unaryop);
} }
static void compileBinOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &, unsigned int depth), std::stack<Token*> &op, unsigned int depth) static void compileBinOp(Token *&tok, AST_state& state, void(*f)(Token *&tok, AST_state& state))
{ {
Token *binop = tok; Token *binop = tok;
if (f) { if (f) {
tok = tok->next(); tok = tok->next();
if (tok) state.depth++;
f(tok, op, depth); if (tok && state.depth <= AST_MAX_DEPTH)
f(tok, state);
state.depth--;
} }
// TODO: Should we check if op is empty. // TODO: Should we check if op is empty.
// * Is it better to add assertion that it isn't? // * Is it better to add assertion that it isn't?
// * Write debug warning if it's empty? // * Write debug warning if it's empty?
if (!op.empty()) { if (!state.op.empty()) {
binop->astOperand2(op.top()); binop->astOperand2(state.op.top());
op.pop(); state.op.pop();
} }
if (!op.empty()) { if (!state.op.empty()) {
binop->astOperand1(op.top()); binop->astOperand1(state.op.top());
op.pop(); state.op.pop();
} }
op.push(binop); state.op.push(binop);
} }
static void compileExpression(Token *&tok, std::stack<Token*> &op, unsigned int depth); static void compileExpression(Token *&tok, AST_state& state);
static void compileTerm(Token *& tok, std::stack<Token*> &op, unsigned int depth) static void compileTerm(Token *&tok, AST_state& state)
{ {
if (!tok) if (!tok)
return; return;
if (Token::Match(tok, "L %str%|%char%")) if (Token::Match(tok, "L %str%|%char%"))
tok = tok->next(); tok = tok->next();
if (tok->isLiteral()) { if (tok->isLiteral()) {
op.push(tok); state.op.push(tok);
tok = tok->next(); tok = tok->next();
} else if (tok->str() == "return") { } else if (tok->str() == "return") {
compileUnaryOp(tok, compileExpression, op, depth); compileUnaryOp(tok, state, compileExpression);
op.pop(); state.op.pop();
} else if (tok->isName() && (!Token::isCPP() || !Token::Match(tok, "new|delete")) && tok->str() != "case") { } else if (tok->isName() && (!state.cpp || !Token::Match(tok, "new|delete")) && tok->str() != "case") {
while (tok->next() && tok->next()->isName()) while (tok->next() && tok->next()->isName())
tok = tok->next(); tok = tok->next();
op.push(tok); state.op.push(tok);
if (tok->next() && tok->linkAt(1) && Token::Match(tok, "%var% <")) if (tok->next() && tok->linkAt(1) && Token::Match(tok, "%var% <"))
tok = tok->linkAt(1); tok = tok->linkAt(1);
tok = tok->next(); tok = tok->next();
} else if (tok->str() == "{") { } else if (tok->str() == "{") {
op.push(tok); state.op.push(tok);
tok = tok->link()->next(); tok = tok->link()->next();
} }
} }
static void compileScope(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileScope(Token *&tok, AST_state& state)
{ {
compileTerm(tok,op, depth); compileTerm(tok, state);
while (tok) { while (tok) {
if (tok->str() == "::") { if (tok->str() == "::") {
Token *binop = tok; Token *binop = tok;
@ -499,41 +517,41 @@ static void compileScope(Token *&tok, std::stack<Token*> &op, unsigned int depth
if (tok && tok->str() == "~") // Jump over ~ of destructor definition if (tok && tok->str() == "~") // Jump over ~ of destructor definition
tok = tok->next(); tok = tok->next();
if (tok) if (tok)
compileTerm(tok, op, depth); compileTerm(tok, state);
if (binop->previous() && binop->previous()->isName()) if (binop->previous() && binop->previous()->isName())
compileBinOp(binop, nullptr, op, depth); compileBinOp(binop, state, nullptr);
else else
compileUnaryOp(binop, nullptr, op, depth); compileUnaryOp(binop, state, nullptr);
} else break; } else break;
} }
} }
static bool isPrefixUnary(const Token* tok) static bool isPrefixUnary(const Token* tok, bool cpp)
{ {
if (!tok->previous() if (!tok->previous()
|| ((Token::Match(tok->previous(), "(|[|{|%op%|;|}|?|:|,|.|return|::") || (Token::isCPP() && tok->strAt(-1) == "throw")) || ((Token::Match(tok->previous(), "(|[|{|%op%|;|}|?|:|,|.|return|::") || (cpp && tok->strAt(-1) == "throw"))
&& (tok->previous()->type() != Token::eIncDecOp || tok->type() == Token::eIncDecOp))) && (tok->previous()->type() != Token::eIncDecOp || tok->type() == Token::eIncDecOp)))
return true; return true;
return tok->strAt(-1) == ")" && iscast(tok->linkAt(-1)); return tok->strAt(-1) == ")" && iscast(tok->linkAt(-1));
} }
static void compilePrecedence2(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compilePrecedence2(Token *&tok, AST_state& state)
{ {
compileScope(tok, op, depth); compileScope(tok, state);
while (tok) { while (tok) {
if (tok->type() == Token::eIncDecOp && !isPrefixUnary(tok)) { if (tok->type() == Token::eIncDecOp && !isPrefixUnary(tok, state.cpp)) {
compileUnaryOp(tok, compileScope, op, depth); compileUnaryOp(tok, state, compileScope);
} else if (tok->str() == "." && tok->strAt(1) != "*") { } else if (tok->str() == "." && tok->strAt(1) != "*") {
if (tok->strAt(1) == ".") { if (tok->strAt(1) == ".") {
op.push(tok); state.op.push(tok);
tok = tok->tokAt(3); tok = tok->tokAt(3);
break; break;
} else } else
compileBinOp(tok, compileScope, op, depth); compileBinOp(tok, state, compileScope);
} else if (tok->str() == "[") { } else if (tok->str() == "[") {
if (isPrefixUnary(tok) && tok->link()->strAt(1) == "(") { // Lambda if (isPrefixUnary(tok, state.cpp) && tok->link()->strAt(1) == "(") { // Lambda
// What we do here: // What we do here:
// - Nest the round bracket under the square bracket. // - Nest the round bracket under the square bracket.
// - Nest what follows the lambda (if anything) with the lambda opening [ // - Nest what follows the lambda (if anything) with the lambda opening [
@ -542,47 +560,47 @@ static void compilePrecedence2(Token *&tok, std::stack<Token*> &op, unsigned int
Token* roundBracket = squareBracket->link()->next(); Token* roundBracket = squareBracket->link()->next();
Token* curlyBracket = Token::findsimplematch(roundBracket->link()->next(), "{"); Token* curlyBracket = Token::findsimplematch(roundBracket->link()->next(), "{");
tok = curlyBracket->next(); tok = curlyBracket->next();
compileExpression(tok, op, depth); compileExpression(tok, state);
op.push(roundBracket); state.op.push(roundBracket);
compileUnaryOp(squareBracket, 0, op, depth); compileUnaryOp(squareBracket, state, nullptr);
tok = curlyBracket->link()->next(); tok = curlyBracket->link()->next();
} else { } else {
Token* tok2 = tok; Token* tok2 = tok;
if (tok->strAt(1) != "]") if (tok->strAt(1) != "]")
compileBinOp(tok, compileExpression, op, depth); compileBinOp(tok, state, compileExpression);
else else
compileUnaryOp(tok, compileExpression, op, depth); compileUnaryOp(tok, state, compileExpression);
tok = tok2->link()->next(); tok = tok2->link()->next();
} }
} else if (tok->str() == "(" && (!iscast(tok) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) { } else if (tok->str() == "(" && (!iscast(tok) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) {
Token* tok2 = tok; Token* tok2 = tok;
tok = tok->next(); tok = tok->next();
bool opPrevTopSquare = !op.empty() && op.top() && op.top()->str() == "["; bool opPrevTopSquare = !state.op.empty() && state.op.top() && state.op.top()->str() == "[";
std::size_t oldOpSize = op.size(); std::size_t oldOpSize = state.op.size();
compileExpression(tok, op, depth); compileExpression(tok, state);
bool operandInside = oldOpSize < op.size(); bool operandInside = oldOpSize < state.op.size();
tok = tok2; tok = tok2;
if ((tok->previous() && tok->previous()->isName() && (tok->strAt(-1) != "return" && (!Token::isCPP() || !Token::Match(tok->previous(), "throw|delete")))) if ((tok->previous() && tok->previous()->isName() && (tok->strAt(-1) != "return" && (!state.cpp || !Token::Match(tok->previous(), "throw|delete"))))
|| (tok->strAt(-1) == "]" && (!Token::isCPP() || !Token::Match(tok->linkAt(-1)->previous(), "new|delete"))) || (tok->strAt(-1) == "]" && (!state.cpp || !Token::Match(tok->linkAt(-1)->previous(), "new|delete")))
|| (tok->strAt(-1) == ">" && tok->linkAt(-1)) || (tok->strAt(-1) == ">" && tok->linkAt(-1))
|| (tok->strAt(-1) == ")" && !iscast(tok->linkAt(-1))) // Don't treat brackets to clarify precedence as function calls || (tok->strAt(-1) == ")" && !iscast(tok->linkAt(-1))) // Don't treat brackets to clarify precedence as function calls
|| (tok->strAt(-1) == "}" && opPrevTopSquare)) { || (tok->strAt(-1) == "}" && opPrevTopSquare)) {
if (operandInside) if (operandInside)
compileBinOp(tok, 0, op, depth); compileBinOp(tok, state, nullptr);
else else
compileUnaryOp(tok, 0, op, depth); compileUnaryOp(tok, state, nullptr);
} }
tok = tok->link()->next(); tok = tok->link()->next();
} else break; } else break;
} }
} }
static void compilePrecedence3(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compilePrecedence3(Token *&tok, AST_state& state)
{ {
compilePrecedence2(tok, op, depth); compilePrecedence2(tok, state);
while (tok) { while (tok) {
if ((Token::Match(tok, "[+-!~*&]") || tok->type() == Token::eIncDecOp) && if ((Token::Match(tok, "[+-!~*&]") || tok->type() == Token::eIncDecOp) &&
isPrefixUnary(tok)) { isPrefixUnary(tok, state.cpp)) {
if (Token::Match(tok, "* [*,)]")) { if (Token::Match(tok, "* [*,)]")) {
Token* tok2 = tok; Token* tok2 = tok;
while (tok2->next() && tok2->str() == "*") while (tok2->next() && tok2->str() == "*")
@ -592,48 +610,48 @@ static void compilePrecedence3(Token *&tok, std::stack<Token*> &op, unsigned int
continue; continue;
} }
} }
compileUnaryOp(tok, compilePrecedence3, op, depth); compileUnaryOp(tok, state, compilePrecedence3);
} else if (tok->str() == "(" && iscast(tok)) { } else if (tok->str() == "(" && iscast(tok)) {
Token* tok2 = tok; Token* tok2 = tok;
tok = tok->link()->next(); tok = tok->link()->next();
compilePrecedence3(tok, op, depth); compilePrecedence3(tok, state);
compileUnaryOp(tok2, 0, op, depth); compileUnaryOp(tok2, state, nullptr);
} else if (Token::isCPP() && tok->str() == "new") { } else if (state.cpp && tok->str() == "new") {
Token* tok2 = tok; Token* tok2 = tok;
tok = tok->next(); tok = tok->next();
op.push(tok); state.op.push(tok);
while (Token::Match(tok, "%var%|*|&|<|[")) { while (Token::Match(tok, "%var%|*|&|<|[")) {
if (tok->link()) if (tok->link())
tok = tok->link(); tok = tok->link();
tok = tok->next(); tok = tok->next();
} }
compileUnaryOp(tok2, 0, op, depth); compileUnaryOp(tok2, state, nullptr);
} else if (Token::isCPP() && tok->str() == "delete") { } else if (state.cpp && tok->str() == "delete") {
Token* tok2 = tok; Token* tok2 = tok;
tok = tok->next(); tok = tok->next();
if (tok->str() == "[") if (tok->str() == "[")
tok = tok->link()->next(); tok = tok->link()->next();
compilePrecedence3(tok, op, depth); compilePrecedence3(tok, state);
compileUnaryOp(tok2, 0, op, depth); compileUnaryOp(tok2, state, nullptr);
} }
// TODO: Handle sizeof // TODO: Handle sizeof
else break; else break;
} }
} }
static void compilePointerToElem(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compilePointerToElem(Token *&tok, AST_state& state)
{ {
compilePrecedence3(tok, op, depth); compilePrecedence3(tok, state);
while (tok) { while (tok) {
if (Token::simpleMatch(tok, ". *")) { if (Token::simpleMatch(tok, ". *")) {
compileBinOp(tok, compilePrecedence3, op, depth); compileBinOp(tok, state, compilePrecedence3);
} else break; } else break;
} }
} }
static void compileMulDiv(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileMulDiv(Token *&tok, AST_state& state)
{ {
compilePointerToElem(tok, op, depth); compilePointerToElem(tok, state);
while (tok) { while (tok) {
if (Token::Match(tok, "[/%]") || (tok->str() == "*" && !tok->astOperand1())) { if (Token::Match(tok, "[/%]") || (tok->str() == "*" && !tok->astOperand1())) {
if (Token::Match(tok, "* [*,)]")) { if (Token::Match(tok, "* [*,)]")) {
@ -645,142 +663,142 @@ static void compileMulDiv(Token *&tok, std::stack<Token*> &op, unsigned int dept
break; break;
} }
} }
compileBinOp(tok, compilePointerToElem, op, depth); compileBinOp(tok, state, compilePointerToElem);
} else break; } else break;
} }
} }
static void compileAddSub(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileAddSub(Token *&tok, AST_state& state)
{ {
compileMulDiv(tok, op, depth); compileMulDiv(tok, state);
while (tok) { while (tok) {
if (Token::Match(tok, "+|-") && !tok->astOperand1()) { if (Token::Match(tok, "+|-") && !tok->astOperand1()) {
compileBinOp(tok, compileMulDiv, op, depth); compileBinOp(tok, state, compileMulDiv);
} else break; } else break;
} }
} }
static void compileShift(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileShift(Token *&tok, AST_state& state)
{ {
compileAddSub(tok, op, depth); compileAddSub(tok, state);
while (tok) { while (tok) {
if (Token::Match(tok, "<<|>>")) { if (Token::Match(tok, "<<|>>")) {
compileBinOp(tok, compileAddSub, op, depth); compileBinOp(tok, state, compileAddSub);
} else break; } else break;
} }
} }
static void compileRelComp(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileRelComp(Token *&tok, AST_state& state)
{ {
compileShift(tok, op, depth); compileShift(tok, state);
while (tok) { while (tok) {
if (Token::Match(tok, "<|<=|>=|>") && !tok->link()) { if (Token::Match(tok, "<|<=|>=|>") && !tok->link()) {
compileBinOp(tok, compileShift, op, depth); compileBinOp(tok, state, compileShift);
} else break; } else break;
} }
} }
static void compileEqComp(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileEqComp(Token *&tok, AST_state& state)
{ {
compileRelComp(tok, op, depth); compileRelComp(tok, state);
while (tok) { while (tok) {
if (Token::Match(tok, "==|!=")) { if (Token::Match(tok, "==|!=")) {
compileBinOp(tok, compileRelComp, op, depth); compileBinOp(tok, state, compileRelComp);
} else break; } else break;
} }
} }
static void compileAnd(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileAnd(Token *&tok, AST_state& state)
{ {
compileEqComp(tok, op, depth); compileEqComp(tok, state);
while (tok) { while (tok) {
if (tok->str() == "&" && !tok->astOperand1()) { if (tok->str() == "&" && !tok->astOperand1()) {
Token* tok2 = tok->next(); Token* tok2 = tok->next();
if (tok2->str() == "&") if (tok2->str() == "&")
tok2 = tok2->next(); tok2 = tok2->next();
if (Token::isCPP() && (tok2->str() == "," || tok2->str() == ")")) { if (state.cpp && (tok2->str() == "," || tok2->str() == ")")) {
tok = tok2; tok = tok2;
break; // rValue reference break; // rValue reference
} }
compileBinOp(tok, compileEqComp, op, depth); compileBinOp(tok, state, compileEqComp);
} else break; } else break;
} }
} }
static void compileXor(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileXor(Token *&tok, AST_state& state)
{ {
compileAnd(tok, op, depth); compileAnd(tok, state);
while (tok) { while (tok) {
if (tok->str() == "^") { if (tok->str() == "^") {
compileBinOp(tok, compileAnd, op, depth); compileBinOp(tok, state, compileAnd);
} else break; } else break;
} }
} }
static void compileOr(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileOr(Token *&tok, AST_state& state)
{ {
compileXor(tok, op, depth); compileXor(tok, state);
while (tok) { while (tok) {
if (tok->str() == "|") { if (tok->str() == "|") {
compileBinOp(tok, compileXor, op, depth); compileBinOp(tok, state, compileXor);
} else break; } else break;
} }
} }
static void compileLogicAnd(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileLogicAnd(Token *&tok, AST_state& state)
{ {
compileOr(tok, op, depth); compileOr(tok, state);
while (tok) { while (tok) {
if (tok->str() == "&&") { if (tok->str() == "&&") {
compileBinOp(tok, compileOr, op, depth); compileBinOp(tok, state, compileOr);
} else break; } else break;
} }
} }
static void compileLogicOr(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileLogicOr(Token *&tok, AST_state& state)
{ {
compileLogicAnd(tok, op, depth); compileLogicAnd(tok, state);
while (tok) { while (tok) {
if (tok->str() == "||") { if (tok->str() == "||") {
compileBinOp(tok, compileLogicAnd, op, depth); compileBinOp(tok, state, compileLogicAnd);
} else break; } else break;
} }
} }
static void compileAssignTernary(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileAssignTernary(Token *&tok, AST_state& state)
{ {
compileLogicOr(tok, op, depth); compileLogicOr(tok, state);
while (tok) { while (tok) {
// 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) == ":") { if (tok->str() == "?" && tok->strAt(1) == ":") {
op.push(0); state.op.push(0);
} }
compileBinOp(tok, compileAssignTernary, op, depth); compileBinOp(tok, state, compileAssignTernary);
} else break; } else break;
} }
} }
static void compileComma(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileComma(Token *&tok, AST_state& state)
{ {
compileAssignTernary(tok, op, depth); compileAssignTernary(tok, state);
while (tok) { while (tok) {
if (tok->str() == ",") { if (tok->str() == ",") {
compileBinOp(tok, compileAssignTernary, op, depth); compileBinOp(tok, state, compileAssignTernary);
} else break; } else break;
} }
} }
static void compileExpression(Token *&tok, std::stack<Token*> &op, unsigned int depth) static void compileExpression(Token *&tok, AST_state& state)
{ {
if (depth > AST_MAX_DEPTH) if (state.depth > AST_MAX_DEPTH)
return; // ticket #5592 return; // ticket #5592
if (tok) if (tok)
compileComma(tok,op, depth+1U); compileComma(tok, state);
} }
static Token * createAstAtToken(Token *tok) static Token * createAstAtToken(Token *tok, bool cpp)
{ {
if (Token::simpleMatch(tok,"for (")) { if (Token::simpleMatch(tok,"for (")) {
Token *tok2 = tok->tokAt(2); Token *tok2 = tok->tokAt(2);
@ -793,8 +811,8 @@ static Token * createAstAtToken(Token *tok)
break; break;
} else if (Token::Match(tok2, "%var% %op%|(|[|.|:|::") || Token::Match(tok2->previous(), "[(;{}] %cop%|(")) { } else if (Token::Match(tok2, "%var% %op%|(|[|.|:|::") || Token::Match(tok2->previous(), "[(;{}] %cop%|(")) {
init1 = tok2; init1 = tok2;
std::stack<Token *> operands; AST_state state1(cpp);
compileExpression(tok2, operands, 0U); compileExpression(tok2, state1);
if (tok2->str() == ";" || tok2->str() == ")") if (tok2->str() == ";" || tok2->str() == ")")
break; break;
init1 = 0; init1 = 0;
@ -813,13 +831,13 @@ static Token * createAstAtToken(Token *tok)
Token * const semicolon1 = tok2; Token * const semicolon1 = tok2;
tok2 = tok2->next(); tok2 = tok2->next();
std::stack<Token *> operands2; AST_state state2(cpp);
compileExpression(tok2, operands2, 0U); compileExpression(tok2, state2);
Token * const semicolon2 = tok2; Token * const semicolon2 = tok2;
tok2 = tok2->next(); tok2 = tok2->next();
std::stack<Token *> operands3; AST_state state3(cpp);
compileExpression(tok2, operands3, 0U); compileExpression(tok2, state3);
if (init != semicolon1) if (init != semicolon1)
semicolon1->astOperand1(const_cast<Token*>(init->astTop())); semicolon1->astOperand1(const_cast<Token*>(init->astTop()));
@ -848,9 +866,9 @@ static Token * createAstAtToken(Token *tok)
return tok->linkAt(1); return tok->linkAt(1);
if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|::") || Token::Match(tok->previous(), "[;{}] %cop%|( !!{")) { if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|::") || Token::Match(tok->previous(), "[;{}] %cop%|( !!{")) {
std::stack<Token *> operands;
Token * const tok1 = tok; Token * const tok1 = tok;
compileExpression(tok, operands, 0U); AST_state state(cpp);
compileExpression(tok, state);
Token * const endToken = tok; Token * const endToken = tok;
if (endToken == tok1) if (endToken == tok1)
return tok1; return tok1;
@ -863,7 +881,7 @@ static Token * createAstAtToken(Token *tok)
break; break;
const Token * const endToken2 = tok->linkAt(1); const Token * const endToken2 = tok->linkAt(1);
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : NULL) for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : NULL)
tok = createAstAtToken(tok); tok = createAstAtToken(tok, cpp);
} }
return endToken ? endToken->previous() : NULL; return endToken ? endToken->previous() : NULL;
@ -875,7 +893,7 @@ static Token * createAstAtToken(Token *tok)
void TokenList::createAst() void TokenList::createAst()
{ {
for (Token *tok = _front; tok; tok = tok ? tok->next() : NULL) { for (Token *tok = _front; tok; tok = tok ? tok->next() : NULL) {
tok = createAstAtToken(tok); tok = createAstAtToken(tok, isCPP());
} }
} }

View File

@ -345,8 +345,11 @@ private:
ASSERT_EQUALS(true, Token::Match(isVar.tokens(), "%type% %var%")); ASSERT_EQUALS(true, Token::Match(isVar.tokens(), "%type% %var%"));
ASSERT_EQUALS(false, Token::Match(isVar.tokens(), "%type% %type%")); ASSERT_EQUALS(false, Token::Match(isVar.tokens(), "%type% %type%"));
givenACodeSampleToTokenize noType("delete", true); givenACodeSampleToTokenize noType1_cpp("delete", true, true);
ASSERT_EQUALS(false, Token::Match(noType.tokens(), "%type%")); ASSERT_EQUALS(false, Token::Match(noType1_cpp.tokens(), "%type%"));
givenACodeSampleToTokenize noType1_c("delete", true, false);
ASSERT_EQUALS(true, Token::Match(noType1_c.tokens(), "%type%"));
givenACodeSampleToTokenize noType2("void delete", true); givenACodeSampleToTokenize noType2("void delete", true);
ASSERT_EQUALS(false, Token::Match(noType2.tokens(), "!!foo %type%")); ASSERT_EQUALS(false, Token::Match(noType2.tokens(), "!!foo %type%"));

View File

@ -30,13 +30,13 @@ private:
Tokenizer _tokenizer; Tokenizer _tokenizer;
public: public:
givenACodeSampleToTokenize(const char sample[], bool createOnly = false) givenACodeSampleToTokenize(const char sample[], bool createOnly = false, bool cpp = true)
: _tokenizer(&_settings, 0) { : _tokenizer(&_settings, 0) {
std::istringstream iss(sample); std::istringstream iss(sample);
if (createOnly) if (createOnly)
_tokenizer.list.createTokens(iss); _tokenizer.list.createTokens(iss, cpp ? "test.cpp" : "test.c");
else else
_tokenizer.tokenize(iss, "test.cpp"); _tokenizer.tokenize(iss, cpp ? "test.cpp" : "test.c");
} }
const Token* tokens() const { const Token* tokens() const {