CheckClass; Added files (Check for mistakes related to classes)
This commit is contained in:
parent
399a3e2598
commit
f20c34a751
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifndef CheckClassH
|
||||||
|
#define CheckClassH
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
void CheckConstructors();
|
||||||
|
|
||||||
|
void CheckUnusedPrivateFunctions();
|
||||||
|
|
||||||
|
void CheckMemset();
|
||||||
|
|
||||||
|
void CheckOperatorEq1(); // Warning upon "void operator=(.."
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifndef CommonCheckH
|
||||||
|
#define CommonCheckH
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct TOKEN;
|
||||||
|
|
||||||
|
std::string FileLine(TOKEN *tok);
|
||||||
|
|
||||||
|
void ReportErr(const std::string errmsg);
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
//---------------------------------------------------------------------------
|
|
@ -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>
|
||||||
|
|
99
tokenize.cpp
99
tokenize.cpp
|
@ -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 : "";
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue