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:
parent
ad879320e5
commit
8b9daadd25
|
@ -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':
|
||||||
|
|
21
lib/token.h
21
lib/token.h
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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%"));
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue