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

View File

@ -86,9 +86,9 @@ public:
/** /**
* \brief Constructor * \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 * \brief Destructor
@ -113,6 +113,12 @@ public:
/** /**
* \brief Compile compiles the program given as string * \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 program Code to compile
* \param[out] functions Returns the names of functions declared as extern * \param[out] functions Returns the names of functions declared as extern
* \param pUser Optional pointer to be passed to compile function (see AddFunction()) * \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); 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 * \brief Returns the last error
* \return Error code * \return Error code
@ -344,20 +339,18 @@ public:
private: private:
//! All user-defined functions //! All user-defined functions
CBotFunction* m_Prog; CBotFunction* m_functions = nullptr;
//! The entry point function //! The entry point function
CBotFunction* m_pRun; CBotFunction* m_entryPoint = nullptr;
//! Classes defined in this program //! Classes defined in this program
CBotClass* m_pClass; CBotClass* m_classes = nullptr;
//! Execution stack //! Execution stack
CBotStack* m_pStack; CBotStack* m_pStack = nullptr;
//! "this" variable //! "this" variable
CBotVar* m_pInstance; CBotVar* m_thisVar = nullptr;
friend class CBotFunction; friend class CBotFunction;
CBotError m_ErrorCode; CBotError m_error = CBotNoErr;
int m_ErrorStart; int m_errorStart = 0;
int m_ErrorEnd; int m_errorEnd = 0;
//! Associated identifier
long m_Ident;
}; };

View File

@ -17,21 +17,120 @@
* along with this program. If not, see http://gnu.org/licenses * along with this program. If not, see http://gnu.org/licenses
*/ */
// Modules inlcude
#include "CBot/CBotToken.h" #include "CBot/CBotToken.h"
#include "CBotKeywordStrings.h"
// Local include
// Global include
#include <cstdarg> #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; std::map<std::string, long> CBotToken::m_defineNum;
int CBotToken::m_ListIdKeyWords[200];
std::vector<std::string> CBotToken::m_ListKeyDefine;
long CBotToken::m_ListKeyNums[MAXDEFNUM];
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotToken::CBotToken() CBotToken::CBotToken()
{ {
@ -94,7 +193,7 @@ CBotToken::~CBotToken()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotToken::Free() 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 sep1[] = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
static char sep2[] = " \r\n\t"; // only separators static char sep2[] = " \r\n\t"; // only separators
static char sep3[] = ",:()[]{}-+*/=;<>!~^|&%."; // operational separators static char sep3[] = ",:()[]{}-+*/=;<>!~^|&%."; // operational separators
@ -216,24 +301,23 @@ static char hexnum[] = "0123456789ABCDEFabcdef";
static char nch[] = "\"\r\n\t"; // forbidden in chains 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 token; // found token
std::string sep; // separators that are after std::string sep; // separators after the token
char c; bool stop = first;
bool stop = first;
if (*program == 0) return nullptr; if (*program == 0) return nullptr;
c = *(program++); // next character char c = *(program++); // next character
if (!first) if (!first)
{ {
mot = c; // built the word token = c; // built the word
c = *(program++); // next character c = *(program++); // next character
// special case for strings // special case for strings
if ( mot[0] == '\"' ) if (token[0] == '\"' )
{ {
while (c != 0 && !CharInList(c, nch)) 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 == 'r' ) c = '\r';
if ( c == 't' ) c = '\t'; if ( c == 't' ) c = '\t';
} }
mot += c; token += c;
c = *(program++); c = *(program++);
} }
if ( c == '\"' ) if ( c == '\"' )
{ {
mot += c; // string is complete token += c; // string is complete
c = *(program++); // next character c = *(program++); // next character
} }
stop = true; stop = true;
} }
// special case for numbers // special case for numbers
if ( CharInList(mot[0], num )) if ( CharInList(token[0], num ))
{ {
bool bdot = false; // found a point? bool bdot = false; // found a point?
bool bexp = false; // found an exponent? bool bexp = false; // found an exponent?
char* liste = num; 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 c = *(program++); // next character
liste = hexnum; liste = hexnum;
} }
cw: cw:
while (c != 0 && CharInList(c, liste)) while (c != 0 && CharInList(c, liste))
{ {
cc: mot += c; cc: token += c;
c = *(program++); // next character c = *(program++); // next character
} }
if ( liste == num ) // not for hexadecimal if ( liste == num ) // not for hexadecimal
@ -280,7 +364,7 @@ cc: mot += c;
if ( !bexp && ( c == 'e' || c == 'E' ) ) if ( !bexp && ( c == 'e' || c == 'E' ) )
{ {
bexp = true; bexp = true;
mot += c; token += c;
c = *(program++); // next character c = *(program++); // next character
if ( c == '-' || if ( c == '-' ||
c == '+' ) goto cc; c == '+' ) goto cc;
@ -291,12 +375,12 @@ cc: mot += c;
stop = true; stop = true;
} }
if (CharInList(mot[0], sep3)) // an operational separator? if (CharInList(token[0], sep3)) // an operational separator?
{ {
std::string motc = mot; std::string motc = token;
while (motc += c, c != 0 && GetKeyWords(motc)>0) // operand seeks the longest possible 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 c = *(program++); // next character
} }
@ -310,7 +394,7 @@ cc: mot += c;
{ {
if (stop || c == 0 || CharInList(c, sep1)) 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: bis:
while (CharInList(c, sep2)) while (CharInList(c, sep2))
{ {
@ -346,33 +430,32 @@ bis:
program--; program--;
CBotToken* token = new CBotToken(mot, sep); CBotToken* t = new CBotToken(token, sep);
if (CharInList( mot[0], num )) token->m_type = TokenTypNum; if (CharInList(token[0], num )) t->m_type = TokenTypNum;
if (mot[0] == '\"') token->m_type = TokenTypString; if (token[0] == '\"') t->m_type = TokenTypString;
if (first) token->m_type = TokenTypNone; if (first) t->m_type = TokenTypNone;
token->m_IdKeyWord = GetKeyWords(mot); t->m_IdKeyWord = GetKeyWord(token);
if (token->m_IdKeyWord > 0) token->m_type = TokenTypKeyWord; if (t->m_IdKeyWord > 0) t->m_type = TokenTypKeyWord;
else GetKeyDefNum(mot, token) ; // treats DefineNum else GetKeyDefNum(token, t) ; // treats DefineNum
return token; return t;
} }
mot += c; // built the word token += c; // built the word
c = *(program++); // next character c = *(program++); // next character
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotToken* CBotToken::CompileTokens(const std::string& program, int& error) CBotToken* CBotToken::CompileTokens(const std::string& program)
{ {
CBotToken *nxt, *prv, *tokenbase; CBotToken *nxt, *prv, *tokenbase;
char* p = const_cast<char*> (program.c_str()); const char* p = program.c_str();
int pos = 0; int pos = 0;
error = 0; prv = tokenbase = NextToken(p, true);
prv = tokenbase = NextToken(p, error, true);
if (tokenbase == nullptr) return nullptr; if (tokenbase == nullptr) return nullptr;
@ -381,29 +464,19 @@ CBotToken* CBotToken::CompileTokens(const std::string& program, int& error)
tokenbase->m_end = pos; tokenbase->m_end = pos;
pos += tokenbase->m_Sep.length(); pos += tokenbase->m_Sep.length();
char* pp = p; const char* pp = p;
while (nullptr != (nxt = NextToken(p, error))) while (nullptr != (nxt = NextToken(p, false)))
{ {
prv->m_next = nxt; // added after prv->m_next = nxt; // added after
nxt->m_prev = prv; nxt->m_prev = prv;
prv = nxt; // advance prv = nxt; // advance
nxt->m_start = pos; 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 pos += (p - pp); // total size
nxt->m_end = pos - nxt->m_Sep.length(); nxt->m_end = pos - nxt->m_Sep.length();
pp = p; 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; 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; for (const auto& it : KEYWORDS)
int l = m_ListKeyWords.size();
if (l == 0)
{ {
LoadKeyWords(); // takes the list for the first time if (it.second == w) return it.first;
l = m_ListKeyWords.size();
}
for (i = 0; i < l; i++)
{
if (m_ListKeyWords[i] == w) return m_ListIdKeyWords[ i ];
} }
return -1; return -1;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotToken::GetKeyDefNum(const std::string& w, CBotToken*& token) bool CBotToken::GetKeyDefNum(const std::string& name, CBotToken* token)
{ {
int i; if (m_defineNum.count(name) == 0)
int l = m_ListKeyDefine.size(); return false;
for (i = 0; i < l; i++) token->m_type = TokenTypDef;
{ token->m_IdKeyWord = m_defineNum[name];
if (m_ListKeyDefine[i] == w) return true;
{
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++;
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CBotToken::DefineNum(const std::string& name, long val) bool CBotToken::DefineNum(const std::string& name, long val)
{ {
int i; if (m_defineNum.count(name) > 0)
int l = m_ListKeyDefine.size();
for (i = 0; i < l; i++)
{ {
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_defineNum[name] = val;
m_ListKeyNums[i] = val;
return true; return true;
} }

View File

@ -21,11 +21,10 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <map>
#include "CBot/CBotEnums.h" #include "CBot/CBotEnums.h"
#define MAXDEFNUM 1000 // limited number of DefineNum
/** /**
* \brief Class representing one token of a program. * \brief Class representing one token of a program.
* *
@ -166,17 +165,7 @@ public:
* \return The first token of the linked liste. * \return The first token of the linked liste.
* \todo Replace the error code by an enum. * \todo Replace the error code by an enum.
*/ */
static CBotToken* CompileTokens(const std::string& p, int& error); static CBotToken* CompileTokens(const std::string& p);
/*!
* \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);
/** /**
* \brief Delete Releases the CBotToken linked list. * \brief Delete Releases the CBotToken linked list.
@ -200,6 +189,17 @@ public:
*/ */
static void Free(); 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: private:
//! The next token in the linked list //! The next token in the linked list
@ -221,42 +221,23 @@ private:
//! The end position of the token in the CBotProgram //! The end position of the token in the CBotProgram
int m_end; int m_end;
/*! //! Map of all predefined constants (see DefineNum())
* \brief GetKeyWords Check if the word is a keyword. static std::map<std::string, long> m_defineNum;
* \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?
/*! /*!
* \brief GetKeyDefNum Check if this is a defined word and set the defined * \brief Check if the word is a keyword
* word type in a CBotToken. * \param w The word to check
* \param [in] w The word to compaire. * \return the keyword ID, or -1 if this is not a keyword
* \param [out] token The token in which the type will be set.
* \return True if the defined word is found false otherwise.
*/ */
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 * \brief Resolve a constant defined with DefineNum()
* std::string::s_keywordString. This keywords are keywords languages (if, +, * \param name Constant name
* for, while, case, extern ...) * \param token Token that we are working on, will be filled with data about found constant
* \todo Fixme Figure out how this should work. * \return true if the constant was found, false otherwise
*/ */
static void LoadKeyWords(); static bool GetKeyDefNum(const std::string& name, CBotToken* token);
//! 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];
}; };
@ -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. * \return True if the type of the token match one of a parameter.
*/ */
extern bool IsOfTypeList(CBotToken* &p, int type1, ...); 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 ) if ( instance == nullptr )
{ {
instance = new CBotVarClass(nullptr, m_type); instance = new CBotVarClass(nullptr, m_type);
// instance->SetClass((static_cast<CBotVarPointer*>(this))->m_pClass); // instance->SetClass((static_cast<CBotVarPointer*>(this))->m_classes);
SetPointer(instance); SetPointer(instance);
} }
instance->SetInit(CBotVar::InitType::DEF); instance->SetInit(CBotVar::InitType::DEF);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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