CheckClass; Added files (Check for mistakes related to classes)

This commit is contained in:
Daniel Marjamäki 2007-05-24 13:07:30 +00:00
parent 399a3e2598
commit f20c34a751
9 changed files with 1115 additions and 1611 deletions

473
CheckClass.cpp Normal file
View File

@ -0,0 +1,473 @@
//---------------------------------------------------------------------------
#include "CheckClass.h"
#include "Tokenize.h"
#include "CommonCheck.h"
#include <locale>
#include <list>
#include <string>
#include <sstream>
//---------------------------------------------------------------------------
extern bool IsName(const char str[]);
//---------------------------------------------------------------------------
struct VAR
{
bool is_class;
const char *name;
bool init;
bool is_pointer;
struct VAR *next;
};
//---------------------------------------------------------------------------
static struct VAR *ClassChecking_GetVarList(const char classname[])
{
// Locate class..
const char *pattern[] = {"class","","{",0};
pattern[1] = classname;
TOKEN *tok1 = findtoken(tokens, pattern);
// All classes..
struct _class
{
const char *name;
struct _class *next;
};
struct _class *classes = NULL;
const char *pattern_anyclass[] = {"class","",NULL};
for (TOKEN *t = findtoken(tokens,pattern_anyclass); t; t = findtoken(t->next,pattern_anyclass))
{
_class *newclass = new _class;
newclass->name = t->next->str;
newclass->next = classes;
classes = newclass;
}
// Get variable list..
bool is_class = false;
bool is_pointer = false;
struct VAR *varlist = NULL;
unsigned int indentlevel = 0;
for (TOKEN *tok = tok1; tok; tok = tok->next)
{
if (!tok->next)
break;
if (tok->str[0] == '{')
indentlevel++;
if (tok->str[0] == '}')
{
if (indentlevel <= 1)
break;
indentlevel--;
}
if (strchr(";{}", tok->str[0]))
is_class = is_pointer = false;
else if (IsName(tok->str))
{
for (_class *c = classes; c; c = c->next)
is_class |= (strcmp(c->name, tok->str) == 0);
}
if (tok->str[0] == '*')
is_pointer = true;
// Member variable?
if ((indentlevel == 1) &&
(tok->next->str[0] == ';') &&
(IsName(tok->str)) &&
(strcmp(tok->str,"const") != 0 ))
{
struct VAR *var = new VAR;
memset(var, 0, sizeof(struct VAR));
var->name = tok->str;
var->next = varlist;
var->is_class = is_class;
var->is_pointer = is_pointer;
varlist = var;
}
}
while (classes)
{
_class *next = classes->next;
delete classes;
classes = next;
}
return varlist;
}
//---------------------------------------------------------------------------
static TOKEN * ClassChecking_VarList_RemoveAssigned(TOKEN *_tokens, struct VAR *varlist, const char classname[], const char funcname[])
{
// Locate class member function
const char *pattern[] = {"","::","","(",NULL};
pattern[0] = classname;
pattern[2] = funcname;
// Locate member function implementation..
TOKEN *ftok = findtoken(_tokens, pattern);
if (!ftok)
return NULL;
bool BeginLine = false;
bool Assign = false;
unsigned int indentlevel = 0;
for (; ftok; ftok = ftok->next)
{
if (!ftok->next)
break;
// Class constructor.. initializing variables like this
// clKalle::clKalle() : var(value) { }
if (indentlevel==0 && strcmp(classname,funcname)==0)
{
if (Assign &&
IsName(ftok->str) &&
ftok->next->str[0]=='(')
{
for (struct VAR *var = varlist; var; var = var->next)
{
if (strcmp(var->name,ftok->str))
continue;
var->init = true;
break;
}
}
Assign |= (ftok->str[0] == ':');
}
if (ftok->str[0] == '{')
{
indentlevel++;
Assign = false;
}
if (ftok->str[0] == '}')
{
if (indentlevel <= 1)
break;
indentlevel--;
}
if (BeginLine && indentlevel>=1 && IsName(ftok->str))
{
// Clearing all variables..
if (match(ftok,"memset ( this ,"))
{
for (struct VAR *var = varlist; var; var = var->next)
var->init = true;
}
// Calling member function?
if (ftok->next->str[0] == '(')
ClassChecking_VarList_RemoveAssigned(tokens, varlist, classname, ftok->str);
// Assignment of member variable?
if (strcmp(ftok->next->str, "=") == 0)
{
for (struct VAR *var = varlist; var; var = var->next)
{
if (strcmp(var->name,ftok->str))
continue;
var->init = true;
break;
}
}
// Calling member function..
if (strcmp(ftok->next->str,".")==0 || strcmp(ftok->next->str,"->")==0)
{
// The functions 'clear' and 'Clear' are supposed to initialize variable.
if (stricmp(ftok->next->next->str,"clear") == 0)
{
for (struct VAR *var = varlist; var; var = var->next)
{
if (strcmp(var->name,ftok->str))
continue;
var->init = true;
break;
}
}
}
}
BeginLine = (strchr("{};", ftok->str[0]));
}
return ftok;
}
//---------------------------------------------------------------------------
// ClassCheck: Check that all class constructors are ok.
//---------------------------------------------------------------------------
void CheckConstructors()
{
// Locate class
const char *pattern_classname[] = {"class","","{",NULL};
TOKEN *tok1 = findtoken(tokens, pattern_classname);
while (tok1)
{
const char *classname = tok1->next->str;
// Are there a class constructor?
const char *pattern_constructor[] = {"clKalle","::","clKalle","(",NULL};
pattern_constructor[0] = classname;
pattern_constructor[2] = classname;
if (!findtoken(tokens,pattern_constructor))
{
// There's no class implementation, it must be somewhere else.
tok1 = findtoken( tok1->next, pattern_classname );
continue;
}
// Check that all member variables are initialized..
struct VAR *varlist = ClassChecking_GetVarList(classname);
ClassChecking_VarList_RemoveAssigned(tokens, varlist, classname, classname);
// Check if any variables are uninitialized
for (struct VAR *var = varlist; var; var = var->next)
{
if (!var->init && (var->is_pointer || !var->is_class))
{
std::ostringstream ostr;
ostr << "Uninitialized member variable '" << classname << "::" << var->name << "'";
ReportErr(ostr.str());
}
}
// Delete the varlist..
while (varlist)
{
struct VAR *nextvar = varlist->next;
delete varlist;
varlist = nextvar;
}
tok1 = findtoken( tok1->next, pattern_classname );
}
}
//---------------------------------------------------------------------------
// ClassCheck: Unused private functions
//---------------------------------------------------------------------------
void CheckUnusedPrivateFunctions()
{
// Locate some class
const char *pattern_class[] = {"class","","{",NULL};
for (TOKEN *tok1 = findtoken(tokens, pattern_class); tok1; tok1 = findtoken(tok1->next, pattern_class))
{
const char *classname = tok1->next->str;
// The class implementation must be available..
const char *pattern_classconstructor[] = {"","::","",NULL};
pattern_classconstructor[0] = classname;
pattern_classconstructor[2] = classname;
if (!findtoken(tokens,pattern_classconstructor))
continue;
// Get private functions..
std::list<std::string> FuncList;
FuncList.clear();
bool priv = false;
unsigned int indent_level = 0;
for (TOKEN *tok = tok1; tok; tok = tok->next)
{
if (match(tok,"friend class"))
{
// Todo: Handle friend classes
FuncList.clear();
break;
}
if (tok->str[0] == '{')
indent_level++;
if (tok->str[0] == '}')
{
if (indent_level <= 1)
break;
indent_level--;
}
if (strcmp(tok->str,"};") == 0)
break;
if (strcmp(tok->str,"private:") == 0)
priv = true;
else if (strcmp(tok->str,"public:") == 0)
priv = false;
else if (strcmp(tok->str,"protected:") == 0)
priv = false;
else if (priv && indent_level == 1)
{
if (std::isalpha(tok->str[0]) &&
tok->next->str[0]=='(' &&
strcmp(tok->str,classname) != 0)
{
FuncList.push_back(tok->str);
}
}
}
// Check that all private functions are used..
const char *pattern_function[] = {"","::",NULL};
pattern_function[0] = classname;
bool HasFuncImpl = false;
for (TOKEN *ftok = findtoken(tokens, pattern_function); ftok; ftok = findtoken(ftok->next,pattern_function))
{
int numpar = 0;
while (ftok && ftok->str[0]!=';' && ftok->str[0]!='{')
{
if (ftok->str[0] == '(')
numpar++;
else if (ftok->str[0] == ')')
numpar--;
ftok = ftok->next;
}
if (!ftok)
break;
if (ftok->str[0] == ';')
continue;
if (numpar != 0)
continue;
HasFuncImpl = true;
indent_level = 0;
while (ftok)
{
if (ftok->str[0] == '{')
indent_level++;
if (ftok->str[0] == '}')
{
if (indent_level<=1)
break;
indent_level--;
}
if (ftok->next && ftok->next->str[0] == '(')
FuncList.remove(ftok->str);
ftok = ftok->next;
}
}
while (HasFuncImpl && !FuncList.empty())
{
bool fp = false;
// Final check; check if the function pointer is used somewhere..
const char *_pattern[] = {"=","",NULL};
_pattern[1] = FuncList.front().c_str();
fp |= (findtoken(tokens, _pattern) != NULL);
_pattern[0] = "(";
fp |= (findtoken(tokens, _pattern) != NULL);
_pattern[0] = ")";
fp |= (findtoken(tokens, _pattern) != NULL);
_pattern[0] = ",";
fp |= (findtoken(tokens, _pattern) != NULL);
if (!fp)
{
std::ostringstream ostr;
ostr << "Class '" << classname << "', unused private function: '" << FuncList.front() << "'";
ReportErr(ostr.str());
}
FuncList.pop_front();
}
}
}
//---------------------------------------------------------------------------
// ClassCheck: Check that memset is not used on classes
//---------------------------------------------------------------------------
void CheckMemset()
{
// Locate all 'memset' tokens..
for (TOKEN *tok = tokens; tok; tok = tok->next)
{
if (strcmp(tok->str,"memset")!=0)
continue;
const char *type = NULL;
if (match(tok, "memset ( var , num , sizeof ( type ) )"))
type = getstr(tok, 8);
else if (match(tok, "memset ( & var , num , sizeof ( type ) )"))
type = getstr(tok, 9);
else if (match(tok, "memset ( var , num , sizeof ( struct type ) )"))
type = getstr(tok, 9);
else if (match(tok, "memset ( & var , num , sizeof ( struct type ) )"))
type = getstr(tok, 10);
// No type defined => The tokens didn't match
if (!(type && type[0]))
continue;
// It will be assumed that memset can be used upon 'this'.
// Todo: Check this too
if (strcmp(getstr(tok,2),"this") == 0)
continue;
// Warn if type is a class..
const char *pattern1[] = {"class","",NULL};
pattern1[1] = type;
if (findtoken(tokens,pattern1))
{
std::ostringstream ostr;
ostr << FileLine(tok) << ": Using 'memset' on class.";
ReportErr(ostr.str());
}
// Warn if type is a struct that contains any std::*
const char *pattern2[] = {"struct","","{",NULL};
pattern2[1] = type;
for (TOKEN *tstruct = findtoken(tokens, pattern2); tstruct; tstruct = tstruct->next)
{
if (tstruct->str[0] == '}')
break;
if (match(tstruct, "std :: type var ;"))
{
std::ostringstream ostr;
ostr << FileLine(tok) << ": Using 'memset' on struct that contains a 'std::" << getstr(tstruct,2) << "'";
ReportErr(ostr.str());
break;
}
}
}
}
//---------------------------------------------------------------------------
// ClassCheck: "void operator=("
//---------------------------------------------------------------------------
void CheckOperatorEq1()
{
const char *pattern[] = {"void", "operator", "=", "(", NULL};
if (TOKEN *tok = findtoken(tokens,pattern))
{
std::ostringstream ostr;
ostr << FileLine(tok) << ": 'operator=' should return something";
ReportErr(ostr.str());
}
}

17
CheckClass.h Normal file
View File

@ -0,0 +1,17 @@
//---------------------------------------------------------------------------
#ifndef CheckClassH
#define CheckClassH
//---------------------------------------------------------------------------
void CheckConstructors();
void CheckUnusedPrivateFunctions();
void CheckMemset();
void CheckOperatorEq1(); // Warning upon "void operator=(.."
//---------------------------------------------------------------------------
#endif

15
CommonCheck.h Normal file
View File

@ -0,0 +1,15 @@
//---------------------------------------------------------------------------
#ifndef CommonCheckH
#define CommonCheckH
//---------------------------------------------------------------------------
#include <string>
struct TOKEN;
std::string FileLine(TOKEN *tok);
void ReportErr(const std::string errmsg);
//---------------------------------------------------------------------------
#endif

453
Statements.cpp Normal file
View File

@ -0,0 +1,453 @@
#include "Statements.h"
#include "tokenize.h"
#include <iostream>
#include <sstream>
std::vector<std::string> VariableNames;
std::list<STATEMENT> Statements;
extern bool Debug;
extern bool IsName(const char str[]);
//---------------------------------------------------------------------------
// Create statement list
//---------------------------------------------------------------------------
void AppendStatement(STATEMENT::etype Type, TOKEN *tok, std::string Var="")
{
STATEMENT NewStatement;
NewStatement.Type = Type;
NewStatement.Token = tok;
if (Var.empty())
{
NewStatement.VarIndex = 0;
}
else
{
bool Found = false;
for (unsigned int i = 0; i < VariableNames.size(); i++)
{
if (VariableNames[i] == Var)
{
Found = true;
NewStatement.VarIndex = i;
break;
}
}
if ( ! Found )
{
NewStatement.VarIndex = VariableNames.size();
VariableNames.push_back(Var);
}
}
Statements.push_back(NewStatement);
}
TOKEN *GotoNextStatement(TOKEN *tok)
{
if (tok && (tok->str[0]=='{' || tok->str[0]=='}'))
return tok->next;
if (tok)
tok = tok->next;
int parlevel = 0;
for (; tok; tok = tok->next)
{
if (tok->str[0] == '(')
parlevel++;
else if (tok->str[0] == ')')
parlevel--;
if (strchr("{}", tok->str[0]))
break;
if (parlevel==0 && tok->str[0] == ';')
{
while (tok && tok->str[0] == ';')
tok = tok->next;
break;
}
}
return tok;
}
void GetVariableName(TOKEN * &Token, std::string &varname)
{
varname = "";
if (Token == NULL)
return;
if (!IsName(Token->str))
return;
// Get variable name..
std::ostringstream ostr;
bool array = false;
bool name = false;
for (TOKEN *tok = Token; tok; tok = tok->next)
{
const char *str = tok->str;
if ((array) || (str[0]=='['))
{
ostr << str;
array = (str[0] != ']');
}
else
{
if (name && IsName(str))
return;
name = IsName(str);
if (!name && strcmp(str,".") && strcmp(str,"->") && strcmp(str,"::"))
{
if (str[0] == '(')
return;
Token = tok;
break;
}
ostr << str;
}
}
varname = ostr.str();
}
void CreateStatementList()
{
// Clear lists..
VariableNames.clear();
Statements.clear();
int indentlevel = 0;
for (TOKEN *tok = tokens; tok; tok = GotoNextStatement(tok))
{
if (tok->str[0] == '{')
{
AppendStatement(STATEMENT::OBRACE, tok);
indentlevel++;
}
else if (tok->str[0] == '}')
{
AppendStatement(STATEMENT::EBRACE, tok);
indentlevel--;
}
else if (indentlevel >= 1)
{
bool hasif = false, hasloop = false, hasswitch = false;
if (strcmp(tok->str,"if")==0)
{
hasif = true;
AppendStatement(STATEMENT::IF, tok);
}
else if (strcmp(tok->str,"else")==0)
{
hasif = true;
if (strcmp(getstr(tok,1),"if")==0)
AppendStatement(STATEMENT::ELSEIF, tok);
else
AppendStatement(STATEMENT::ELSE, tok);
}
else if (strcmp(tok->str,"do")==0 ||
strcmp(tok->str,"while")==0 ||
strcmp(tok->str,"for")==0)
{
AppendStatement(STATEMENT::LOOP, tok);
hasloop = true;
}
else if (strcmp(tok->str,"switch")==0)
{
AppendStatement(STATEMENT::SWITCH, tok);
hasswitch = true;
}
// Declaring variables..
if (IsName(tok->str) && strcmp(tok->str,"delete") && strcmp(tok->str,"return"))
{
const char *str1 = getstr(tok, 1);
bool decl = IsName(str1) || str1[0]=='*';
for (TOKEN *tok2 = decl ? tok->next : NULL; tok2; tok2 = tok2->next)
{
if (strchr("{};.", tok2->str[0]))
break;
const char *str1 = getstr(tok2, 1);
if (IsName(tok2->str) && strchr("[=,;",str1[0]))
{
AppendStatement(STATEMENT::DECL, tok2, tok2->str);
while (tok2 && !strchr(",;", tok2->str[0]))
tok2 = tok2->next;
if (tok2->str[0] == ';')
break;
}
}
}
// Assign..
for (TOKEN *tok2 = tok; tok2; tok2 = tok2->next)
{
if (strchr("{};", tok2->str[0]))
break;
TOKEN *eq = tok2;
std::string varname = "";
GetVariableName(eq, varname);
// Equal with..
if (eq && strcmp(eq->str,"=")==0 && !varname.empty())
{
TOKEN *rs = eq->next;
bool ismalloc = false;
ismalloc |= match(rs, "strdup (");
if (rs->str[0]=='(' && IsName(getstr(rs,1)))
{
ismalloc |= match(rs, "( type * ) malloc (");
ismalloc |= match(rs, "( type * * ) malloc (");
ismalloc |= match(rs, "( type type * ) malloc (");
ismalloc |= match(rs, "( type type * * ) malloc (");
}
if ( ismalloc )
AppendStatement(STATEMENT::MALLOC, tok2, varname);
else if ( match(rs,"new type ;") )
AppendStatement(STATEMENT::NEW, tok2, varname);
else if ( match(rs, "new type (") )
AppendStatement(STATEMENT::NEW, tok2, varname);
else if ( match(rs, "new type [") )
AppendStatement(STATEMENT::NEWARRAY, tok2, varname);
else
AppendStatement(STATEMENT::ASSIGN, tok2, varname);
tok2 = eq;
}
}
// Delete..
for (TOKEN *tok2 = tok; tok2; tok2 = tok2->next)
{
if (strchr("{};", tok2->str[0]))
break;
if (match(tok2, "free ( var ) ;"))
AppendStatement(STATEMENT::FREE, tok2, getstr(tok2, 2));
if (match(tok2, "delete var ;"))
AppendStatement(STATEMENT::DELETE, tok2, getstr(tok2,1));
if (match(tok2, "delete [ ] var ;"))
AppendStatement(STATEMENT::DELETEARRAY, tok2, getstr(tok2,3));
}
// Use..
bool UseVar = false;
int parlevel = 0;
for (TOKEN *tok2 = tok; tok2; tok2 = tok2->next)
{
if (parlevel==0 && strchr("{};", tok2->str[0]))
break;
if (tok2->str[0] == '(')
parlevel++;
if (tok2->str[0] == ')')
parlevel--;
if (parlevel == 0 && tok2->str[0] == ',')
UseVar = false;
else if (tok2->str[0]=='=' || tok2->str[0]=='(')
UseVar = true;
else if (UseVar && IsName(tok2->str))
{
std::string varname = "";
GetVariableName(tok2, varname);
if (!varname.empty() &&
varname!="continue" &&
varname!="break" &&
varname!="return")
{
AppendStatement(STATEMENT::USE, tok2, varname);
}
if (tok2->str[0] == ')')
parlevel--;
if (parlevel==0 && tok2->str[0]==';')
break;
}
}
// Return, continue, break..
for (TOKEN *tok2 = tok; tok2; tok2 = tok2->next)
{
if (strchr("{};", tok2->str[0]))
break;
if (strcmp(tok2->str,"continue")==0)
{
AppendStatement(STATEMENT::CONTINUE, tok2);
break;
}
if (strcmp(tok2->str,"break")==0)
{
AppendStatement(STATEMENT::BREAK, tok2);
break;
}
if (strcmp(tok2->str,"return")==0)
{
if (IsName(getstr(tok2,1)) && strcmp(getstr(tok2,2),";")==0)
AppendStatement(STATEMENT::RETURN, tok2, getstr(tok2,1));
else
AppendStatement(STATEMENT::RETURN, tok2, ";");
break;
}
}
if (hasif)
{
AppendStatement(STATEMENT::ENDIF, tok);
}
else if (hasloop)
{
AppendStatement(STATEMENT::ENDLOOP, tok);
}
else if (hasswitch)
{
AppendStatement(STATEMENT::ENDSWITCH, tok);
}
}
}
if (Debug)
{
std::list<STATEMENT>::const_iterator it;
for (it = Statements.begin(); it != Statements.end(); it++)
{
STATEMENT s = *it;
std::cout << it->Token->linenr << " : ";
switch (s.Type)
{
case STATEMENT::OBRACE:
std::cout << "{";
break;
case STATEMENT::EBRACE:
std::cout << "}";
break;
case STATEMENT::DECL:
std::cout << "decl " << VariableNames[s.VarIndex];
break;
case STATEMENT::ASSIGN:
std::cout << "assign " << VariableNames[s.VarIndex];
break;
case STATEMENT::MALLOC:
std::cout << "malloc " << VariableNames[s.VarIndex];
break;
case STATEMENT::FREE:
std::cout << "free " << VariableNames[s.VarIndex];
break;
case STATEMENT::NEW:
std::cout << "new " << VariableNames[s.VarIndex];
break;
case STATEMENT::NEWARRAY:
std::cout << "new[] " << VariableNames[s.VarIndex];
break;
case STATEMENT::DELETE:
std::cout << "delete " << VariableNames[s.VarIndex];
break;
case STATEMENT::DELETEARRAY:
std::cout << "delete[] " << VariableNames[s.VarIndex];
break;
case STATEMENT::USE:
std::cout << "use " << VariableNames[s.VarIndex];
break;
case STATEMENT::LOOP:
std::cout << "loop";
break;
case STATEMENT::ENDLOOP:
std::cout << "endloop";
break;
case STATEMENT::SWITCH:
std::cout << "switch";
break;
case STATEMENT::ENDSWITCH:
std::cout << "endswitch";
break;
case STATEMENT::IF:
std::cout << "if";
break;
case STATEMENT::ELSEIF:
std::cout << "elseif";
break;
case STATEMENT::ELSE:
std::cout << "else";
break;
case STATEMENT::ENDIF:
std::cout << "endif";
break;
case STATEMENT::RETURN:
std::cout << "return " << VariableNames[s.VarIndex];
break;
case STATEMENT::CONTINUE:
std::cout << "continue";
break;
case STATEMENT::BREAK:
std::cout << "break";
break;
default:
std::cout << "ERROR. Unknown code!!";
break;
}
std::cout << "\n";
}
}
}
//---------------------------------------------------------------------------

37
Statements.h Normal file
View File

@ -0,0 +1,37 @@
//---------------------------------------------------------------------------
#ifndef StatementsH
#define StatementsH
//---------------------------------------------------------------------------
#include <list>
#include <vector>
#include <string>
extern std::vector<std::string> VariableNames;
// Forward declaration
struct TOKEN;
struct STATEMENT
{
enum etype {OBRACE, EBRACE,
DECL, ASSIGN, USE,
MALLOC, FREE,
NEW, DELETE,
NEWARRAY, DELETEARRAY,
LOOP, ENDLOOP,
IF, ELSE, ELSEIF, ENDIF,
SWITCH, ENDSWITCH,
RETURN, CONTINUE, BREAK};
etype Type;
unsigned int VarIndex;
TOKEN *Token;
};
extern std::list<STATEMENT> Statements;
void CreateStatementList();
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------

View File

@ -4,7 +4,8 @@
<MACROS> <MACROS>
<VERSION value="BCB.06.00"/> <VERSION value="BCB.06.00"/>
<PROJECT value="cppcheck.exe"/> <PROJECT value="cppcheck.exe"/>
<OBJFILES value="main.obj tokenize.obj"/> <OBJFILES value="main.obj tokenize.obj CheckMemoryLeak.obj CommonCheck.obj Statements.obj
CheckBufferOverrun.obj CheckClass.obj CheckHeaders.obj"/>
<RESFILES value="cppcheck.res"/> <RESFILES value="cppcheck.res"/>
<DEFFILE value=""/> <DEFFILE value=""/>
<RESDEPEN value="$(RESFILES)"/> <RESDEPEN value="$(RESFILES)"/>
@ -54,6 +55,12 @@
<FILE FILENAME="cppcheck.bpf" FORMNAME="" UNITNAME="cppcheck" CONTAINERID="BPF" DESIGNCLASS="" LOCALCOMMAND=""/> <FILE FILENAME="cppcheck.bpf" FORMNAME="" UNITNAME="cppcheck" CONTAINERID="BPF" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="main.cpp" FORMNAME="" UNITNAME="main" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/> <FILE FILENAME="main.cpp" FORMNAME="" UNITNAME="main" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="tokenize.cpp" FORMNAME="" UNITNAME="tokenize" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/> <FILE FILENAME="tokenize.cpp" FORMNAME="" UNITNAME="tokenize" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="CheckMemoryLeak.cpp" FORMNAME="" UNITNAME="CheckMemoryLeak.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="CommonCheck.cpp" FORMNAME="" UNITNAME="CommonCheck.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="Statements.cpp" FORMNAME="" UNITNAME="Statements.cpp" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="CheckBufferOverrun.cpp" FORMNAME="" UNITNAME="CheckBufferOverrun" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="CheckClass.cpp" FORMNAME="" UNITNAME="CheckClass" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="CheckHeaders.cpp" FORMNAME="" UNITNAME="CheckHeaders" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
</FILELIST> </FILELIST>
<BUILDTOOLS> <BUILDTOOLS>
</BUILDTOOLS> </BUILDTOOLS>

