jedioutcast/utils/Assimilate/Tokenizer.cpp
2013-04-04 13:07:40 -05:00

3346 lines
58 KiB
C++

// Tokenizer.cpp
#ifndef NOT_USING_MODULES
// !!! if you are not using modules, read BELOW !!!
#include "Module.h" // if you are not using modules,
// create an empty Module.h in your
// project -- use of modules allows
// the error handler to be overridden
// with a custom CErrHandler
#endif
#include "Tokenizer.h"
enum
{
DIR_INCLUDE = TK_USERDEF,
DIR_IFDEF,
DIR_IFNDEF,
DIR_ENDIF,
DIR_ELSE,
DIR_DEFINE,
DIR_UNDEFINE,
};
keywordArray_t CTokenizer::directiveKeywords[] =
{
"include", DIR_INCLUDE,
"ifdef", DIR_IFDEF,
"ifndef", DIR_IFNDEF,
"endif", DIR_ENDIF,
"else", DIR_ELSE,
"define", DIR_DEFINE,
"undefine", DIR_UNDEFINE,
"", TK_EOF,
};
keywordArray_t CTokenizer::errorMessages[] =
{
"No Error", TKERR_NONE,
"Unknown Error", TKERR_UNKNOWN,
"Buffer creation failed", TKERR_BUFFERCREATE,
"Unrecognized symbol", TKERR_UNRECOGNIZEDSYMBOL,
"Duplicate symbol", TKERR_DUPLICATESYMBOL,
"String length exceeded", TKERR_STRINGLENGTHEXCEEDED,
"Identifier length exceeded", TKERR_IDENTIFIERLENGTHEXCEEDED,
"Expected integer", TKERR_EXPECTED_INTEGER,
"Expected identifier", TKERR_EXPECTED_IDENTIFIER,
"Expected string", TKERR_EXPECTED_STRING,
"Expected char", TKERR_EXPECTED_CHAR,
"Expected float", TKERR_EXPECTED_FLOAT,
"Unexpected token", TKERR_UNEXPECTED_TOKEN,
"Invalid directive", TKERR_INVALID_DIRECTIVE,
"Include file not found", TKERR_INCLUDE_FILE_NOTFOUND,
"Unmatched directive", TKERR_UNMATCHED_DIRECTIVE,
"Unexpected End of File", TKERR_UNEXPECTED_EOF,
"", TKERR_USERERROR,
};
//
// CSymbol
//
CSymbol::CSymbol()
{
}
CSymbol::~CSymbol()
{
}
CSymbol* CSymbol::Create(LPCTSTR symbolName)
{
CSymbol* retval = new CSymbol();
retval->Init(symbolName);
return retval;
}
LPCTSTR CSymbol::GetName()
{
if (m_symbolName == NULL)
{
return "";
}
return m_symbolName;
}
void CSymbol::Init(LPCTSTR symbolName)
{
if ((symbolName == NULL) || (strlen(symbolName) < 1))
{
m_symbolName = NULL;
return;
}
m_symbolName = (char*)malloc(strlen(symbolName) + 1);
// ASSERT(m_symbolName);
strcpy(m_symbolName, symbolName);
}
void CSymbol::Delete()
{
if (m_symbolName != NULL)
{
free(m_symbolName);
m_symbolName = NULL;
}
delete this;
}
//
// CDirectiveSymbol
//
CDirectiveSymbol::CDirectiveSymbol()
{
}
CDirectiveSymbol::~CDirectiveSymbol()
{
}
CDirectiveSymbol* CDirectiveSymbol::Create(LPCTSTR symbolName)
{
CDirectiveSymbol* retval = new CDirectiveSymbol();
retval->Init(symbolName);
return retval;
}
void CDirectiveSymbol::Init(LPCTSTR symbolName)
{
CSymbol::Init(symbolName);
m_value = NULL;
}
void CDirectiveSymbol::Delete()
{
if (m_value != NULL)
{
free(m_value);
m_value = NULL;
}
CSymbol::Delete();
}
void CDirectiveSymbol::SetValue(LPCTSTR value)
{
if (m_value != NULL)
{
free(m_value);
m_value = NULL;
}
if ((value == NULL) || (strlen(value) < 1))
{
return;
}
m_value = (char*)malloc(strlen(value) + 1);
strcpy(m_value, value);
}
LPCTSTR CDirectiveSymbol::GetValue()
{
return m_value;
}
//
// CIntSymbol
//
CIntSymbol::CIntSymbol()
{
}
CIntSymbol* CIntSymbol::Create(LPCTSTR symbolName, int value)
{
CIntSymbol* retval = new CIntSymbol();
retval->Init(symbolName, value);
return retval;
}
void CIntSymbol::Delete()
{
CSymbol::Delete();
}
void CIntSymbol::Init(LPCTSTR symbolName, int value)
{
CSymbol::Init(symbolName);
m_value = value;
}
int CIntSymbol::GetValue()
{
return m_value;
}
//
// CSymbolTable
//
CSymbolTable::CSymbolTable()
{
Init();
}
CSymbolTable::~CSymbolTable()
{
}
CSymbolTable* CSymbolTable::Create()
{
CSymbolTable* retval = new CSymbolTable();
retval->Init();
return retval;
}
void CSymbolTable::Init()
{
}
void CSymbolTable::DiscardSymbols()
{
for (symbolmap_t::iterator isymbol = m_symbols.begin(); isymbol != m_symbols.end(); isymbol++)
{
(*isymbol).second->Delete();
}
m_symbols.erase(m_symbols.begin(), m_symbols.end());
}
void CSymbolTable::Delete()
{
DiscardSymbols();
delete this;
}
void CSymbolTable::Iterate(void function(CSymbol*, DWORD, DWORD), DWORD parm1, DWORD parm2)
{
for (symbolmap_t::iterator isymbol = m_symbols.begin(); isymbol != m_symbols.end(); isymbol++)
{
function((*isymbol).second, parm1, parm2);
}
}
int CSymbolTable::GetNumEntries()
{
return m_symbols.size();
}
LPCSTR CSymbolTable::GetEntry(int iIndex)
{
if (iIndex<GetNumEntries())
{
int i=0;
for (symbolmap_t::iterator isymbol = m_symbols.begin(); isymbol != m_symbols.end(); isymbol++)
{
if (i++==iIndex)
return (*isymbol).first;
}
}
return NULL;
}
bool CSymbolTable::AddSymbol(CSymbol* theSymbol)
{
LPCTSTR name = theSymbol->GetName();
symbolmap_t::iterator iter = m_symbols.find(name);
if (iter != m_symbols.end())
{
return false;
}
m_symbols.insert(symbolmap_t::value_type(name, theSymbol));
return true;
}
CSymbol* CSymbolTable::FindSymbol(LPCTSTR symbolName)
{
if (symbolName)
{
symbolmap_t::iterator iter = m_symbols.find(symbolName);
if (iter != m_symbols.end())
{
return (*iter).second;
}
}
return NULL;
}
CSymbol* CSymbolTable::ExtractSymbol(LPCTSTR symbolName)
{
symbolmap_t::iterator iter = m_symbols.find(symbolName);
if (iter != m_symbols.end())
{
CSymbol* retval = (*iter).second;
m_symbols.erase(iter);
return retval;
}
return NULL;
}
void CSymbolTable::RemoveSymbol(LPCTSTR symbolName)
{
m_symbols.erase(symbolName);
}
//
// CParseStream
//
CParseStream::CParseStream()
{
}
CParseStream::~CParseStream()
{
}
CParseStream* CParseStream::Create()
{
return NULL;
}
void CParseStream::Delete()
{
delete this;
}
bool CParseStream::Init()
{
m_next = NULL;
m_original = false;
return true;
}
bool CParseStream::NextChar(byte& theByte)
{
return false;
}
long CParseStream::GetRemainingSize()
{
return 0;
}
bool CParseStream::CanEndOfFile()
{
return false;
}
CParseStream* CParseStream::GetNext()
{
return m_next;
}
void CParseStream::SetNext(CParseStream* next)
{
m_next = next;
}
int CParseStream::GetCurLine()
{
return 0;
}
void CParseStream::GetCurFilename(char** theBuff)
{
*theBuff = NULL;
}
bool CParseStream::IsThisDefinition(void* theDefinition)
{
return false;
}
//
// CParsePutBack
//
CParsePutBack::CParsePutBack()
{
}
CParsePutBack::~CParsePutBack()
{
}
CParsePutBack* CParsePutBack::Create(byte theByte, CParseStream* parent)
{
CParsePutBack* curParsePutBack = new CParsePutBack();
curParsePutBack->Init(theByte, parent);
return curParsePutBack;
}
void CParsePutBack::Delete()
{
delete this;
}
bool CParsePutBack::NextChar(byte& theByte)
{
if (m_consumed)
{
return false;
}
theByte = m_byte;
m_consumed = true;
return true;
}
void CParsePutBack::Init(byte theByte, CParseStream* parent)
{
CParseStream::Init();
m_consumed = false;
m_byte = theByte;
m_curLine = 0;
m_parent = parent;
if (m_parent != NULL)
{
m_curLine = m_parent->GetCurLine();
}
}
long CParsePutBack::GetRemainingSize()
{
if (m_consumed)
{
return 0;
}
else
{
return 1;
}
}
int CParsePutBack::GetCurLine()
{
return m_curLine;
}
void CParsePutBack::GetCurFilename(char** theBuff)
{
if (m_parent == NULL)
{
*theBuff = NULL;
return;
}
m_parent->GetCurFilename(theBuff);
}
//
// CParseFile
//
CParseFile::CParseFile()
{
}
CParseFile::~CParseFile()
{
}
CParseFile* CParseFile::Create()
{
CParseFile* theParseFile = new CParseFile();
if ( !theParseFile->Init() )
{
delete theParseFile;
return NULL;
}
return theParseFile;
}
CParseFile* CParseFile::Create(LPCTSTR filename, CTokenizer* tokenizer, DWORD buffsize)
{
CParseFile* theParseFile = new CParseFile();
if ( theParseFile->Init(filename, tokenizer, buffsize) )
return theParseFile;
theParseFile->Delete();
return NULL;
}
void CParseFile::Delete()
{
if (m_buff != NULL)
{
free(m_buff);
m_buff = NULL;
}
if (m_ownsFile && (m_fileHandle != NULL))
{
CloseHandle(m_fileHandle);
m_fileHandle = NULL;
}
if (m_fileName != NULL)
{
free(m_fileName);
m_fileName = NULL;
}
delete this;
}
bool CParseFile::Init()
{
m_fileHandle = NULL;
m_buff = NULL;
m_ownsFile = false;
m_curByte = NULL;
m_curLine = 1;
m_fileName = NULL;
m_usesBuffer = false;
m_buffsize = 0;
m_buffByte = 0;
bool retval = CParseStream::Init();
m_original = true;
return retval;
}
DWORD CParseFile::GetFileSize()
{
DWORD dwCur = SetFilePointer(m_fileHandle, 0L, NULL, FILE_CURRENT);
DWORD dwLen = SetFilePointer(m_fileHandle, 0, NULL, FILE_END);
SetFilePointer(m_fileHandle, dwCur, NULL, FILE_BEGIN);
return dwLen;
}
bool CParseFile::CanEndOfFile()
{
return true;
}
void CParseFile::Read(void* buff, UINT buffsize)
{
DWORD bytesRead;
ReadFile(m_fileHandle, buff, buffsize, &bytesRead, NULL);
}
bool CParseFile::Init(LPCTSTR filename, CTokenizer* tokenizer, DWORD buffsize)
{
CParseStream::Init();
m_fileName = (char*)malloc(strlen(filename) + 1);
strcpy(m_fileName, filename);
DWORD dwAccess = GENERIC_READ;
DWORD dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = 0;
DWORD dwCreateFlag = OPEN_EXISTING;
//need to get the game path to complete filename
m_fileHandle = CreateFile(filename, dwAccess, dwShareMode, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL, NULL);
if (m_fileHandle == (HANDLE)-1)
{
tokenizer->Error(TKERR_INCLUDE_FILE_NOTFOUND, filename);
//
// if you don't do this, you get a memory leak when the Init() code below orphans this handle
// (malloc'd at function top), I know it'll always be NZ, but I just prefer handling memptrs legally...-slc
//
if (m_fileName)
{
free(m_fileName);
m_fileName = NULL; // I know this gets zeroed in Init(), but I really hate leaving bad ptrs!
}
Init();
return false;
}
m_filesize = GetFileSize();
if (buffsize > 0)
{
m_usesBuffer = true;
if (buffsize > m_filesize)
{
buffsize = m_filesize;
}
}
else
{
buffsize = m_filesize;
}
m_buff = (byte*)malloc(buffsize);
if (m_buff == NULL)
{
tokenizer->Error(TKERR_BUFFERCREATE);
Init();
return false;
}
Read(m_buff, buffsize);
m_buffsize = buffsize;
m_curByte = 0;
m_buffByte = 0;
m_curPos = 1;
m_ownsFile = true;
m_curLine = 1;
m_original = true;
return true;
}
long CParseFile::GetRemainingSize()
{
return m_filesize - m_curByte;
}
bool CParseFile::NextChar(byte& theByte)
{
if (m_curByte >= m_filesize)
{
return false;
}
if (m_buff[m_buffByte] == '\n')
{
m_curLine += 1;
m_curPos = 1;
}
else
{
m_curPos++;
}
theByte = m_buff[m_buffByte++];
m_curByte++;
if (m_buffByte >= m_buffsize)
{
if (m_buffsize > GetRemainingSize())
{
m_buffsize = GetRemainingSize();
}
Read(m_buff, m_buffsize);
m_buffByte = 0;
}
return true;
}
int CParseFile::GetCurLine()
{
return m_curLine;
}
void CParseFile::GetCurFilename(char** theBuff)
{
*theBuff = NULL;
if (m_fileName != NULL)
{
*theBuff = (char*)malloc(strlen(m_fileName) + 1);
strcpy(*theBuff, m_fileName);
}
}
//
// CParseMemory
//
CParseMemory::CParseMemory()
{
}
CParseMemory::~CParseMemory()
{
}
CParseMemory* CParseMemory::Create(byte* data, long datasize, bool original)
{
CParseMemory* curParse = new CParseMemory();
curParse->Init(data, datasize, original);
return curParse;
}
void CParseMemory::Delete()
{
delete this;
}
bool CParseMemory::CanEndOfFile()
{
return true;
}
bool CParseMemory::NextChar(byte& theByte)
{
if (m_offset < m_datasize)
{
if (m_data[m_offset] == '\n')
{
m_curLine += 1;
m_curPos = 1;
}
else
{
m_curPos++;
}
theByte = m_data[m_offset++];
return true;
}
else
{
return false;
}
}
void CParseMemory::Init(byte* data, long datasize, bool original)
{
m_data = data;
m_curLine = 1;
m_curPos = 1;
m_offset = 0;
m_datasize = datasize;
m_original = original;
}
long CParseMemory::GetRemainingSize()
{
return m_datasize - m_offset;
}
int CParseMemory::GetCurLine()
{
return m_curLine;
}
void CParseMemory::GetCurFilename(char** theBuff)
{
*theBuff = NULL;
}
//
// CParseBlock
//
CParseBlock::CParseBlock()
{
}
CParseBlock::~CParseBlock()
{
}
CParseBlock* CParseBlock::Create(byte* data, long datasize)
{
CParseBlock* curParse = new CParseBlock();
curParse->Init(data, datasize);
return curParse;
}
void CParseBlock::Delete()
{
if (m_data != NULL)
{
free(m_data);
m_data = NULL;
}
delete this;
}
bool CParseBlock::CanEndOfFile()
{
return false;
}
void CParseBlock::Init(byte* data, long datasize)
{
m_data = (byte*)malloc(datasize);
memcpy(m_data, data, datasize);
m_curLine = 1;
m_curPos = 1;
m_offset = 0;
m_datasize = datasize;
m_original = false;
}
//
// CParseToken
//
CParseToken::CParseToken()
{
}
CParseToken::~CParseToken()
{
}
CParseToken* CParseToken::Create(CToken* token)
{
CParseToken* curParse = new CParseToken();
curParse->Init(token);
return curParse;
}
void CParseToken::Delete()
{
if (m_data != NULL)
{
free(m_data);
m_data = NULL;
}
delete this;
}
bool CParseToken::NextChar(byte& theByte)
{
if (m_offset < m_datasize)
{
if (m_data[m_offset] == '\n')
{
m_curLine += 1;
m_curPos = 1;
}
else
{
m_curPos++;
}
theByte = m_data[m_offset++];
return true;
}
else
{
return false;
}
}
void CParseToken::Init(CToken* token)
{
LPCTSTR tokenString = token->GetStringValue();
m_datasize = strlen(tokenString);
if (m_datasize > 0)
{
m_data = (byte*) malloc(m_datasize);
memcpy(m_data, tokenString, m_datasize);
}
else
{
m_data = NULL;
}
m_curLine = 1;
m_curPos = 1;
m_offset = 0;
m_original = false;
token->Delete();
}
long CParseToken::GetRemainingSize()
{
return m_datasize - m_offset;
}
int CParseToken::GetCurLine()
{
return m_curLine;
}
void CParseToken::GetCurFilename(char** theBuff)
{
*theBuff = NULL;
}
//
// CParseDefine
//
CParseDefine::CParseDefine()
{
}
CParseDefine::~CParseDefine()
{
}
CParseDefine* CParseDefine::Create(CDirectiveSymbol* definesymbol)
{
CParseDefine* retval = new CParseDefine();
retval->Init(definesymbol);
return retval;
}
bool CParseDefine::CanEndOfFile()
{
return false;
}
void CParseDefine::Delete()
{
CParseMemory::Delete();
}
void CParseDefine::Init(CDirectiveSymbol* definesymbol)
{
CParseMemory::Init((byte*)definesymbol->GetValue(), strlen(definesymbol->GetValue()));
m_defineSymbol = definesymbol;
}
bool CParseDefine::IsThisDefinition(void* theDefinition)
{
return (CDirectiveSymbol*)theDefinition == m_defineSymbol;
}
//
// CToken
//
CToken::CToken()
{
}
CToken::~CToken()
{
}
CToken* CToken::Create()
{
CToken* theToken;
if (m_avail == NULL)
{
theToken = new CToken();
}
else
{
theToken = m_avail;
m_avail = theToken->GetNext();
}
theToken->Init();
return theToken;
}
void CToken::Delete()
{
if (m_string != NULL)
{
free(m_string);
m_string = NULL;
}
MakeAvail();
}
void CToken::Init()
{
m_next = NULL;
m_string = NULL;
}
void CToken::SetNext(CToken* theToken)
{
m_next = theToken;
}
CToken* CToken::GetNext()
{
return m_next;
}
int CToken::GetType()
{
return TK_EOF;
}
int CToken::GetIntValue()
{
return 0;
}
LPCTSTR CToken::GetStringValue()
{
if (m_string == NULL)
{
return "";
}
return m_string;
}
float CToken::GetFloatValue()
{
return 0.0;
}
//
// CCharToken
//
CCharToken::CCharToken()
{
}
CCharToken::~CCharToken()
{
}
CCharToken* CCharToken::Create(byte theByte)
{
CCharToken* theToken;
if (m_avail == NULL)
{
theToken = new CCharToken();
}
else
{
theToken = m_avail;
m_avail = (CCharToken*)theToken->GetNext();
}
theToken->Init(theByte);
return theToken;
}
void CCharToken::Delete()
{
CToken::Delete();
}
void CCharToken::Init(byte theByte)
{
CToken::Init();
char charString[10];
switch(theByte)
{
case '\0':
strcpy(charString, "\\0");
break;
case '\n':
strcpy(charString, "\\n");
break;
case '\\':
strcpy(charString, "\\\\");
break;
case '\'':
strcpy(charString, "\\'");
break;
case '\?':
strcpy(charString, "\\?");
break;
case '\a':
strcpy(charString, "\\a");
break;
case '\b':
strcpy(charString, "\\b");
break;
case '\f':
strcpy(charString, "\\f");
break;
case '\r':
strcpy(charString, "\\r");
break;
case '\t':
strcpy(charString, "\\t");
break;
case '\v':
strcpy(charString, "\\v");
break;
default:
charString[0] = (char)theByte;
charString[1] = '\0';
break;
}
m_string = (char*)malloc(strlen(charString) + 1);
strcpy(m_string, charString);
}
int CCharToken::GetType()
{
return TK_CHAR;
}
//
// CStringToken
//
CStringToken::CStringToken()
{
}
CStringToken::~CStringToken()
{
}
CStringToken* CStringToken::Create(LPCTSTR theString)
{
CStringToken* theToken;
if (m_avail == NULL)
{
theToken = new CStringToken();
}
else
{
theToken = m_avail;
m_avail = (CStringToken*)theToken->GetNext();
}
theToken->Init(theString);
return theToken;
}
void CStringToken::Delete()
{
CToken::Delete();
}
void CStringToken::Init(LPCTSTR theString)
{
CToken::Init();
m_string = (char*)malloc(strlen(theString) + 1);
// ASSERT(m_string);
strcpy(m_string, theString);
}
int CStringToken::GetType()
{
return TK_STRING;
}
//
// CIntToken
//
CIntToken::CIntToken()
{
}
CIntToken::~CIntToken()
{
}
CIntToken* CIntToken::Create(long value)
{
CIntToken* theToken;
if (m_avail == NULL)
{
theToken = new CIntToken();
}
else
{
theToken = m_avail;
m_avail = (CIntToken*)theToken->GetNext();
}
theToken->Init(value);
return theToken;
}
void CIntToken::Delete()
{
CToken::Delete();
}
void CIntToken::Init(long value)
{
CToken::Init();
m_value = value;
}
int CIntToken::GetType()
{
return TK_INT;
}
int CIntToken::GetIntValue()
{
return m_value;
}
float CIntToken::GetFloatValue()
{
return (float)m_value;
}
LPCTSTR CIntToken::GetStringValue()
{
if (m_string != NULL)
{
free(m_string);
m_string = NULL;
}
char temp[128];
sprintf(temp, "%d", m_value);
m_string = (char*)malloc(strlen(temp) + 1);
strcpy(m_string, temp);
return m_string;
}
//
// CFloatToken
//
CFloatToken::CFloatToken()
{
}
CFloatToken::~CFloatToken()
{
}
CFloatToken* CFloatToken::Create(float value)
{
CFloatToken* theToken;
if (m_avail == NULL)
{
theToken = new CFloatToken();
}
else
{
theToken = m_avail;
m_avail = (CFloatToken*)theToken->GetNext();
}
theToken->Init(value);
return theToken;
}
void CFloatToken::Delete()
{
CToken::Delete();
}
void CFloatToken::Init(float value)
{
CToken::Init();
m_value = value;
}
int CFloatToken::GetType()
{
return TK_FLOAT;
}
float CFloatToken::GetFloatValue()
{
return m_value;
}
LPCTSTR CFloatToken::GetStringValue()
{
if (m_string != NULL)
{
free(m_string);
m_string = NULL;
}
char temp[128];
sprintf(temp, "%g", m_value);
m_string = (char*)malloc(strlen(temp) + 1);
strcpy(m_string, temp);
return m_string;
}
//
// CIdentifierToken
//
CIdentifierToken::CIdentifierToken()
{
}
CIdentifierToken::~CIdentifierToken()
{
}
CIdentifierToken* CIdentifierToken::Create(LPCTSTR name)
{
CIdentifierToken* theToken;
if (m_avail == NULL)
{
theToken = new CIdentifierToken();
}
else
{
theToken = m_avail;
m_avail = (CIdentifierToken*)theToken->GetNext();
}
theToken->Init(name);
return theToken;
}
void CIdentifierToken::Delete()
{
CToken::Delete();
}
void CIdentifierToken::Init(LPCTSTR name)
{
CToken::Init();
m_string = (char*)malloc(strlen(name) + 1);
// ASSERT(m_string);
strcpy(m_string, name);
}
int CIdentifierToken::GetType()
{
return TK_IDENTIFIER;
}
//
// CCommentToken
//
CCommentToken::CCommentToken()
{
}
CCommentToken::~CCommentToken()
{
}
CCommentToken* CCommentToken::Create(LPCTSTR name)
{
CCommentToken* theToken;
if (m_avail == NULL)
{
theToken = new CCommentToken();
}
else
{
theToken = m_avail;
m_avail = (CCommentToken*)theToken->GetNext();
}
theToken->Init(name);
return theToken;
}
void CCommentToken::Delete()
{
CToken::Delete();
}
void CCommentToken::Init(LPCTSTR name)
{
CToken::Init();
m_string = (char*)malloc(strlen(name) + 1);
// ASSERT(m_string);
strcpy(m_string, name);
}
int CCommentToken::GetType()
{
return TK_COMMENT;
}
//
// CSpaceToken
//
CSpaceToken::CSpaceToken()
{
}
CSpaceToken::~CSpaceToken()
{
}
CSpaceToken* CSpaceToken::Create(LPCTSTR name)
{
CSpaceToken* theToken;
if (m_avail == NULL)
{
theToken = new CSpaceToken();
}
else
{
theToken = m_avail;
m_avail = (CSpaceToken*)theToken->GetNext();
}
theToken->Init(name);
return theToken;
}
void CSpaceToken::Delete()
{
CToken::Delete();
}
void CSpaceToken::Init(LPCTSTR name)
{
CToken::Init();
m_string = (char*)malloc(strlen(name) + 1);
// ASSERT(m_string);
strcpy(m_string, name);
}
int CSpaceToken::GetType()
{
return TK_SPACE;
}
//
// CUserToken
//
CUserToken::CUserToken()
{
}
CUserToken::~CUserToken()
{
}
CUserToken* CUserToken::Create(int value, LPCTSTR string)
{
CUserToken* theToken;
if (m_avail == NULL)
{
theToken = new CUserToken();
}
else
{
theToken = m_avail;
m_avail = (CUserToken*)theToken->GetNext();
}
theToken->Init(value, string);
return theToken;
}
void CUserToken::Delete()
{
CToken::Delete();
}
void CUserToken::Init(int value, LPCTSTR string)
{
CToken::Init();
m_value = value;
m_string = (char*)malloc(strlen(string) + 1);
strcpy(m_string, string);
}
int CUserToken::GetType()
{
return m_value;
}
//
// CUndefinedToken
//
CUndefinedToken::CUndefinedToken()
{
}
CUndefinedToken::~CUndefinedToken()
{
}
CUndefinedToken* CUndefinedToken::Create(LPCTSTR string)
{
CUndefinedToken* theToken;
if (m_avail == NULL)
{
theToken = new CUndefinedToken();
}
else
{
theToken = m_avail;
m_avail = (CUndefinedToken*)theToken->GetNext();
}
theToken->Init(string);
return theToken;
}
void CUndefinedToken::Delete()
{
CToken::Delete();
}
void CUndefinedToken::Init(LPCTSTR string)
{
CToken::Init();
m_string = (char*)malloc(strlen(string) + 1);
strcpy(m_string, string);
}
int CUndefinedToken::GetType()
{
return TK_UNDEFINED;
}
//
// CTokenizerState
//
CTokenizerState::CTokenizerState()
{
}
CTokenizerState::~CTokenizerState()
{
}
CTokenizerState* CTokenizerState::Create(bool skip)
{
CTokenizerState* retval = new CTokenizerState();
retval->Init(skip);
return retval;
}
void CTokenizerState::Init(bool skip)
{
m_next = NULL;
m_skip = skip;
m_elseHit = false;
}
void CTokenizerState::Delete()
{
delete this;
}
CTokenizerState* CTokenizerState::GetNext()
{
return m_next;
}
bool CTokenizerState::ProcessElse()
{
if (!m_elseHit)
{
m_elseHit = true;
m_skip = !m_skip;
}
return m_elseHit;
}
void CTokenizerState::SetNext(CTokenizerState* next)
{
m_next = next;
}
bool CTokenizerState::Skipping()
{
return m_skip;
}
//
// CTokenizerHolderState
//
CTokenizerHolderState::CTokenizerHolderState()
{
}
CTokenizerHolderState::~CTokenizerHolderState()
{
}
CTokenizerHolderState* CTokenizerHolderState::Create()
{
CTokenizerHolderState* retval = new CTokenizerHolderState();
retval->Init();
return retval;
}
void CTokenizerHolderState::Init()
{
CTokenizerState::Init(true);
}
void CTokenizerHolderState::Delete()
{
delete this;
}
bool CTokenizerHolderState::ProcessElse()
{
if (!m_elseHit)
{
m_elseHit = true;
}
return m_elseHit;
}
//
// CKeywordTable
//
CKeywordTable::CKeywordTable(CTokenizer* tokenizer, keywordArray_t* keywords)
{
m_tokenizer = tokenizer;
m_holdKeywords = tokenizer->SetKeywords(keywords);
}
CKeywordTable::~CKeywordTable()
{
m_tokenizer->SetKeywords(m_holdKeywords);
}
//
// CTokenizer
//
CTokenizer::CTokenizer()
{
}
CTokenizer::~CTokenizer()
{
}
CTokenizer* CTokenizer::Create(UINT dwFlags)
{
CTokenizer* theTokenizer = new CTokenizer();
theTokenizer->Init(dwFlags);
return theTokenizer;
}
void CTokenizer::Delete()
{
while (m_curParseStream != NULL)
{
CParseStream* curStream = m_curParseStream;
m_curParseStream = curStream->GetNext();
curStream->Delete();
}
if (m_symbolLookup != NULL)
{
m_symbolLookup->Delete();
m_symbolLookup = NULL;
}
while (m_nextToken != NULL)
{
CToken* curToken = m_nextToken;
m_nextToken = curToken->GetNext();
curToken->Delete();
}
while (m_state != NULL)
{
Error(TKERR_UNMATCHED_DIRECTIVE);
CTokenizerState* curState = m_state;
m_state = curState->GetNext();
curState->Delete();
}
/* if (m_lastErrMsg != NULL)
{
free(m_lastErrMsg);
m_lastErrMsg = NULL;
}*/
CToken::DeleteAll();
CCharToken::DeleteAll();
CIntToken::DeleteAll();
CFloatToken::DeleteAll();
CStringToken::DeleteAll();
CSpaceToken::DeleteAll();
CUndefinedToken::DeleteAll();
CUserToken::DeleteAll();
CIdentifierToken::DeleteAll();
CCommentToken::DeleteAll();
delete this;
}
void CTokenizer::Error(int theError)
{
char errString[128];
char lookupstring[128];
int i = 0;
while ((errorMessages[i].m_tokenvalue != TKERR_USERERROR) && (errorMessages[i].m_tokenvalue != theError))
{
i++;
}
if ((errorMessages[i].m_tokenvalue == TKERR_USERERROR) && (m_errors != NULL))
{
i = 0;
while ((m_errors[i].m_tokenvalue != TK_EOF) && (m_errors[i].m_tokenvalue != theError))
{
i++;
}
strcpy(lookupstring, m_errors[i].m_keyword);
}
else
{
strcpy(lookupstring, errorMessages[i].m_keyword);
}
// If anyone objects to me altering this, say so... -Ste
// sprintf(errString, "Error -- %d, %s", theError, lookupstring);
sprintf(errString, "Error -- %d, \"%s\" (line %d)", theError, lookupstring, GetCurLine());
Error(errString, theError);
}
void CTokenizer::Error(int theError, LPCTSTR errString)
{
char errstring[128];
char lookupstring[128];
int i = 0;
while ((errorMessages[i].m_tokenvalue != TKERR_USERERROR) && (errorMessages[i].m_tokenvalue != theError))
{
i++;
}
if ((errorMessages[i].m_tokenvalue == TKERR_USERERROR) && (m_errors != NULL))
{
i = 0;
while ((m_errors[i].m_tokenvalue != TK_EOF) && (m_errors[i].m_tokenvalue != theError))
{
i++;
}
strcpy(lookupstring, m_errors[i].m_keyword);
}
else
{
strcpy(lookupstring, errorMessages[i].m_keyword);
}
// If anyone objects to me altering this, say so... -Ste
// sprintf(errstring, "Error -- %d, %s - %s", theError, lookupstring, errString);
_snprintf(errstring, sizeof(errstring), "Error -- %d, %s - \"%s\" (line %d)", theError, lookupstring, errString, GetCurLine());
Error(errstring, theError);
}
void CTokenizer::Error(LPCTSTR errString, int theError)
{
if (m_errorProc != NULL)
{
m_errorProc(errString);
}
#ifdef USES_MODULES
else
{
ReportError(theError, errString);
}
#endif
}
bool CTokenizer::AddParseFile(LPCTSTR filename, DWORD buffsize)
{
CParseStream* newStream = CParseFile::Create(filename, this, buffsize);
if ( newStream != NULL )
{
newStream->SetNext(m_curParseStream);
m_curParseStream = newStream;
return true;
}
return false;
}
void CTokenizer::AddParseStream(byte* data, long datasize)
{
CParseStream* newStream = CParseMemory::Create(data, datasize, true);
newStream->SetNext(m_curParseStream);
m_curParseStream = newStream;
}
long CTokenizer::GetRemainingSize()
{
long retval = 0;
CParseStream* curStream = m_curParseStream;
while (curStream != NULL)
{
retval += curStream->GetRemainingSize();
curStream = curStream->GetNext();
}
return retval;
}
LPCTSTR CTokenizer::LookupToken(int tokenID, keywordArray_t* theTable)
{
if (theTable == NULL)
{
theTable = m_keywords;
}
if (theTable == NULL)
{
return NULL;
}
int i = 0;
while (theTable[i].m_tokenvalue != TK_EOF)
{
if (theTable[i].m_tokenvalue == tokenID)
{
return theTable[i].m_keyword;
}
i++;
}
return NULL;
}
void CTokenizer::PutBackToken(CToken* theToken, bool commented, LPCTSTR addedChars)
{
if (commented)
{
CParseToken* newStream = CParseToken::Create(theToken);
newStream->SetNext(m_curParseStream);
m_curParseStream = newStream;
if (addedChars != NULL)
{
CParsePutBack* spacer = CParsePutBack::Create(' ', newStream);
spacer->SetNext(m_curParseStream);
m_curParseStream = spacer;
CParseBlock* newBlock = CParseBlock::Create((byte*)addedChars, strlen(addedChars));
newBlock->SetNext(m_curParseStream);
m_curParseStream = newBlock;
}
char temp[] = "// * ";
CParseBlock* newBlock = CParseBlock::Create((byte*)temp, strlen(temp));
newBlock->SetNext(m_curParseStream);
m_curParseStream = newBlock;
return;
}
switch(theToken->GetType())
{
case TK_INT:
case TK_EOF:
case TK_UNDEFINED:
case TK_FLOAT:
case TK_CHAR:
case TK_STRING:
case TK_EOL:
case TK_COMMENT:
theToken->SetNext(m_nextToken);
m_nextToken = theToken;
break;
default:
CParseToken* newStream = CParseToken::Create(theToken);
newStream->SetNext(m_curParseStream);
m_curParseStream = newStream;
break;
}
if (addedChars != NULL)
{
CParseBlock* newBlock = CParseBlock::Create((byte*)addedChars, strlen(addedChars));
newBlock->SetNext(m_curParseStream);
m_curParseStream = newBlock;
}
}
CToken* CTokenizer::GetToken(keywordArray_t* keywords, UINT onFlags, UINT offFlags)
{
keywordArray_t* holdKeywords = SetKeywords(keywords);
CToken* retval = GetToken(onFlags, offFlags);
SetKeywords(holdKeywords);
return retval;
}
CToken* CTokenizer::GetToken(UINT onFlags, UINT offFlags)
{
UINT holdFlags = m_flags;
m_flags |= onFlags;
m_flags &= (~offFlags);
CToken* theToken = NULL;
while (theToken == NULL)
{
theToken = FetchToken();
if (theToken == NULL)
{
continue;
}
if (theToken->GetType() == TK_EOF)
{
break;
}
if (m_state != NULL)
{
if (m_state->Skipping())
{
theToken->Delete();
theToken = NULL;
}
}
}
m_flags = holdFlags;
return theToken;
}
void CTokenizer::GetToEndOfFile()
{
m_parsingToEnd = true;
byte theByte;
while(m_parsingToEnd)
{
if (!NextChar(theByte))
{
return;
}
}
}
CToken* CTokenizer::GetToEndOfLine(int tokenType)
{
char theString[MAX_STRING_LENGTH];
theString[0] = ' ';
while (isspace(theString[0]))
{
if (!NextChar((byte&)theString[0]))
{
return NULL;
}
if ((theString[0] == '\n') || (theString[0] == '\r'))
{
PutBackChar(theString[0]);
theString[0] = ' ';
break;
}
}
for (int i = 1; ; i++)
{
char *read;
if (i < MAX_STRING_LENGTH)
read = &theString[i];
else
read = &theString[MAX_STRING_LENGTH-1]; //just use the last char
if (NextChar((byte&)*read))
{
if ((*read != '\n') && (*read != '\r'))
{
continue;
}
PutBackChar(*read);
}
//got to end of line
*read = '\0';
switch(tokenType)
{
case TK_COMMENT:
//
// strip trailing whitespace...
//
while (strlen(theString) && isspace(theString[strlen(theString)-1]))
{
theString[strlen(theString)-1] = 0;
}
if (i >= MAX_STRING_LENGTH)
Error(TKERR_STRINGLENGTHEXCEEDED);
return CCommentToken::Create(theString);
case TK_IDENTIFIER:
default:
if (i >= MAX_STRING_LENGTH)
Error(TKERR_IDENTIFIERLENGTHEXCEEDED);
return CIdentifierToken::Create(theString);
}
}
}
void CTokenizer::SkipToLineEnd()
{
byte theByte;
while(NextChar(theByte))
{
if (theByte == '\n')
{
break;
}
}
}
CToken* CTokenizer::FetchToken()
{
if (m_nextToken != NULL)
{
CToken* curToken = m_nextToken;
m_nextToken = curToken->GetNext();
curToken->SetNext(NULL);
return curToken;
}
byte theByte;
CToken* theToken = NULL;
while (true)
{
if (!NextChar(theByte))
{
if ((m_curParseStream != NULL) && ((TKF_RETURN_EOF & m_flags) != 0))
{
CParseStream* curParseStream = m_curParseStream;
m_curParseStream = curParseStream->GetNext();
curParseStream->Delete();
}
return CToken::Create();
}
if ((theByte == ' ') && (m_flags & TKF_SPACETOKENS))
{
return CSpaceToken::Create(" ");
}
if (theByte <= ' ')
{
if ((theByte == '\n') && ((TKF_USES_EOL & m_flags) != 0))
{
return CUserToken::Create(TK_EOL, "-EOLN-");
}
continue;
}
switch(theByte)
{
case '#':
if ((m_flags & TKF_IGNOREDIRECTIVES) == 0)
{
theToken = HandleDirective();
}
else
{
if ((m_flags & TKF_NODIRECTIVES) != 0)
{
return HandleSymbol('#');
}
SkipToLineEnd();
}
break;
case '/':
theToken = HandleSlash();
break;
case '"':
theToken = HandleString();
break;
case '\'':
theToken = HandleQuote();
break;
default:
if (((theByte >= 'a') && (theByte <= 'z'))
|| ((theByte >= 'A') && (theByte <= 'Z'))
|| ((theByte == '_') && ((m_flags & TKF_NOUNDERSCOREINIDENTIFIER) == 0)))
{
theToken = HandleIdentifier(theByte);
}
else if (((m_flags & TKF_RETURNINTSASIDENTIFIERS) != 0) && (theByte >= '0') && (theByte <= '9'))
{
theToken = HandleIdentifier(theByte);
}
else if (((m_flags & TKF_NUMERICIDENTIFIERSTART) != 0) && (theByte >= '0') && (theByte <= '9'))
{
theToken = HandleIdentifier(theByte);
}
else if (((theByte >= '0') && (theByte <= '9')) || (theByte == '-'))
{
theToken = HandleNumeric(theByte);
}
else if (theByte == '.')
{
theToken = HandleDecimal();
}
else if (theByte <= ' ')
{
break;
}
else
{
theToken = HandleSymbol(theByte);
}
}
if (theToken != NULL)
{
return theToken;
}
}
}
bool CTokenizer::NextChar(byte& theByte)
{
while (m_curParseStream != NULL)
{
if (m_curParseStream->NextChar(theByte))
{
return true;
}
bool endoffile = m_curParseStream->CanEndOfFile();
if (endoffile && ((TKF_RETURN_EOF & m_flags) != 0))
{
return false;
}
CParseStream* curParseStream = m_curParseStream;
m_curParseStream = curParseStream->GetNext();
curParseStream->Delete();
if (m_parsingToEnd && endoffile)
{
break;
}
}
if (m_parsingToEnd)
{
theByte = TK_EOF;
m_parsingToEnd = false;
return true;
}
return false;
}
bool CTokenizer::RequireToken(int tokenType)
{
CToken* theToken = GetToken();
bool retValue = theToken->GetType() == tokenType;
theToken->Delete();
return retValue;
}
void CTokenizer::ScanUntilToken(int tokenType)
{
CToken* curToken;
int tokenValue = TK_UNDEFINED;
while (tokenValue != tokenType)
{
curToken = GetToken();
tokenValue = curToken->GetType();
if (tokenValue == TK_EOF)
{
PutBackToken(curToken);
break;
}
if (tokenValue == tokenType)
{
PutBackToken(curToken);
}
else
{
curToken->Delete();
}
}
}
void CTokenizer::Init(UINT dwFlags)
{
m_symbolLookup = NULL;
m_nextToken = NULL;
m_curParseStream = NULL;
m_keywords = NULL;
m_symbols = NULL;
m_errors = NULL;
m_state = NULL;
m_flags = dwFlags;
m_errorProc = NULL;
m_parsingToEnd = false;
}
void CTokenizer::SetErrorProc(LPTokenizerErrorProc errorProc)
{
m_errorProc = errorProc;
}
void CTokenizer::SetAdditionalErrors(keywordArray_t* theErrors)
{
m_errors = theErrors;
}
keywordArray_t* CTokenizer::SetKeywords(keywordArray_t* theKeywords)
{
keywordArray_t* retval = m_keywords;
m_keywords = theKeywords;
return retval;
}
void CTokenizer::SetSymbols(keywordArray_t* theSymbols)
{
m_symbols = theSymbols;
if (m_symbolLookup != NULL)
{
m_symbolLookup->Delete();
m_symbolLookup = NULL;
}
int i = 0;
if (theSymbols == NULL)
{
return;
}
while(theSymbols[i].m_tokenvalue != TK_EOF)
{
InsertSymbol(theSymbols[i].m_keyword, theSymbols[i].m_tokenvalue);
i++;
}
}
void CTokenizer::InsertSymbol(LPCTSTR theSymbol, int theValue)
{
CSymbolLookup** curHead = &m_symbolLookup;
CSymbolLookup* curParent = NULL;
CSymbolLookup* curLookup = NULL;
for (UINT i = 0; i < strlen(theSymbol); i++)
{
bool found = false;
curLookup = *curHead;
while (curLookup != NULL)
{
if (curLookup->GetByte() == theSymbol[i])
{
found = true;
break;
}
curLookup = curLookup->GetNext();
}
if (!found)
{
curLookup = CSymbolLookup::Create(theSymbol[i]);
curLookup->SetParent(curParent);
curLookup->SetNext(*curHead);
*curHead = curLookup;
}
curHead = curLookup->GetChildAddress();
curParent = curLookup;
}
if (curLookup->GetValue() != -1)
{
Error(TKERR_DUPLICATESYMBOL);
}
curLookup->SetValue(theValue);
}
CToken* CTokenizer::HandleString()
{
char theString[MAX_STRING_LENGTH];
for (int i = 0; i < MAX_STRING_LENGTH; i++)
{
if (!NextChar((byte&)theString[i]))
{
return NULL;
}
if (theString[i] == '"')
{
theString[i] = '\0';
return CStringToken::Create(theString);
}
if (theString[i] == '\\')
{
theString[i] = Escapement();
}
}
Error(TKERR_STRINGLENGTHEXCEEDED);
return NULL;
}
void CTokenizer::GetCurFilename(char** filename)
{
if (m_curParseStream == NULL)
{
*filename = (char*)malloc(1);
*filename[0] = '\0';
return;
}
m_curParseStream->GetCurFilename(filename);
}
int CTokenizer::GetCurLine()
{
if (m_curParseStream == NULL)
{
return 0;
}
return m_curParseStream->GetCurLine();
}
void CTokenizer::PutBackChar(byte theByte)
{
CParseStream* newStream = CParsePutBack::Create(theByte, m_curParseStream);
newStream->SetNext(m_curParseStream);
m_curParseStream = newStream;
}
byte CTokenizer::Escapement()
{
byte theByte;
if (NextChar(theByte))
{
if (m_flags & TKF_NO_ESC_XLAT)
{
PutBackChar(theByte);
}
else
{
switch(theByte)
{
case 'n':
return '\n';
case '\\':
return '\\';
case '\'':
return '\'';
case '?':
return '\?';
case 'a':
return '\a';
case 'b':
return '\b';
case 'f':
return '\f';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case '0':
return '\0';
// support for octal or hex sequences?? \000 or \xhhh
default:
PutBackChar(theByte);
}
}
}
return '\\';
}
bool CTokenizer::AddDefineSymbol(CDirectiveSymbol* definesymbol)
{
CParseStream* curStream = m_curParseStream;
while(curStream != NULL)
{
if (curStream->IsThisDefinition(definesymbol))
{
return false;
}
curStream = curStream->GetNext();
}
CParseStream* newStream = CParseDefine::Create(definesymbol);
newStream->SetNext(m_curParseStream);
m_curParseStream = newStream;
return true;
}
CToken* CTokenizer::TokenFromName(LPCTSTR name)
{
CDirectiveSymbol* defineSymbol = (CDirectiveSymbol*)m_defines.FindSymbol(name);
if (defineSymbol != NULL)
{
if (AddDefineSymbol(defineSymbol))
{
return FetchToken();
}
}
if ((m_keywords != NULL) && ((m_flags & TKF_IGNOREKEYWORDS) == 0))
{
int i = 0;
if ((m_flags & TKF_NOCASEKEYWORDS) == 0)
{
while (m_keywords[i].m_tokenvalue != TK_EOF)
{
if (strcmp(m_keywords[i].m_keyword, name) == 0)
{
return CUserToken::Create(m_keywords[i].m_tokenvalue, name);
}
i++;
}
}
else
{
while (m_keywords[i].m_tokenvalue != TK_EOF)
{
if (stricmp(m_keywords[i].m_keyword, name) == 0)
{
return CUserToken::Create(m_keywords[i].m_tokenvalue, name);
}
i++;
}
}
}
return CIdentifierToken::Create(name);
}
int CTokenizer::DirectiveFromName(LPCTSTR name)
{
if (directiveKeywords != NULL)
{
int i = 0;
while (directiveKeywords[i].m_tokenvalue != TK_EOF)
{
if (strcmp(directiveKeywords[i].m_keyword, name) == 0)
{
return directiveKeywords[i].m_tokenvalue;
}
i++;
}
}
return -1;
}
CToken* CTokenizer::HandleIdentifier(byte theByte)
{
char theString[MAX_IDENTIFIER_LENGTH];
theString[0] = theByte;
bool numeric = (theByte >= '0') && (theByte <= '9');
for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++)
{
if (NextChar((byte&)theString[i]))
{
if (((theString[i] != '_') || ((m_flags & TKF_NOUNDERSCOREINIDENTIFIER) == 0)) &&
((theString[i] != '-') || ((m_flags & TKF_NODASHINIDENTIFIER) == 0)))
{
if ((theString[i] >= '0') && (theString[i] <= '9'))
{
continue;
}
else
if (((theString[i] >= 'A') && (theString[i] <= 'Z'))
|| ((theString[i] >= 'a') && (theString[i] <= 'z'))
|| (theString[i] == '_') || (theString[i] == '-'))
{
numeric = false;
continue;
}
}
if ((numeric) && ((m_flags & TKF_RETURNINTSASIDENTIFIERS) == 0))
{
theByte = theString[i];
theString[i] = '\0';
if (theByte == '.')
{
long value = atoi(theString);
return HandleFloat(false, value);
}
PutBackChar(theByte);
i--;
theByte = theString[i];
theString[i] = '\0';
long value = atoi(theString);
return HandleNumeric(theByte, value);
}
PutBackChar(theString[i]);
}
theString[i] = '\0';
return TokenFromName(theString);
}
Error(TKERR_IDENTIFIERLENGTHEXCEEDED);
return NULL;
}
CToken* CTokenizer::HandleSlash()
{
byte theByte;
if (!NextChar(theByte))
{
return NULL;
}
if (theByte == '/')
{
if (m_flags & (TKF_COMMENTTOKENS|TKF_COMMENTTOKENSSLASHSLASHONLY))
{
return GetToEndOfLine(TK_COMMENT);
}
SkipToLineEnd();
return NULL;
}
if (theByte == '*')
{
if ( (m_flags & (TKF_COMMENTTOKENS|TKF_COMMENTTOKENSSLASHSLASHONLY)) == TKF_COMMENTTOKENS )
{
char theString[MAX_IDENTIFIER_LENGTH + 1];
memset(theString,0,sizeof(theString)); // needed later
theString[0] = ' ';
while (isspace(theString[0]))
{
if (!NextChar((byte&)theString[0]))
{
return NULL;
}
}
for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++)
{
if (NextChar((byte&)theString[i]))
{
if (theString[i] != '*')
{
continue;
}
i++;
if (NextChar((byte&)theString[i]))
{
if (theString[i] == '/')
{
i--;
theString[i] = '\0';
//
// strip trailing whitespace...
//
while (strlen(theString) && isspace(theString[strlen(theString)-1]))
{
theString[strlen(theString)-1] = 0;
}
return CCommentToken::Create(theString);
}
}
}
}
Error(TKERR_IDENTIFIERLENGTHEXCEEDED);
//
// we should actually keep reading until we've finished scanning the /**/ comment completely, even though
// we're not returning it, or we end up returning stuff inside this comment as individual tokens later on
//
while (NextChar(theByte))
{
// note slightly awkward check to see if the leading star was the last char read above (unlikely but possible)
//
if (theByte != '*' && theString[MAX_IDENTIFIER_LENGTH-1]!= '*')
{
theString[MAX_IDENTIFIER_LENGTH-1]=0;
continue;
}
if (NextChar(theByte))
{
if (theByte == '/')
{
break;
}
}
else
{
break;
}
}
return NULL;
}
while(NextChar(theByte))
{
while(theByte == '*')
{
if (!NextChar(theByte))
{
break;
}
if (theByte == '/')
{
return NULL;
}
}
}
return NULL;
}
PutBackChar(theByte);
return HandleSymbol('/');
}
CToken* CTokenizer::HandleNumeric(byte theByte, long value)
{
bool thesign = theByte == '-';
if (thesign)
{
if (!NextChar(theByte))
{
return HandleSymbol('-');
}
if (theByte == '.')
{
return HandleDecimal(thesign);
}
if ((theByte < '0') || (theByte > '9'))
{
PutBackChar(theByte);
return HandleSymbol('-');
}
}
if (theByte == 'O')
{
return HandleOctal(thesign);
}
bool digithit = (value != 0);
if ((theByte == '0') && (value == 0))
{
digithit = true;
if (!NextChar(theByte))
{
return CIntToken::Create(0);
}
if ((theByte == 'x') || (theByte == 'X'))
{
return HandleHex(thesign);
}
}
while((theByte >= '0') && (theByte <= '9'))
{
value = (value * 10) + (theByte - '0');
if (!NextChar(theByte))
{
if (thesign)
{
value = -value;
}
return CIntToken::Create(value);
}
digithit = true;
}
if (theByte == '.')
{
if (digithit)
{
return HandleFloat(thesign, value);
}
if (thesign)
{
PutBackChar(theByte);
theByte = '-';
}
return HandleSymbol(theByte);
}
PutBackChar(theByte);
if (thesign)
{
value = -value;
}
return CIntToken::Create(value);
}
CToken* CTokenizer::HandleOctal(bool thesign)
{
byte theByte;
int value = 0;
if (!NextChar(theByte))
{
return CIntToken::Create(value);
}
while(true)
{
if((theByte >= '0') && (theByte <='7'))
{
value = (value * 8) + (theByte - '0');
}
else
{
PutBackChar(theByte);
if (thesign)
{
value = -value;
}
return CIntToken::Create(value);
}
if (!NextChar(theByte))
{
if (thesign)
{
value = -value;
}
return CIntToken::Create(value);
}
}
}
CToken* CTokenizer::HandleHex(bool thesign)
{
int value = 0;
while (true)
{
byte theByte;
if (!NextChar(theByte))
{
if (thesign)
{
value = -value;
}
return CIntToken::Create(value);
}
switch (theByte)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
theByte = theByte - '0';
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
theByte = theByte - 'A' + 10;
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
theByte = theByte - 'a' + 10;
break;
default:
PutBackChar(theByte);
if (thesign)
{
value = -value;
}
return CIntToken::Create(value);
}
value = (value * 16) + theByte;
}
}
CToken* CTokenizer::HandleDecimal(bool thesign)
{
byte theByte;
if (!NextChar(theByte))
{
if (thesign)
{
PutBackChar('.');
return HandleSymbol('-');
}
HandleSymbol('.');
}
PutBackChar(theByte);
if ((theByte <= '9') && (theByte >= '0'))
{
return HandleFloat(thesign);
}
if (thesign)
{
PutBackChar('.');
theByte = '-';
}
else
{
theByte = '.';
}
return HandleSymbol(theByte);
}
CToken* CTokenizer::HandleFloat(bool thesign, long value)
{
float lower = 1.0;
float newValue = (float)value;
byte theByte;
while(NextChar(theByte))
{
if ((theByte >= '0') && (theByte <= '9'))
{
lower = lower / 10;
newValue = newValue + ((theByte - '0') * lower);
continue;
}
PutBackChar(theByte);
break;
}
if (thesign)
{
newValue = -newValue;
}
return CFloatToken::Create(newValue);
}
CToken* CTokenizer::HandleQuote()
{
byte theByte;
if (!NextChar(theByte))
{
Error(TKERR_EXPECTED_CHAR);
return NULL;
}
if (theByte == '\\')
{
theByte = Escapement();
}
byte dummy;
if (!NextChar(dummy))
{
Error(TKERR_EXPECTED_CHAR);
return NULL;
}
if (dummy != '\'')
{
PutBackChar(dummy);
PutBackChar(theByte);
Error(TKERR_EXPECTED_CHAR);
return NULL;
}
return CCharToken::Create(theByte);
}
void CTokenizer::SetFlags(UINT flags)
{
m_flags = flags;
}
UINT CTokenizer::GetFlags()
{
return m_flags;
}
CToken* CTokenizer::HandleSymbol(byte theByte)
{
char symbolString[128];
int curStrLen = 0;
symbolString[0] = '\0';
bool consumed = false;
CSymbolLookup* curLookup;
if ((m_flags & TKF_RAWSYMBOLSONLY) == 0)
{
curLookup = m_symbolLookup;
}
else
{
curLookup = NULL;
}
CSymbolLookup* lastLookup = NULL;
while(curLookup != NULL)
{
if (curLookup->GetByte() == theByte)
{
symbolString[curStrLen++] = theByte;
symbolString[curStrLen] = '\0';
lastLookup = curLookup;
consumed = true;
if (curLookup->GetChild() == NULL)
{
break;
}
if (!NextChar(theByte))
{
PutBackToken(CToken::Create());
break;
}
consumed = false;
curLookup = curLookup->GetChild();
continue;
}
curLookup = curLookup->GetNext();
}
if ((!consumed) && (lastLookup != NULL))
{
PutBackChar(theByte);
}
while ((lastLookup != NULL) && (lastLookup->GetValue() == -1))
{
curStrLen--;
symbolString[curStrLen] = '\0';
// symbolString = symbolString.Left(symbolString.GetLength() - 1);
if (lastLookup->GetParent() == NULL)
{
if ((m_flags & TKF_WANTUNDEFINED) == 0)
{
Error(TKERR_UNRECOGNIZEDSYMBOL);
}
}
else
{
PutBackChar(lastLookup->GetByte());
}
lastLookup = lastLookup->GetParent();
}
if (lastLookup == NULL)
{
if ((m_flags & TKF_WANTUNDEFINED) == 0)
{
return NULL;
}
curStrLen = 0;
symbolString[curStrLen++] = char(theByte);
symbolString[curStrLen] = '\0';
if ((m_flags & TKF_WIDEUNDEFINEDSYMBOLS) != 0)
{
while (true)
{
if (!NextChar(theByte))
{
PutBackToken(CToken::Create());
break;
}
if (theByte == ' ')
{
break;
}
if (((theByte >= 'a') && (theByte <= 'z')) || ((theByte >= 'A') && (theByte <= 'Z')) ||
((theByte >= '0') && (theByte <= '9')))
{
PutBackChar(theByte);
break;
}
if (theByte < ' ')
{
if ((theByte == '\n') && ((TKF_USES_EOL & m_flags) != 0))
{
PutBackToken(CUserToken::Create(TK_EOL, "-EOLN-"));
break;
}
continue;
}
symbolString[curStrLen++] = theByte;
symbolString[curStrLen] = '\0';
}
}
return CUndefinedToken::Create(symbolString);
}
return CUserToken::Create(lastLookup->GetValue(), symbolString);
}
CToken* CTokenizer::HandleDirective()
{
int tokenValue = 0;
CToken* theToken = FetchToken();
if (theToken->GetType() == TK_EOF)
{
return theToken;
}
if (theToken->GetType() != TK_IDENTIFIER)
{
Error(TKERR_INVALID_DIRECTIVE);
theToken->Delete();
SkipToLineEnd();
return NULL;
}
CDirectiveSymbol* curSymbol;
CTokenizerState* state;
int theDirective = DirectiveFromName(theToken->GetStringValue());
theToken->Delete();
byte theByte;
switch(theDirective)
{
case DIR_INCLUDE:
if ((m_state != NULL) && (m_state->Skipping()))
{
break;
}
theToken = GetToken();
if (theToken->GetType() != TK_STRING)
{
Error(TKERR_INCLUDE_FILE_NOTFOUND);
theToken->Delete();
SkipToLineEnd();
break;
}
AddParseFile(theToken->GetStringValue());
theToken->Delete();
break;
case DIR_IFDEF:
if ((m_state != NULL) && (m_state->Skipping()))
{
state = CTokenizerHolderState::Create();
state->SetNext(m_state);
m_state = state;
break;
}
theToken = GetToken();
if (theToken->GetType() != TK_IDENTIFIER)
{
Error(TKERR_EXPECTED_IDENTIFIER);
theToken->Delete();
SkipToLineEnd();
break;
}
state = CTokenizerState::Create(m_defines.FindSymbol(theToken->GetStringValue()) == NULL);
theToken->Delete();
state->SetNext(m_state);
m_state = state;
break;
case DIR_IFNDEF:
if ((m_state != NULL) && (m_state->Skipping()))
{
state = CTokenizerHolderState::Create();
state->SetNext(m_state);
m_state = state;
break;
}
theToken = GetToken();
if (theToken->GetType() != TK_IDENTIFIER)
{
Error(TKERR_EXPECTED_IDENTIFIER);
theToken->Delete();
SkipToLineEnd();
break;
}
state = CTokenizerState::Create(m_defines.FindSymbol(theToken->GetStringValue()) != NULL);
theToken->Delete();
state->SetNext(m_state);
m_state = state;
break;
case DIR_ENDIF:
if (m_state == NULL)
{
Error(TKERR_UNMATCHED_DIRECTIVE);
break;
}
state = m_state;
m_state = state->GetNext();
state->Delete();
break;
case DIR_ELSE:
if (m_state == NULL)
{
Error(TKERR_UNMATCHED_DIRECTIVE);
break;
}
if (!m_state->ProcessElse())
{
Error(TKERR_UNMATCHED_DIRECTIVE);
break;
}
break;
case DIR_DEFINE:
if ((m_state != NULL) && (m_state->Skipping()))
{
break;
}
theToken = GetToken();
if (theToken->GetType() != TK_IDENTIFIER)
{
Error(TKERR_EXPECTED_IDENTIFIER);
theToken->Delete();
SkipToLineEnd();
break;
}
// blind add - should check first for value changes
{
curSymbol = CDirectiveSymbol::Create(theToken->GetStringValue());
char temp[128];
int tempsize = 0;
while(NextChar(theByte))
{
if (theByte == '\n')
{
break;
}
temp[tempsize++] = char(theByte);
}
temp[tempsize] = '\0';
curSymbol->SetValue(temp);
if (!m_defines.AddSymbol(curSymbol))
{
curSymbol->Delete();
}
}
theToken->Delete();
break;
case DIR_UNDEFINE:
if ((m_state != NULL) && (m_state->Skipping()))
{
break;
}
theToken = GetToken();
if (theToken->GetType() != TK_IDENTIFIER)
{
Error(TKERR_EXPECTED_IDENTIFIER);
theToken->Delete();
SkipToLineEnd();
break;
}
m_defines.RemoveSymbol(theToken->GetStringValue());
theToken->Delete();
break;
default:
Error(TKERR_INVALID_DIRECTIVE);
SkipToLineEnd();
break;
}
return NULL;
}
COLORREF CTokenizer::ParseRGB()
{
CToken* theToken = GetToken();
if (theToken->GetType() != TK_INT)
{
Error(TKERR_EXPECTED_INTEGER);
theToken->Delete();
return RGB(0, 0, 0);
}
int red = theToken->GetIntValue();
theToken->Delete();
theToken = GetToken();
if (theToken->GetType() != TK_INT)
{
Error(TKERR_EXPECTED_INTEGER);
theToken->Delete();
return RGB(0, 0, 0);
}
int green = theToken->GetIntValue();
theToken->Delete();
theToken = GetToken();
if (theToken->GetType() != TK_INT)
{
Error(TKERR_EXPECTED_INTEGER);
theToken->Delete();
return RGB(0, 0, 0);
}
int blue = theToken->GetIntValue();
theToken->Delete();
return RGB(red, green, blue);
}
//
// CSymbolLookup
//
CSymbolLookup::CSymbolLookup()
{
}
CSymbolLookup::~CSymbolLookup()
{
}
CSymbolLookup* CSymbolLookup::Create(byte theByte)
{
CSymbolLookup* curLookup = new CSymbolLookup();
curLookup->Init(theByte);
return curLookup;
}
void CSymbolLookup::Delete()
{
if (m_sibling != NULL)
{
m_sibling->Delete();
m_sibling = NULL;
}
if (m_child != NULL)
{
m_child->Delete();
m_child = NULL;
}
delete this;
}
void CSymbolLookup::Init(byte theByte)
{
m_parent = NULL;
m_child = NULL;
m_sibling = NULL;
m_value = -1;
m_byte = theByte;
}
CSymbolLookup* CSymbolLookup::GetNext()
{
return m_sibling;
}
void CSymbolLookup::SetNext(CSymbolLookup* next)
{
m_sibling = next;
}
void CSymbolLookup::SetParent(CSymbolLookup* parent)
{
m_parent = parent;
}
void CSymbolLookup::SetValue(int value)
{
m_value = value;
}
int CSymbolLookup::GetValue()
{
return m_value;
}
byte CSymbolLookup::GetByte()
{
return m_byte;
}
CSymbolLookup** CSymbolLookup::GetChildAddress()
{
return &m_child;
}
CSymbolLookup* CSymbolLookup::GetChild()
{
return m_child;
}
CSymbolLookup* CSymbolLookup::GetParent()
{
return m_parent;
}
void CToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = cur->GetNext();
delete(cur);
}
}
CToken* CToken::m_avail = NULL;
void CToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CCharToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CCharToken*)cur->GetNext();
delete(cur);
}
}
CCharToken* CCharToken::m_avail = NULL;
void CCharToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CIntToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CIntToken*)cur->GetNext();
delete(cur);
}
}
CIntToken* CIntToken::m_avail = NULL;
void CIntToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CFloatToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CFloatToken*)cur->GetNext();
delete(cur);
}
}
CFloatToken* CFloatToken::m_avail = NULL;
void CFloatToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CStringToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CStringToken*)cur->GetNext();
delete(cur);
}
}
CStringToken* CStringToken::m_avail = NULL;
void CStringToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CSpaceToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CSpaceToken*)cur->GetNext();
delete(cur);
}
}
CSpaceToken* CSpaceToken::m_avail = NULL;
void CSpaceToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CUndefinedToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CUndefinedToken*)cur->GetNext();
delete(cur);
}
}
CUndefinedToken* CUndefinedToken::m_avail = NULL;
void CUndefinedToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CUserToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CUserToken*)cur->GetNext();
delete(cur);
}
}
CUserToken* CUserToken::m_avail = NULL;
void CUserToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CIdentifierToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CIdentifierToken*)cur->GetNext();
delete(cur);
}
}
CIdentifierToken* CIdentifierToken::m_avail = NULL;
void CIdentifierToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}
void CCommentToken::DeleteAll()
{
while(m_avail != NULL)
{
CToken* cur = m_avail;
m_avail = (CCommentToken*)cur->GetNext();
delete(cur);
}
}
CCommentToken* CCommentToken::m_avail = NULL;
void CCommentToken::MakeAvail()
{
SetNext(m_avail);
m_avail = this;
}