Some random CBotProgram and CBotToken refactoring

dev-time-step
krzys-h 2015-12-23 15:36:55 +01:00
parent 9b4a6e0131
commit fbdc071659
14 changed files with 282 additions and 438 deletions

View File

@ -623,7 +623,7 @@ int CBotFunction::DoCall(long& nIdent, const std::string& name, CBotVar** ppVars
{
if ( !pt->m_MasterClass.empty() )
{
CBotVar* pInstance = m_pProg->m_pInstance;
CBotVar* pInstance = m_pProg->m_thisVar;
// make "this" known
CBotVar* pThis ;
if ( pInstance == nullptr )
@ -702,7 +702,7 @@ void CBotFunction::RestoreCall(long& nIdent, const std::string& name, CBotVar**
{
if ( !pt->m_MasterClass.empty() )
{
// CBotVar* pInstance = m_pProg->m_pInstance;
// CBotVar* pInstance = m_pProg->m_thisVar;
// make "this" known
CBotVar* pThis = pStk1->FindVar("this");
pThis->SetInit(CBotVar::InitType::IS_POINTER);

View File

@ -1,108 +0,0 @@
#include "CBot/CBotKeywordStrings.h"
#include <map>
//! \brief Keeps the string corresponding to keyword ID
// Map is filled with id-string pars that are needed for CBot language parsing
static const std::map<TokenId, const std::string> s_keywordString = {
{ID_IF, "if"},
{ID_ELSE, "else"},
{ID_WHILE, "while"},
{ID_DO, "do"},
{ID_FOR, "for"},
{ID_BREAK, "break"},
{ID_CONTINUE, "continue"},
{ID_SWITCH, "switch"},
{ID_CASE, "case"},
{ID_DEFAULT, "default"},
{ID_TRY, "try"},
{ID_THROW, "throw"},
{ID_CATCH, "catch"},
{ID_FINALLY, "finally"},
{ID_TXT_AND, "and"},
{ID_TXT_OR, "or"},
{ID_TXT_NOT, "not"},
{ID_RETURN, "return"},
{ID_CLASS, "class"},
{ID_EXTENDS, "extends"},
{ID_SYNCHO, "synchronized"},
{ID_NEW, "new"},
{ID_PUBLIC, "public"},
{ID_EXTERN, "extern"},
{ID_STATIC, "static"},
{ID_PROTECTED, "protected"},
{ID_PRIVATE, "private"},
{ID_INT, "int"},
{ID_FLOAT, "float"},
{ID_BOOLEAN, "boolean"},
{ID_STRING, "string"},
{ID_VOID, "void"},
{ID_BOOL, "bool"},
{ID_TRUE, "true"},
{ID_FALSE, "false"},
{ID_NULL, "null"},
{ID_NAN, "nan"},
{ID_OPENPAR, "("},
{ID_CLOSEPAR, ")"},
{ID_OPBLK, "{"},
{ID_CLBLK, "}"},
{ID_SEP, ";"},
{ID_COMMA, ","},
{ID_DOTS, ":"},
{ID_DOT, "."},
{ID_OPBRK, "["},
{ID_CLBRK, "]"},
{ID_DBLDOTS, "::"},
{ID_LOGIC, "?"},
{ID_ADD, "+"},
{ID_SUB, "-"},
{ID_MUL, "*"},
{ID_DIV, "/"},
{ID_ASS, "="},
{ID_ASSADD, "+="},
{ID_ASSSUB, "-="},
{ID_ASSMUL, "*="},
{ID_ASSDIV, "/="},
{ID_ASSOR, "|="},
{ID_ASSAND, "&="},
{ID_ASSXOR, "^="},
{ID_ASSSL, "<<="},
{ID_ASSSR, ">>>="},
{ID_ASSASR, ">>="},
{ID_SL, "<<"},
{ID_SR, ">>"},
{ID_ASR, ">>"},
{ID_INC, "++"},
{ID_DEC, "--"},
{ID_LO, "<"},
{ID_HI, ">"},
{ID_LS, "<="},
{ID_HS, ">="},
{ID_EQ, "=="},
{ID_NE, "!="},
{ID_AND, "&"},
{ID_XOR, "^"},
{ID_OR, "|"},
{ID_LOG_AND, "&&"},
{ID_LOG_OR, "||"},
{ID_LOG_NOT, "!"},
{ID_NOT, "~"},
{ID_MODULO, "%"},
{ID_POWER, "**"},
{ID_ASSMODULO, "%="},
{TX_UNDEF, "undefined"},
{TX_NAN, "not a number"}
};
static const std::string emptyString = "";
const std::string& LoadString(TokenId id)
{
if (s_keywordString.find(id) != s_keywordString.end())
{
return s_keywordString.at(id);
}
else
{
return emptyString;
}
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "CBotEnums.h"
#include <string>
/**
* \brief LoadString Maps given ID to its string equivalent.
* \param id Provided identifier.
* \return String if found, else NullString.
*/
const std::string& LoadString(TokenId id);

View File

@ -17,7 +17,6 @@
* along with this program. If not, see http://gnu.org/licenses
*/
// Modules inlcude
#include "CBot/CBotVar/CBotVar.h"
#include "CBot/CBotCall.h"
@ -29,51 +28,26 @@
#include "CBot/CBotInstr/CBotFunction.h"
#include "CBotKeywordStrings.h"
#include "CBot/stdlib/stdlib.h"
// Local include
// Global include
#include <stdio.h>
////////////////////////////////////////////////////////////////////////////////
CBotProgram::CBotProgram()
{
m_Prog = nullptr;
m_pRun = nullptr;
m_pClass = nullptr;
m_pStack = nullptr;
m_pInstance = nullptr;
m_ErrorCode = CBotNoErr;
m_Ident = 0;
}
////////////////////////////////////////////////////////////////////////////////
CBotProgram::CBotProgram(CBotVar* pInstance)
CBotProgram::CBotProgram(CBotVar* thisVar)
: m_thisVar(thisVar)
{
m_Prog = nullptr;
m_pRun = nullptr;
m_pClass = nullptr;
m_pStack = nullptr;
m_pInstance = pInstance;
m_ErrorCode = CBotNoErr;
m_Ident = 0;
}
////////////////////////////////////////////////////////////////////////////////
CBotProgram::~CBotProgram()
{
// delete m_pClass;
m_pClass->Purge();
m_pClass = nullptr;
// delete m_classes;
m_classes->Purge();
m_classes = nullptr;
CBotClass::FreeLock(this);
delete m_Prog;
delete m_functions;
#if STACKMEM
m_pStack->Delete();
#else
@ -81,33 +55,31 @@ CBotProgram::~CBotProgram()
#endif
}
////////////////////////////////////////////////////////////////////////////////
bool CBotProgram::Compile(const std::string& program, std::vector<std::string>& functions, void* pUser)
{
int error = 0;
// Cleanup the previously compiled program
Stop();
// delete m_pClass;
m_pClass->Purge(); // purge the old definitions of classes
// delete m_classes;
m_classes->Purge(); // purge the old definitions of classes
// but without destroying the object
m_pClass = nullptr;
delete m_Prog; m_Prog= nullptr;
m_classes = nullptr;
delete m_functions; m_functions = nullptr;
functions.clear();
m_ErrorCode = CBotNoErr;
m_error = CBotNoErr;
// transforms the program in Tokens
CBotToken* pBaseToken = CBotToken::CompileTokens(program, error);
// Step 1. Process the code into tokens
CBotToken* pBaseToken = CBotToken::CompileTokens(program);
if ( pBaseToken == nullptr ) return false;
CBotCStack* pStack = new CBotCStack(nullptr);
CBotToken* p = pBaseToken->GetNext(); // skips the first token (separator)
pStack->SetBotCall(this); // defined used routines
CBotCall::SetPUser(pUser);
// first made a quick pass just to take the headers of routines and classes
// Step 2. Find all function and class definitions
while ( pStack->IsOk() && p != nullptr && p->GetType() != 0)
{
if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking
@ -116,27 +88,28 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
( p->GetType() == ID_PUBLIC && p->GetNext()->GetType() == ID_CLASS ))
{
CBotClass* nxt = CBotClass::Compile1(p, pStack);
if (m_pClass == nullptr ) m_pClass = nxt;
else m_pClass->AddNext(nxt);
if (m_classes == nullptr ) m_classes = nxt;
else m_classes->AddNext(nxt);
}
else
{
CBotFunction* next = CBotFunction::Compile1(p, pStack, nullptr);
if (m_Prog == nullptr ) m_Prog = next;
else m_Prog->AddNext(next);
if (m_functions == nullptr ) m_functions = next;
else m_functions->AddNext(next);
}
}
if ( !pStack->IsOk() )
{
m_ErrorCode = pStack->GetError(m_ErrorStart, m_ErrorEnd);
delete m_Prog;
m_Prog = nullptr;
m_error = pStack->GetError(m_errorStart, m_errorEnd);
delete m_functions;
m_functions = nullptr;
delete pBaseToken;
return false;
}
// Step 3. Real compilation
// CBotFunction* temp = nullptr;
CBotFunction* next = m_Prog; // rewind the list
CBotFunction* next = m_functions; // rewind the list
p = pBaseToken->GetNext(); // returns to the beginning
@ -165,15 +138,15 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
if ( !pStack->IsOk() )
{
m_ErrorCode = pStack->GetError(m_ErrorStart, m_ErrorEnd);
delete m_Prog;
m_Prog = nullptr;
m_error = pStack->GetError(m_errorStart, m_errorEnd);
delete m_functions;
m_functions = nullptr;
}
delete pBaseToken;
delete pStack;
return (m_Prog != nullptr);
return (m_functions != nullptr);
}
////////////////////////////////////////////////////////////////////////////////
@ -186,16 +159,16 @@ bool CBotProgram::Start(const std::string& name)
#endif
m_pStack = nullptr;
m_pRun = m_Prog;
while (m_pRun != nullptr)
m_entryPoint = m_functions;
while (m_entryPoint != nullptr)
{
if ( m_pRun->GetName() == name ) break;
m_pRun = m_pRun->m_next;
if (m_entryPoint->GetName() == name ) break;
m_entryPoint = m_entryPoint->m_next;
}
if ( m_pRun == nullptr )
if (m_entryPoint == nullptr )
{
m_ErrorCode = CBotErrNoRun;
m_error = CBotErrNoRun;
return false;
}
@ -213,7 +186,7 @@ bool CBotProgram::Start(const std::string& name)
////////////////////////////////////////////////////////////////////////////////
bool CBotProgram::GetPosition(const std::string& name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
{
CBotFunction* p = m_Prog;
CBotFunction* p = m_functions;
while (p != nullptr)
{
if ( p->GetName() == name ) break;
@ -231,9 +204,9 @@ bool CBotProgram::Run(void* pUser, int timer)
{
bool ok;
if (m_pStack == nullptr || m_pRun == nullptr) goto error;
if (m_pStack == nullptr || m_entryPoint == nullptr) goto error;
m_ErrorCode = CBotNoErr;
m_error = CBotNoErr;
m_pStack->Reset(pUser); // empty the possible previous error, and resets the timer
if ( timer >= 0 ) m_pStack->SetTimer(timer);
@ -246,16 +219,16 @@ bool CBotProgram::Run(void* pUser, int timer)
if ( ok )
{
// returns to normal execution
ok = m_pRun->Execute(nullptr, m_pStack, m_pInstance);
ok = m_entryPoint->Execute(nullptr, m_pStack, m_thisVar);
}
#else
ok = m_pRun->Execute(nullptr, m_pStack, m_pInstance);
ok = m_pRun->Execute(nullptr, m_pStack, m_thisVar);
#endif
// completed on a mistake?
if (!ok && !m_pStack->IsOk())
{
m_ErrorCode = m_pStack->GetError(m_ErrorStart, m_ErrorEnd);
m_error = m_pStack->GetError(m_errorStart, m_errorEnd);
#if STACKMEM
m_pStack->Delete();
#else
@ -265,11 +238,11 @@ bool CBotProgram::Run(void* pUser, int timer)
return true; // execution is finished!
}
if ( ok ) m_pRun = nullptr; // more function in execution
if ( ok ) m_entryPoint = nullptr; // more function in execution
return ok;
error:
m_ErrorCode = CBotErrNoRun;
m_error = CBotErrNoRun;
return true;
}
@ -282,7 +255,7 @@ void CBotProgram::Stop()
delete m_pStack;
#endif
m_pStack = nullptr;
m_pRun = nullptr;
m_entryPoint = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
@ -314,36 +287,24 @@ void CBotProgram::SetTimer(int n)
////////////////////////////////////////////////////////////////////////////////
CBotError CBotProgram::GetError()
{
return m_ErrorCode;
}
////////////////////////////////////////////////////////////////////////////////
void CBotProgram::SetIdent(long n)
{
m_Ident = n;
}
////////////////////////////////////////////////////////////////////////////////
long CBotProgram::GetIdent()
{
return m_Ident;
return m_error;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotProgram::GetError(CBotError& code, int& start, int& end)
{
code = m_ErrorCode;
start = m_ErrorStart;
end = m_ErrorEnd;
code = m_error;
start = m_errorStart;
end = m_errorEnd;
return code > 0;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotProgram::GetError(CBotError& code, int& start, int& end, CBotProgram*& pProg)
{
code = m_ErrorCode;
start = m_ErrorStart;
end = m_ErrorEnd;
code = m_error;
start = m_errorStart;
end = m_errorEnd;
pProg = this;
return code > 0;
}
@ -351,7 +312,7 @@ bool CBotProgram::GetError(CBotError& code, int& start, int& end, CBotProgram*&
////////////////////////////////////////////////////////////////////////////////
CBotFunction* CBotProgram::GetFunctions()
{
return m_Prog;
return m_functions;
}
////////////////////////////////////////////////////////////////////////////////
@ -393,7 +354,8 @@ CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
////////////////////////////////////////////////////////////////////////////////
bool CBotProgram::DefineNum(const std::string& name, long val)
{
return CBotToken::DefineNum(name, val);
CBotToken::DefineNum(name, val);
return true;
}
////////////////////////////////////////////////////////////////////////////////
@ -405,7 +367,7 @@ bool CBotProgram::SaveState(FILE* pf)
if ( m_pStack != nullptr )
{
if (!WriteWord( pf, 1)) return false;
if (!WriteString( pf, m_pRun->GetName() )) return false;
if (!WriteString( pf, m_entryPoint->GetName() )) return false;
if (!m_pStack->SaveState(pf)) return false;
}
else
@ -445,7 +407,7 @@ bool CBotProgram::RestoreState(FILE* pf)
m_pStack->SetBotCall(this); // bases for routines
// restored some states in the stack according to the structure
m_pRun->RestoreState(nullptr, m_pStack, m_pInstance);
m_entryPoint->RestoreState(nullptr, m_pStack, m_thisVar);
return true;
}
@ -458,18 +420,18 @@ int CBotProgram::GetVersion()
////////////////////////////////////////////////////////////////////////////////
void CBotProgram::Init()
{
CBotToken::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero
CBotToken::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable
CBotToken::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value
CBotToken::DefineNum("CBotErrNoRetVal", CBotErrNoRetVal); // function did not return results
CBotToken::DefineNum("CBotErrNoRun", CBotErrNoRun); // active Run () without a function // TODO: Is this actually a runtime error?
CBotToken::DefineNum("CBotErrUndefFunc", CBotErrUndefFunc); // Calling a function that no longer exists
CBotToken::DefineNum("CBotErrNotClass", CBotErrNotClass); // Class no longer exists
CBotToken::DefineNum("CBotErrNull", CBotErrNull); // Attempted to use a null pointer
CBotToken::DefineNum("CBotErrNan", CBotErrNan); // Can't do operations on nan
CBotToken::DefineNum("CBotErrOutArray", CBotErrOutArray); // Attempted access out of bounds of an array
CBotToken::DefineNum("CBotErrStackOver", CBotErrStackOver); // Stack overflow
CBotToken::DefineNum("CBotErrDeletedPtr", CBotErrDeletedPtr); // Attempted to use deleted object
CBotProgram::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero
CBotProgram::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable
CBotProgram::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value
CBotProgram::DefineNum("CBotErrNoRetVal", CBotErrNoRetVal); // function did not return results
CBotProgram::DefineNum("CBotErrNoRun", CBotErrNoRun); // active Run () without a function // TODO: Is this actually a runtime error?
CBotProgram::DefineNum("CBotErrUndefFunc", CBotErrUndefFunc); // Calling a function that no longer exists
CBotProgram::DefineNum("CBotErrNotClass", CBotErrNotClass); // Class no longer exists
CBotProgram::DefineNum("CBotErrNull", CBotErrNull); // Attempted to use a null pointer
CBotProgram::DefineNum("CBotErrNan", CBotErrNan); // Can't do operations on nan
CBotProgram::DefineNum("CBotErrOutArray", CBotErrOutArray); // Attempted access out of bounds of an array
CBotProgram::DefineNum("CBotErrStackOver", CBotErrStackOver); // Stack overflow
CBotProgram::DefineNum("CBotErrDeletedPtr", CBotErrDeletedPtr); // Attempted to use deleted object
CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf );
@ -484,4 +446,4 @@ void CBotProgram::Free()
CBotToken::Free() ;
CBotCall ::Free() ;
CBotClass::Free() ;
}
}

View File

@ -86,9 +86,9 @@ public:
/**
* \brief Constructor
* \param pInstance Variable to pass to the program as "this"
* \param thisVar Variable to pass to the program as "this"
*/
CBotProgram(CBotVar* pInstance);
CBotProgram(CBotVar* thisVar);
/**
* \brief Destructor
@ -113,6 +113,12 @@ public:
/**
* \brief Compile compiles the program given as string
*
* Compilation is done in a few steps:
* 1. Convert the code into "tokens" - see CBotToken::CompileTokens()
* 2. First pass - getting declarations of all functions an classes for use later
* 3. Second pass - compiling definitions of all functions and classes
*
* \param program Code to compile
* \param[out] functions Returns the names of functions declared as extern
* \param pUser Optional pointer to be passed to compile function (see AddFunction())
@ -121,17 +127,6 @@ public:
*/
bool Compile(const std::string& program, std::vector<std::string>& functions, void* pUser = nullptr);
/**
* \brief Associates an unique identifier with this instance of CBotProgram
*/
void SetIdent(long n);
/**
* \brief Returns the unique identifier
* \see SetIdent
*/
long GetIdent();
/**
* \brief Returns the last error
* \return Error code
@ -344,20 +339,18 @@ public:
private:
//! All user-defined functions
CBotFunction* m_Prog;
CBotFunction* m_functions = nullptr;
//! The entry point function
CBotFunction* m_pRun;
CBotFunction* m_entryPoint = nullptr;
//! Classes defined in this program
CBotClass* m_pClass;
CBotClass* m_classes = nullptr;
//! Execution stack
CBotStack* m_pStack;
CBotStack* m_pStack = nullptr;
//! "this" variable
CBotVar* m_pInstance;
CBotVar* m_thisVar = nullptr;
friend class CBotFunction;
CBotError m_ErrorCode;
int m_ErrorStart;
int m_ErrorEnd;
//! Associated identifier
long m_Ident;
CBotError m_error = CBotNoErr;
int m_errorStart = 0;
int m_errorEnd = 0;
};

View File

@ -17,21 +17,120 @@
* along with this program. If not, see http://gnu.org/licenses
*/
// Modules inlcude
#include "CBot/CBotToken.h"
#include "CBotKeywordStrings.h"
// Local include
// Global include
#include <cstdarg>
#include <map>
//! \brief Keeps the string corresponding to keyword ID
//! Map is filled with id-string pars that are needed for CBot language parsing
static const std::map<TokenId, const std::string> KEYWORDS = {
{ID_IF, "if"},
{ID_ELSE, "else"},
{ID_WHILE, "while"},
{ID_DO, "do"},
{ID_FOR, "for"},
{ID_BREAK, "break"},
{ID_CONTINUE, "continue"},
{ID_SWITCH, "switch"},
{ID_CASE, "case"},
{ID_DEFAULT, "default"},
{ID_TRY, "try"},
{ID_THROW, "throw"},
{ID_CATCH, "catch"},
{ID_FINALLY, "finally"},
{ID_TXT_AND, "and"},
{ID_TXT_OR, "or"},
{ID_TXT_NOT, "not"},
{ID_RETURN, "return"},
{ID_CLASS, "class"},
{ID_EXTENDS, "extends"},
{ID_SYNCHO, "synchronized"},
{ID_NEW, "new"},
{ID_PUBLIC, "public"},
{ID_EXTERN, "extern"},
{ID_STATIC, "static"},
{ID_PROTECTED, "protected"},
{ID_PRIVATE, "private"},
{ID_INT, "int"},
{ID_FLOAT, "float"},
{ID_BOOLEAN, "boolean"},
{ID_STRING, "string"},
{ID_VOID, "void"},
{ID_BOOL, "bool"},
{ID_TRUE, "true"},
{ID_FALSE, "false"},
{ID_NULL, "null"},
{ID_NAN, "nan"},
{ID_OPENPAR, "("},
{ID_CLOSEPAR, ")"},
{ID_OPBLK, "{"},
{ID_CLBLK, "}"},
{ID_SEP, ";"},
{ID_COMMA, ","},
{ID_DOTS, ":"},
{ID_DOT, "."},
{ID_OPBRK, "["},
{ID_CLBRK, "]"},
{ID_DBLDOTS, "::"},
{ID_LOGIC, "?"},
{ID_ADD, "+"},
{ID_SUB, "-"},
{ID_MUL, "*"},
{ID_DIV, "/"},
{ID_ASS, "="},
{ID_ASSADD, "+="},
{ID_ASSSUB, "-="},
{ID_ASSMUL, "*="},
{ID_ASSDIV, "/="},
{ID_ASSOR, "|="},
{ID_ASSAND, "&="},
{ID_ASSXOR, "^="},
{ID_ASSSL, "<<="},
{ID_ASSSR, ">>>="},
{ID_ASSASR, ">>="},
{ID_SL, "<<"},
{ID_SR, ">>"},
{ID_ASR, ">>"},
{ID_INC, "++"},
{ID_DEC, "--"},
{ID_LO, "<"},
{ID_HI, ">"},
{ID_LS, "<="},
{ID_HS, ">="},
{ID_EQ, "=="},
{ID_NE, "!="},
{ID_AND, "&"},
{ID_XOR, "^"},
{ID_OR, "|"},
{ID_LOG_AND, "&&"},
{ID_LOG_OR, "||"},
{ID_LOG_NOT, "!"},
{ID_NOT, "~"},
{ID_MODULO, "%"},
{ID_POWER, "**"},
{ID_ASSMODULO, "%="},
{TX_UNDEF, "undefined"},
{TX_NAN, "not a number"}
};
namespace {
static const std::string emptyString = "";
}
const std::string& LoadString(TokenId id)
{
if (KEYWORDS.find(id) != KEYWORDS.end())
{
return KEYWORDS.at(id);
}
else
{
return emptyString;
}
}
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> CBotToken::m_ListKeyWords;
int CBotToken::m_ListIdKeyWords[200];
std::vector<std::string> CBotToken::m_ListKeyDefine;
long CBotToken::m_ListKeyNums[MAXDEFNUM];
std::map<std::string, long> CBotToken::m_defineNum;
////////////////////////////////////////////////////////////////////////////////
CBotToken::CBotToken()
{
@ -94,7 +193,7 @@ CBotToken::~CBotToken()
////////////////////////////////////////////////////////////////////////////////
void CBotToken::Free()
{
m_ListKeyDefine.clear();
m_defineNum.clear();
}
////////////////////////////////////////////////////////////////////////////////
@ -194,20 +293,6 @@ bool CharInList(const char c, const char* list)
}
}
////////////////////////////////////////////////////////////////////////////////
bool Char2InList(const char c, const char cc, const char* list)
{
int i = 0;
while (true)
{
if (c == list[i++] &&
cc == list[i++]) return true;
if (list[i] == 0) return false;
}
}
static char sep1[] = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
static char sep2[] = " \r\n\t"; // only separators
static char sep3[] = ",:()[]{}-+*/=;<>!~^|&%."; // operational separators
@ -216,24 +301,23 @@ static char hexnum[] = "0123456789ABCDEFabcdef";
static char nch[] = "\"\r\n\t"; // forbidden in chains
////////////////////////////////////////////////////////////////////////////////
CBotToken* CBotToken::NextToken(char* &program, int& error, bool first)
CBotToken* CBotToken::NextToken(const char*& program, bool first)
{
std::string mot; // the word which is found
std::string sep; // separators that are after
char c;
bool stop = first;
std::string token; // found token
std::string sep; // separators after the token
bool stop = first;
if (*program == 0) return nullptr;
c = *(program++); // next character
char c = *(program++); // next character
if (!first)
{
mot = c; // built the word
token = c; // built the word
c = *(program++); // next character
// special case for strings
if ( mot[0] == '\"' )
if (token[0] == '\"' )
{
while (c != 0 && !CharInList(c, nch))
{
@ -244,34 +328,34 @@ CBotToken* CBotToken::NextToken(char* &program, int& error, bool first)
if ( c == 'r' ) c = '\r';
if ( c == 't' ) c = '\t';
}
mot += c;
token += c;
c = *(program++);
}
if ( c == '\"' )
{
mot += c; // string is complete
token += c; // string is complete
c = *(program++); // next character
}
stop = true;
}
// special case for numbers
if ( CharInList(mot[0], num ))
if ( CharInList(token[0], num ))
{
bool bdot = false; // found a point?
bool bexp = false; // found an exponent?
char* liste = num;
if (mot[0] == '0' && c == 'x') // hexadecimal value?
if (token[0] == '0' && c == 'x') // hexadecimal value?
{
mot += c;
token += c;
c = *(program++); // next character
liste = hexnum;
}
cw:
while (c != 0 && CharInList(c, liste))
{
cc: mot += c;
cc: token += c;
c = *(program++); // next character
}
if ( liste == num ) // not for hexadecimal
@ -280,7 +364,7 @@ cc: mot += c;
if ( !bexp && ( c == 'e' || c == 'E' ) )
{
bexp = true;
mot += c;
token += c;
c = *(program++); // next character
if ( c == '-' ||
c == '+' ) goto cc;
@ -291,12 +375,12 @@ cc: mot += c;
stop = true;
}
if (CharInList(mot[0], sep3)) // an operational separator?
if (CharInList(token[0], sep3)) // an operational separator?
{
std::string motc = mot;
while (motc += c, c != 0 && GetKeyWords(motc)>0) // operand seeks the longest possible
std::string motc = token;
while (motc += c, c != 0 && GetKeyWord(motc) > 0) // operand seeks the longest possible
{
mot += c; // build the word
token += c; // build the word
c = *(program++); // next character
}
@ -310,7 +394,7 @@ cc: mot += c;
{
if (stop || c == 0 || CharInList(c, sep1))
{
if (!first && mot.empty()) return nullptr; // end of the analysis
if (!first && token.empty()) return nullptr; // end of the analysis
bis:
while (CharInList(c, sep2))
{
@ -346,33 +430,32 @@ bis:
program--;
CBotToken* token = new CBotToken(mot, sep);
CBotToken* t = new CBotToken(token, sep);
if (CharInList( mot[0], num )) token->m_type = TokenTypNum;
if (mot[0] == '\"') token->m_type = TokenTypString;
if (first) token->m_type = TokenTypNone;
if (CharInList(token[0], num )) t->m_type = TokenTypNum;
if (token[0] == '\"') t->m_type = TokenTypString;
if (first) t->m_type = TokenTypNone;
token->m_IdKeyWord = GetKeyWords(mot);
if (token->m_IdKeyWord > 0) token->m_type = TokenTypKeyWord;
else GetKeyDefNum(mot, token) ; // treats DefineNum
t->m_IdKeyWord = GetKeyWord(token);
if (t->m_IdKeyWord > 0) t->m_type = TokenTypKeyWord;
else GetKeyDefNum(token, t) ; // treats DefineNum
return token;
return t;
}
mot += c; // built the word
token += c; // built the word
c = *(program++); // next character
}
}
////////////////////////////////////////////////////////////////////////////////
CBotToken* CBotToken::CompileTokens(const std::string& program, int& error)
CBotToken* CBotToken::CompileTokens(const std::string& program)
{
CBotToken *nxt, *prv, *tokenbase;
char* p = const_cast<char*> (program.c_str());
const char* p = program.c_str();
int pos = 0;
error = 0;
prv = tokenbase = NextToken(p, error, true);
prv = tokenbase = NextToken(p, true);
if (tokenbase == nullptr) return nullptr;
@ -381,29 +464,19 @@ CBotToken* CBotToken::CompileTokens(const std::string& program, int& error)
tokenbase->m_end = pos;
pos += tokenbase->m_Sep.length();
char* pp = p;
while (nullptr != (nxt = NextToken(p, error)))
const char* pp = p;
while (nullptr != (nxt = NextToken(p, false)))
{
prv->m_next = nxt; // added after
nxt->m_prev = prv;
prv = nxt; // advance
nxt->m_start = pos;
/* pos += nxt->m_Text.GetLength(); // chain may be shorter (BOA deleted)
nxt->m_end = pos;
pos += nxt->m_Sep.GetLength();*/
pos += (p - pp); // total size
nxt->m_end = pos - nxt->m_Sep.length();
pp = p;
}
// adds a token as a terminator
// ( useful for the previous )
nxt = new CBotToken();
nxt->m_type = TokenTypNone;
prv->m_next = nxt; // added after
nxt->m_prev = prv;
return tokenbase;
}
@ -414,87 +487,38 @@ void CBotToken::Delete(CBotToken* pToken)
}
////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetKeyWords(const std::string& w)
int CBotToken::GetKeyWord(const std::string& w)
{
int i;
int l = m_ListKeyWords.size();
if (l == 0)
for (const auto& it : KEYWORDS)
{
LoadKeyWords(); // takes the list for the first time
l = m_ListKeyWords.size();
}
for (i = 0; i < l; i++)
{
if (m_ListKeyWords[i] == w) return m_ListIdKeyWords[ i ];
if (it.second == w) return it.first;
}
return -1;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotToken::GetKeyDefNum(const std::string& w, CBotToken*& token)
bool CBotToken::GetKeyDefNum(const std::string& name, CBotToken* token)
{
int i;
int l = m_ListKeyDefine.size();
if (m_defineNum.count(name) == 0)
return false;
for (i = 0; i < l; i++)
{
if (m_ListKeyDefine[i] == w)
{
token->m_IdKeyWord = m_ListKeyNums[i];
token->m_type = TokenTypDef;
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
void CBotToken::LoadKeyWords()
{
std::string s;
int i, n = 0;
i = TokenKeyWord; //start with keywords of the language
while (!(s = LoadString(static_cast<TokenId>(i))).empty())
{
m_ListKeyWords.push_back(s);
m_ListIdKeyWords[n++] = i++;
}
i = TokenKeyVal; //keywords of values
while (!(s = LoadString(static_cast<TokenId>(i))).empty())
{
m_ListKeyWords.push_back(s);
m_ListIdKeyWords[n++] = i++;
}
i = TokenKeyOp; //operators
while (!(s = LoadString(static_cast<TokenId>(i))).empty())
{
m_ListKeyWords.push_back(s);
m_ListIdKeyWords[n++] = i++;
}
token->m_type = TokenTypDef;
token->m_IdKeyWord = m_defineNum[name];
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotToken::DefineNum(const std::string& name, long val)
{
int i;
int l = m_ListKeyDefine.size();
for (i = 0; i < l; i++)
if (m_defineNum.count(name) > 0)
{
if (m_ListKeyDefine[i] == name) return false;
// TODO: No access to the logger from CBot library :(
printf("CBOT WARNING: %s redefined\n", name.c_str());
return false;
}
if ( i == MAXDEFNUM ) return false;
m_ListKeyDefine.push_back( name );
m_ListKeyNums[i] = val;
m_defineNum[name] = val;
return true;
}

View File

@ -21,11 +21,10 @@
#include <vector>
#include <string>
#include <map>
#include "CBot/CBotEnums.h"
#define MAXDEFNUM 1000 // limited number of DefineNum
/**
* \brief Class representing one token of a program.
*
@ -166,17 +165,7 @@ public:
* \return The first token of the linked liste.
* \todo Replace the error code by an enum.
*/
static CBotToken* CompileTokens(const std::string& p, int& error);
/*!
* \brief NextToken Looking for the next token in the string. The string must
* not start with separators. The separator is part of the previous token.
* \param [in] program The program string.
* \param [out] error The error code.
* \param [in] first True if this is the first call false othewise.
* \return A CBotTOken.
*/
static CBotToken* NextToken(char* &program, int& error, bool first = false);
static CBotToken* CompileTokens(const std::string& p);
/**
* \brief Delete Releases the CBotToken linked list.
@ -200,6 +189,17 @@ public:
*/
static void Free();
private:
/*!
* \brief NextToken Looking for the next token in the string. The string must
* not start with separators. The separator is part of the previous token.
* \param [in] program The program string.
* \param [out] error The error code.
* \param [in] first True if this is the first call false othewise.
* \return A CBotTOken.
*/
static CBotToken* NextToken(const char*& program, bool first);
private:
//! The next token in the linked list
@ -221,42 +221,23 @@ private:
//! The end position of the token in the CBotProgram
int m_end;
/*!
* \brief GetKeyWords Check if the word is a keyword.
* \param w The word to compare.
* \return -1 if this is not a keyword the keyword number otherwise.
*/
static int GetKeyWords(const std::string& w); // is it a keyword?
//! Map of all predefined constants (see DefineNum())
static std::map<std::string, long> m_defineNum;
/*!
* \brief GetKeyDefNum Check if this is a defined word and set the defined
* word type in a CBotToken.
* \param [in] w The word to compaire.
* \param [out] token The token in which the type will be set.
* \return True if the defined word is found false otherwise.
* \brief Check if the word is a keyword
* \param w The word to check
* \return the keyword ID, or -1 if this is not a keyword
*/
static bool GetKeyDefNum(const std::string& w, CBotToken*& token);
static int GetKeyWord(const std::string& w);
/*!
* \brief LoadKeyWords Loads the list of keywords. The list of keyword is
* std::string::s_keywordString. This keywords are keywords languages (if, +,
* for, while, case, extern ...)
* \todo Fixme Figure out how this should work.
/**
* \brief Resolve a constant defined with DefineNum()
* \param name Constant name
* \param token Token that we are working on, will be filled with data about found constant
* \return true if the constant was found, false otherwise
*/
static void LoadKeyWords();
//! List of keywords of the CBot language (if, +, for, while, case, extern ...)
static std::vector<std::string> m_ListKeyWords;
//! List of id correponding to the keywords of the CBot language
static int m_ListIdKeyWords[200];
//! List of CBot language error and list of colobot specific keywords
//! This keywords are defined in :
//! - void CScriptFunctions::Init()
//! - void CBotProgram::Init()
static std::vector<std::string> m_ListKeyDefine;
//! List of id correponding to the defined words
static long m_ListKeyNums[MAXDEFNUM];
static bool GetKeyDefNum(const std::string& name, CBotToken* token);
};
@ -276,3 +257,13 @@ extern bool IsOfType(CBotToken* &p, int type1, int type2 = -1);
* \return True if the type of the token match one of a parameter.
*/
extern bool IsOfTypeList(CBotToken* &p, int type1, ...);
/**
* \brief LoadString Maps given ID to its string equivalent.
* \param id Provided identifier.
* \return String if found, else NullString.
*/
const std::string& LoadString(TokenId id);

View File

@ -355,7 +355,7 @@ void CBotVar::SetInit(CBotVar::InitType initType)
if ( instance == nullptr )
{
instance = new CBotVarClass(nullptr, m_type);
// instance->SetClass((static_cast<CBotVarPointer*>(this))->m_pClass);
// instance->SetClass((static_cast<CBotVarPointer*>(this))->m_classes);
SetPointer(instance);
}
instance->SetInit(CBotVar::InitType::DEF);

View File

@ -21,7 +21,6 @@
#include "CBot/CBotEnums.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotKeywordStrings.h"
#include "CBot/CBotToken.h"

View File

@ -22,7 +22,6 @@
#include "CBot/CBotEnums.h"
#include "CBot/CBotToken.h"
#include "CBot/CBotKeywordStrings.h"
#include "CBot/CBotUtils.h"

View File

@ -23,7 +23,6 @@
#include "CBot/CBotEnums.h"
#include "CBot/CBotToken.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotKeywordStrings.h"
// Local include

View File

@ -23,7 +23,6 @@
#include "CBot/CBotEnums.h"
#include "CBot/CBotToken.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotKeywordStrings.h"
// Local include

View File

@ -10,7 +10,6 @@ set(SOURCES
CBotDefParam.cpp
CBotCallMethode.cpp
CBotTypResult.cpp
CBotKeywordStrings.cpp
CBotInstr/CBotInstr.cpp
CBotInstr/CBotInstrUtils.cpp
CBotInstr/CBotWhile.cpp

View File

@ -160,7 +160,7 @@ bool CScript::CheckToken()
CBotToken* allBt;
std::string bs;
std::string token;
int error, cursor1, cursor2, i;
int cursor1, cursor2, i;
char used[100];
if ( !m_object->GetCheckToken() ) return true;
@ -176,7 +176,7 @@ bool CScript::CheckToken()
used[i] = 0; // token not used
}
allBt = CBotToken::CompileTokens(m_script.get(), error);
allBt = CBotToken::CompileTokens(m_script.get());
bt = allBt;
while ( bt != nullptr )
{
@ -635,8 +635,7 @@ void CScript::ColorizeScript(Ui::CEdit* edit, int rangeStart, int rangeEnd)
std::string text = std::string(edit->GetText(), edit->GetMaxChar());
text = text.substr(rangeStart, rangeEnd-rangeStart);
int error;
CBotToken* bt = CBotToken::CompileTokens(text.c_str(), error);
CBotToken* bt = CBotToken::CompileTokens(text.c_str());
while ( bt != nullptr )
{
std::string token = bt->GetString();