diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 7b4f1f94..e1a9398f 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -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); diff --git a/src/CBot/CBotKeywordStrings.cpp b/src/CBot/CBotKeywordStrings.cpp deleted file mode 100644 index 75e52ad1..00000000 --- a/src/CBot/CBotKeywordStrings.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "CBot/CBotKeywordStrings.h" - -#include - -//! \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 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; - } -} \ No newline at end of file diff --git a/src/CBot/CBotKeywordStrings.h b/src/CBot/CBotKeywordStrings.h deleted file mode 100644 index 6cdb0cf9..00000000 --- a/src/CBot/CBotKeywordStrings.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "CBotEnums.h" - -#include - -/** - * \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); diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index c2cc8169..66697d7e 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -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 - -//////////////////////////////////////////////////////////////////////////////// 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& 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& ( 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& 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() ; -} +} \ No newline at end of file diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index 41b71680..5d27f925 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -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& 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; }; diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp index ad4469c7..89f87e93 100644 --- a/src/CBot/CBotToken.cpp +++ b/src/CBot/CBotToken.cpp @@ -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 +#include + +//! \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 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 CBotToken::m_ListKeyWords; -int CBotToken::m_ListIdKeyWords[200]; -std::vector CBotToken::m_ListKeyDefine; -long CBotToken::m_ListKeyNums[MAXDEFNUM]; - +std::map 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,:()[]{}-+*/=;>!~^|&%."; // 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 (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(i))).empty()) - { - m_ListKeyWords.push_back(s); - m_ListIdKeyWords[n++] = i++; - } - - - i = TokenKeyVal; //keywords of values - while (!(s = LoadString(static_cast(i))).empty()) - { - m_ListKeyWords.push_back(s); - m_ListIdKeyWords[n++] = i++; - } - - i = TokenKeyOp; //operators - while (!(s = LoadString(static_cast(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; } diff --git a/src/CBot/CBotToken.h b/src/CBot/CBotToken.h index 2cdada33..6955ed6b 100644 --- a/src/CBot/CBotToken.h +++ b/src/CBot/CBotToken.h @@ -21,11 +21,10 @@ #include #include +#include #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 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 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 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); diff --git a/src/CBot/CBotVar/CBotVar.cpp b/src/CBot/CBotVar/CBotVar.cpp index 7b15ef39..677a126e 100644 --- a/src/CBot/CBotVar/CBotVar.cpp +++ b/src/CBot/CBotVar/CBotVar.cpp @@ -355,7 +355,7 @@ void CBotVar::SetInit(CBotVar::InitType initType) if ( instance == nullptr ) { instance = new CBotVarClass(nullptr, m_type); -// instance->SetClass((static_cast(this))->m_pClass); +// instance->SetClass((static_cast(this))->m_classes); SetPointer(instance); } instance->SetInit(CBotVar::InitType::DEF); diff --git a/src/CBot/CBotVar/CBotVarBoolean.cpp b/src/CBot/CBotVar/CBotVarBoolean.cpp index a0602b8d..c7bffd73 100644 --- a/src/CBot/CBotVar/CBotVarBoolean.cpp +++ b/src/CBot/CBotVar/CBotVarBoolean.cpp @@ -21,7 +21,6 @@ #include "CBot/CBotEnums.h" #include "CBot/CBotUtils.h" -#include "CBot/CBotKeywordStrings.h" #include "CBot/CBotToken.h" diff --git a/src/CBot/CBotVar/CBotVarFloat.cpp b/src/CBot/CBotVar/CBotVarFloat.cpp index 0d7688ad..6f93b540 100644 --- a/src/CBot/CBotVar/CBotVarFloat.cpp +++ b/src/CBot/CBotVar/CBotVarFloat.cpp @@ -22,7 +22,6 @@ #include "CBot/CBotEnums.h" #include "CBot/CBotToken.h" -#include "CBot/CBotKeywordStrings.h" #include "CBot/CBotUtils.h" diff --git a/src/CBot/CBotVar/CBotVarInt.cpp b/src/CBot/CBotVar/CBotVarInt.cpp index b3fad7a5..58b8cde9 100644 --- a/src/CBot/CBotVar/CBotVarInt.cpp +++ b/src/CBot/CBotVar/CBotVarInt.cpp @@ -23,7 +23,6 @@ #include "CBot/CBotEnums.h" #include "CBot/CBotToken.h" #include "CBot/CBotUtils.h" -#include "CBot/CBotKeywordStrings.h" // Local include diff --git a/src/CBot/CBotVar/CBotVarString.cpp b/src/CBot/CBotVar/CBotVarString.cpp index 0dee1c5e..48fb21ea 100644 --- a/src/CBot/CBotVar/CBotVarString.cpp +++ b/src/CBot/CBotVar/CBotVarString.cpp @@ -23,7 +23,6 @@ #include "CBot/CBotEnums.h" #include "CBot/CBotToken.h" #include "CBot/CBotUtils.h" -#include "CBot/CBotKeywordStrings.h" // Local include diff --git a/src/CBot/CMakeLists.txt b/src/CBot/CMakeLists.txt index 62f7d72f..0a890554 100644 --- a/src/CBot/CMakeLists.txt +++ b/src/CBot/CMakeLists.txt @@ -10,7 +10,6 @@ set(SOURCES CBotDefParam.cpp CBotCallMethode.cpp CBotTypResult.cpp - CBotKeywordStrings.cpp CBotInstr/CBotInstr.cpp CBotInstr/CBotInstrUtils.cpp CBotInstr/CBotWhile.cpp diff --git a/src/script/script.cpp b/src/script/script.cpp index 0627be10..3537b97e 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -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();