1616
main.cpp

File diff suppressed because it is too large Load Diff

View File

@ -11,12 +11,7 @@
std::vector<std::string> Files; std::vector<std::string> Files;
struct TOKEN *tokens, *tokens_back; struct TOKEN *tokens, *tokens_back;
// These functions are in "main.cpp" extern bool IsName(const char str[]);
bool match(struct TOKEN *tok, const std::string pattern);
TOKEN *gettok(struct TOKEN *tok, int index);
const char *getstr(struct TOKEN *tok, int index);
struct DefineSymbol struct DefineSymbol
{ {
@ -408,3 +403,95 @@ void Tokenize(const char FileName[])
//---------------------------------------------------------------------------
// Helper functions for handling the tokens list
//---------------------------------------------------------------------------
TOKEN *findtoken(TOKEN *tok1, const char *tokenstr[])
{
for (TOKEN *ret = tok1; ret; ret = ret->next)
{
unsigned int i = 0;
TOKEN *tok = ret;
while (tokenstr[i])
{
if (!tok)
return NULL;
if (*(tokenstr[i]) && strcmp(tokenstr[i],tok->str))
break;
tok = tok->next;
i++;
}
if (!tokenstr[i])
return ret;
}
return NULL;
}
//---------------------------------------------------------------------------
bool match(TOKEN *tok, const std::string pattern)
{
if (!tok)
return false;
const char *p = pattern.c_str();
while (*p)
{
char str[50];
char *s = str;
while (*p==' ')
p++;
while (*p && *p!=' ')
{
*s = *p;
s++;
p++;
}
*s = 0;
if (str[0] == 0)
return true;
if (strcmp(str,"var")==0 || strcmp(str,"type")==0)
{
if (!IsName(tok->str))
return false;
}
else if (strcmp(str,"num")==0)
{
if (!std::isdigit(tok->str[0]))
return false;
}
else if (strcmp(str, tok->str) != 0)
return false;
tok = tok->next;
if (!tok)
return false;
}
return true;
}
//---------------------------------------------------------------------------
TOKEN *gettok(TOKEN *tok, int index)
{
while (tok && index>0)
{
tok = tok->next;
index--;
}
return tok;
}
//---------------------------------------------------------------------------
const char *getstr(TOKEN *tok, int index)
{
tok = gettok(tok, index);
return tok ? tok->str : "";
}
//---------------------------------------------------------------------------

View File

@ -20,6 +20,13 @@ extern struct TOKEN *tokens, *tokens_back;
void Tokenize(const char FileName[]); void Tokenize(const char FileName[]);
// Helper functions for handling the tokens list..
TOKEN *findtoken(TOKEN *tok1, const char *tokenstr[]);
bool match(TOKEN *tok, const std::string pattern);
TOKEN *gettok(TOKEN *tok, int index);
const char *getstr(TOKEN *tok, int index);
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif #endif