Merge pull request #1253 from melex750/dev-savegame
Add types byte, short, char, long, and doubleblender-script
commit
a67266553f
|
@ -1795,6 +1795,12 @@ msgstr ""
|
||||||
msgid "Invalid universal character name"
|
msgid "Invalid universal character name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Empty character constant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Duplicate label in switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dividing by zero"
|
msgid "Dividing by zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
6
po/cs.po
6
po/cs.po
|
@ -489,6 +489,9 @@ msgstr "Dolů (\\key gdown;)"
|
||||||
msgid "Drawer bot"
|
msgid "Drawer bot"
|
||||||
msgstr "Tužkobot"
|
msgstr "Tužkobot"
|
||||||
|
|
||||||
|
msgid "Duplicate label in switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||||
msgstr "Prach\\Prach a špína na robotech a budovách"
|
msgstr "Prach\\Prach a špína na robotech a budovách"
|
||||||
|
|
||||||
|
@ -507,6 +510,9 @@ msgstr "Upravit vybraný program"
|
||||||
msgid "Egg"
|
msgid "Egg"
|
||||||
msgstr "Vejce"
|
msgstr "Vejce"
|
||||||
|
|
||||||
|
msgid "Empty character constant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "End of block missing"
|
msgid "End of block missing"
|
||||||
msgstr "Chybí konec bloku"
|
msgstr "Chybí konec bloku"
|
||||||
|
|
||||||
|
|
6
po/de.po
6
po/de.po
|
@ -490,6 +490,9 @@ msgstr "Sinkt (\\key gdown;)"
|
||||||
msgid "Drawer bot"
|
msgid "Drawer bot"
|
||||||
msgstr "Zeichner"
|
msgstr "Zeichner"
|
||||||
|
|
||||||
|
msgid "Duplicate label in switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||||
msgstr "Schmutz\\Schmutz auf Robotern und Bauten"
|
msgstr "Schmutz\\Schmutz auf Robotern und Bauten"
|
||||||
|
|
||||||
|
@ -508,6 +511,9 @@ msgstr "Gewähltes Programm bearbeiten"
|
||||||
msgid "Egg"
|
msgid "Egg"
|
||||||
msgstr "Ei"
|
msgstr "Ei"
|
||||||
|
|
||||||
|
msgid "Empty character constant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "End of block missing"
|
msgid "End of block missing"
|
||||||
msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)"
|
msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)"
|
||||||
|
|
||||||
|
|
6
po/fr.po
6
po/fr.po
|
@ -492,6 +492,9 @@ msgstr "Descend (\\key gdown;)"
|
||||||
msgid "Drawer bot"
|
msgid "Drawer bot"
|
||||||
msgstr "Robot dessinateur"
|
msgstr "Robot dessinateur"
|
||||||
|
|
||||||
|
msgid "Duplicate label in switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||||
msgstr "Salissures\\Salissures des robots et bâtiments"
|
msgstr "Salissures\\Salissures des robots et bâtiments"
|
||||||
|
|
||||||
|
@ -510,6 +513,9 @@ msgstr "Éditer le programme sélectionné"
|
||||||
msgid "Egg"
|
msgid "Egg"
|
||||||
msgstr "Oeuf"
|
msgstr "Oeuf"
|
||||||
|
|
||||||
|
msgid "Empty character constant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "End of block missing"
|
msgid "End of block missing"
|
||||||
msgstr "Il manque la fin du bloc"
|
msgstr "Il manque la fin du bloc"
|
||||||
|
|
||||||
|
|
6
po/pl.po
6
po/pl.po
|
@ -488,6 +488,9 @@ msgstr "Dół (\\key gdown;)"
|
||||||
msgid "Drawer bot"
|
msgid "Drawer bot"
|
||||||
msgstr "Robot rysownik"
|
msgstr "Robot rysownik"
|
||||||
|
|
||||||
|
msgid "Duplicate label in switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||||
msgstr "Kurz\\Kurz i bród na robotach i budynkach"
|
msgstr "Kurz\\Kurz i bród na robotach i budynkach"
|
||||||
|
|
||||||
|
@ -506,6 +509,9 @@ msgstr "Edytuj zaznaczony program"
|
||||||
msgid "Egg"
|
msgid "Egg"
|
||||||
msgstr "Jajo"
|
msgstr "Jajo"
|
||||||
|
|
||||||
|
msgid "Empty character constant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "End of block missing"
|
msgid "End of block missing"
|
||||||
msgstr "Brak końca bloku"
|
msgstr "Brak końca bloku"
|
||||||
|
|
||||||
|
|
6
po/pt.po
6
po/pt.po
|
@ -487,6 +487,9 @@ msgstr "Baixo (\\key gdown;)"
|
||||||
msgid "Drawer bot"
|
msgid "Drawer bot"
|
||||||
msgstr "Robô cartoonista"
|
msgstr "Robô cartoonista"
|
||||||
|
|
||||||
|
msgid "Duplicate label in switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||||
msgstr "Poeira\\Poeira e sujeira nos robôs e prédios"
|
msgstr "Poeira\\Poeira e sujeira nos robôs e prédios"
|
||||||
|
|
||||||
|
@ -505,6 +508,9 @@ msgstr "Alterar o programa selecionado"
|
||||||
msgid "Egg"
|
msgid "Egg"
|
||||||
msgstr "Ovo"
|
msgstr "Ovo"
|
||||||
|
|
||||||
|
msgid "Empty character constant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "End of block missing"
|
msgid "End of block missing"
|
||||||
msgstr "Fim do bloco ausente"
|
msgstr "Fim do bloco ausente"
|
||||||
|
|
||||||
|
|
6
po/ru.po
6
po/ru.po
|
@ -496,6 +496,9 @@ msgstr "Вниз (\\key gdown;)"
|
||||||
msgid "Drawer bot"
|
msgid "Drawer bot"
|
||||||
msgstr "Рисовальщик"
|
msgstr "Рисовальщик"
|
||||||
|
|
||||||
|
msgid "Duplicate label in switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||||
msgstr "Пыль\\Пыль и грязь на ботах и зданиях"
|
msgstr "Пыль\\Пыль и грязь на ботах и зданиях"
|
||||||
|
|
||||||
|
@ -514,6 +517,9 @@ msgstr "Изменить выбранную программу"
|
||||||
msgid "Egg"
|
msgid "Egg"
|
||||||
msgstr "Яйцо"
|
msgstr "Яйцо"
|
||||||
|
|
||||||
|
msgid "Empty character constant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "End of block missing"
|
msgid "End of block missing"
|
||||||
msgstr "Отсутствует конец блока"
|
msgstr "Отсутствует конец блока"
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
#include "CBot/CBotCStack.h"
|
#include "CBot/CBotCStack.h"
|
||||||
#include "CBot/CBotDefParam.h"
|
#include "CBot/CBotDefParam.h"
|
||||||
#include "CBot/CBotUtils.h"
|
#include "CBot/CBotUtils.h"
|
||||||
#include "CBot/CBotFileUtils.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -364,69 +363,70 @@ void CBotClass::RestoreMethode(long& nIdent,
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotClass::SaveStaticState(FILE* pf)
|
bool CBotClass::SaveStaticState(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if (!WriteWord( pf, CBOTVERSION*2)) return false;
|
if (!WriteLong(ostr, CBOTVERSION*2)) return false;
|
||||||
|
|
||||||
// saves the state of static variables in classes
|
// saves the state of static variables in classes
|
||||||
for (CBotClass* p : m_publicClasses)
|
for (CBotClass* p : m_publicClasses)
|
||||||
{
|
{
|
||||||
if (!WriteWord( pf, 1 )) return false;
|
if (!WriteWord(ostr, 1)) return false;
|
||||||
// save the name of the class
|
// save the name of the class
|
||||||
if (!WriteString( pf, p->GetName() )) return false;
|
if (!WriteString(ostr, p->GetName())) return false;
|
||||||
|
|
||||||
CBotVar* pv = p->GetVar();
|
CBotVar* pv = p->GetVar();
|
||||||
while( pv != nullptr )
|
while( pv != nullptr )
|
||||||
{
|
{
|
||||||
if ( pv->IsStatic() )
|
if ( pv->IsStatic() )
|
||||||
{
|
{
|
||||||
if (!WriteWord( pf, 1 )) return false;
|
if (!WriteWord(ostr, 1)) return false;
|
||||||
if (!WriteString( pf, pv->GetName() )) return false;
|
if (!WriteString(ostr, pv->GetName())) return false;
|
||||||
|
|
||||||
if ( !pv->Save0State(pf) ) return false; // common header
|
if (!pv->Save0State(ostr)) return false; // common header
|
||||||
if ( !pv->Save1State(pf) ) return false; // saves as the child class
|
if (!pv->Save1State(ostr)) return false; // saves as the child class
|
||||||
if ( !WriteWord( pf, 0 ) ) return false;
|
if (!WriteWord(ostr, 0)) return false;
|
||||||
}
|
}
|
||||||
pv = pv->GetNext();
|
pv = pv->GetNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteWord( pf, 0 )) return false;
|
if (!WriteWord(ostr, 0)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteWord( pf, 0 )) return false;
|
if (!WriteWord(ostr, 0)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotClass::RestoreStaticState(FILE* pf)
|
bool CBotClass::RestoreStaticState(std::istream &istr)
|
||||||
{
|
{
|
||||||
std::string ClassName, VarName;
|
std::string ClassName, VarName;
|
||||||
CBotClass* pClass;
|
CBotClass* pClass;
|
||||||
unsigned short w;
|
unsigned short w;
|
||||||
|
|
||||||
if (!ReadWord( pf, w )) return false;
|
long version;
|
||||||
if ( w != CBOTVERSION*2 ) return false;
|
if (!ReadLong(istr, version)) return false;
|
||||||
|
if (version != CBOTVERSION*2) return false;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!ReadWord( pf, w )) return false;
|
if (!ReadWord(istr, w)) return false;
|
||||||
if ( w == 0 ) return true;
|
if ( w == 0 ) return true;
|
||||||
|
|
||||||
if (!ReadString( pf, ClassName )) return false;
|
if (!ReadString(istr, ClassName)) return false;
|
||||||
pClass = Find(ClassName);
|
pClass = Find(ClassName);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!ReadWord( pf, w )) return false;
|
if (!ReadWord(istr, w)) return false;
|
||||||
if ( w == 0 ) break;
|
if ( w == 0 ) break;
|
||||||
|
|
||||||
CBotVar* pVar = nullptr;
|
CBotVar* pVar = nullptr;
|
||||||
CBotVar* pv = nullptr;
|
CBotVar* pv = nullptr;
|
||||||
|
|
||||||
if (!ReadString( pf, VarName )) return false;
|
if (!ReadString(istr, VarName)) return false;
|
||||||
if ( pClass != nullptr ) pVar = pClass->GetItem(VarName);
|
if ( pClass != nullptr ) pVar = pClass->GetItem(VarName);
|
||||||
|
|
||||||
if (!CBotVar::RestoreState(pf, pv)) return false; // the temp variable
|
if (!CBotVar::RestoreState(istr, pv)) return false; // the temp variable
|
||||||
|
|
||||||
if ( pVar != nullptr ) pVar->Copy(pv);
|
if ( pVar != nullptr ) pVar->Copy(pv);
|
||||||
delete pv;
|
delete pv;
|
||||||
|
|
|
@ -331,18 +331,18 @@ public:
|
||||||
static void ClearPublic();
|
static void ClearPublic();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief SaveStaticState
|
* \brief Save all static variables from each public class
|
||||||
* \param pf
|
* \param ostr Output stream
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
static bool SaveStaticState(FILE* pf);
|
static bool SaveStaticState(std::ostream &ostr);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief RestoreStaticState
|
* \brief Restore all static variables in each public class
|
||||||
* \param pf
|
* \param istr Input stream
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
static bool RestoreStaticState(FILE* pf);
|
static bool RestoreStaticState(std::istream &istr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Request a lock on this class (for "synchronized" keyword)
|
* \brief Request a lock on this class (for "synchronized" keyword)
|
||||||
|
|
|
@ -173,14 +173,34 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
|
||||||
{
|
{
|
||||||
switch (p->m_type.GetType())
|
switch (p->m_type.GetType())
|
||||||
{
|
{
|
||||||
|
case CBotTypByte:
|
||||||
|
newvar->SetValByte(pVar->GetValByte());
|
||||||
|
newvar->SetInit(pVar->GetInit()); // copy nan
|
||||||
|
break;
|
||||||
|
case CBotTypShort:
|
||||||
|
newvar->SetValShort(pVar->GetValShort());
|
||||||
|
newvar->SetInit(pVar->GetInit()); // copy nan
|
||||||
|
break;
|
||||||
|
case CBotTypChar:
|
||||||
|
newvar->SetValChar(pVar->GetValChar());
|
||||||
|
newvar->SetInit(pVar->GetInit()); // copy nan
|
||||||
|
break;
|
||||||
case CBotTypInt:
|
case CBotTypInt:
|
||||||
newvar->SetValInt(pVar->GetValInt());
|
newvar->SetValInt(pVar->GetValInt());
|
||||||
newvar->SetInit(pVar->GetInit()); // copy nan
|
newvar->SetInit(pVar->GetInit()); // copy nan
|
||||||
break;
|
break;
|
||||||
|
case CBotTypLong:
|
||||||
|
newvar->SetValLong(pVar->GetValLong());
|
||||||
|
newvar->SetInit(pVar->GetInit()); // copy nan
|
||||||
|
break;
|
||||||
case CBotTypFloat:
|
case CBotTypFloat:
|
||||||
newvar->SetValFloat(pVar->GetValFloat());
|
newvar->SetValFloat(pVar->GetValFloat());
|
||||||
newvar->SetInit(pVar->GetInit()); // copy nan
|
newvar->SetInit(pVar->GetInit()); // copy nan
|
||||||
break;
|
break;
|
||||||
|
case CBotTypDouble:
|
||||||
|
newvar->SetValDouble(pVar->GetValDouble());
|
||||||
|
newvar->SetInit(pVar->GetInit()); // copy nan
|
||||||
|
break;
|
||||||
case CBotTypString:
|
case CBotTypString:
|
||||||
newvar->SetValString(pVar->GetValString());
|
newvar->SetValString(pVar->GetValString());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -35,13 +35,13 @@ namespace CBot
|
||||||
enum CBotType
|
enum CBotType
|
||||||
{
|
{
|
||||||
CBotTypVoid = 0, //!< void
|
CBotTypVoid = 0, //!< void
|
||||||
CBotTypByte = 1, //!< byte (NOT IMPLEMENTED)
|
CBotTypByte = 1, //!< byte
|
||||||
CBotTypShort = 2, //!< short (NOT IMPLEMENTED)
|
CBotTypShort = 2, //!< short
|
||||||
CBotTypChar = 3, //!< char (NOT IMPLEMENTED)
|
CBotTypChar = 3, //!< char
|
||||||
CBotTypInt = 4, //!< int
|
CBotTypInt = 4, //!< int
|
||||||
CBotTypLong = 5, //!< long (NOT IMPLEMENTED)
|
CBotTypLong = 5, //!< long
|
||||||
CBotTypFloat = 6, //!< float
|
CBotTypFloat = 6, //!< float
|
||||||
CBotTypDouble = 7, //!< double (NOT IMPLEMENTED)
|
CBotTypDouble = 7, //!< double
|
||||||
CBotTypBoolean = 8, //!< bool
|
CBotTypBoolean = 8, //!< bool
|
||||||
CBotTypString = 9, //!< string
|
CBotTypString = 9, //!< string
|
||||||
|
|
||||||
|
@ -106,6 +106,11 @@ enum TokenId
|
||||||
ID_STRING,
|
ID_STRING,
|
||||||
ID_VOID,
|
ID_VOID,
|
||||||
ID_BOOL,
|
ID_BOOL,
|
||||||
|
ID_BYTE,
|
||||||
|
ID_SHORT,
|
||||||
|
ID_CHAR,
|
||||||
|
ID_LONG,
|
||||||
|
ID_DOUBLE,
|
||||||
|
|
||||||
TokenKeyVal = 2200, //!< keywords that represent values (true, false, null, nan)
|
TokenKeyVal = 2200, //!< keywords that represent values (true, false, null, nan)
|
||||||
ID_TRUE = 2200,
|
ID_TRUE = 2200,
|
||||||
|
@ -177,7 +182,8 @@ enum TokenType
|
||||||
TokenTypNum = 2, //!< number
|
TokenTypNum = 2, //!< number
|
||||||
TokenTypString = 3, //!< string
|
TokenTypString = 3, //!< string
|
||||||
TokenTypVar = 4, //!< a variable name
|
TokenTypVar = 4, //!< a variable name
|
||||||
TokenTypDef = 5 //!< value according DefineNum
|
TokenTypDef = 5, //!< value according DefineNum
|
||||||
|
TokenTypChar = 6, //!< character literal
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -247,6 +253,8 @@ enum CBotError : int
|
||||||
CBotErrHexDigits = 5052, //!< missing hex digits after escape sequence
|
CBotErrHexDigits = 5052, //!< missing hex digits after escape sequence
|
||||||
CBotErrHexRange = 5053, //!< hex value out of range
|
CBotErrHexRange = 5053, //!< hex value out of range
|
||||||
CBotErrUnicodeName = 5054, //!< invalid universal character name
|
CBotErrUnicodeName = 5054, //!< invalid universal character name
|
||||||
|
CBotErrCharEmpty = 5055, //!< empty character constant
|
||||||
|
CBotErrRedefCase = 5056, //!< duplicate label in switch
|
||||||
|
|
||||||
// Runtime errors
|
// Runtime errors
|
||||||
CBotErrZeroDiv = 6000, //!< division by zero
|
CBotErrZeroDiv = 6000, //!< division by zero
|
||||||
|
|
|
@ -21,129 +21,261 @@
|
||||||
|
|
||||||
#include "CBot/CBotClass.h"
|
#include "CBot/CBotClass.h"
|
||||||
#include "CBot/CBotEnums.h"
|
#include "CBot/CBotEnums.h"
|
||||||
#include "CBot/CBotUtils.h"
|
|
||||||
|
|
||||||
namespace CBot
|
namespace CBot
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
// file management
|
static bool WriteBinary(std::ostream &ostr, T value, unsigned padTo = 0)
|
||||||
|
|
||||||
// necessary because it is not possible to do the fopen in the main program
|
|
||||||
// fwrite and fread in a dll or using the FILE * returned.
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
FILE* fOpen(const char* name, const char* mode)
|
|
||||||
{
|
{
|
||||||
return fopen(name, mode);
|
unsigned char chr;
|
||||||
}
|
unsigned count = 1;
|
||||||
|
while (value > 127) // unsigned LEB128
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
int fClose(FILE* filehandle)
|
|
||||||
{
|
|
||||||
return fclose(filehandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
std::size_t fWrite(const void *buffer,
|
|
||||||
std::size_t elemsize,
|
|
||||||
std::size_t length,
|
|
||||||
FILE* filehandle)
|
|
||||||
{
|
|
||||||
return fwrite(buffer, elemsize, length, filehandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
std::size_t fRead(void *buffer,
|
|
||||||
std::size_t elemsize,
|
|
||||||
std::size_t length,
|
|
||||||
FILE* filehandle)
|
|
||||||
{
|
|
||||||
return fread(buffer, elemsize, length, filehandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ReadWord(FILE* pf, unsigned short& w)
|
|
||||||
{
|
|
||||||
size_t lg;
|
|
||||||
|
|
||||||
lg = fread(&w, sizeof( unsigned short ), 1, pf );
|
|
||||||
|
|
||||||
return (lg == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ReadFloat(FILE* pf, float& w)
|
|
||||||
{
|
|
||||||
size_t lg;
|
|
||||||
|
|
||||||
lg = fread(&w, sizeof( float ), 1, pf );
|
|
||||||
|
|
||||||
return (lg == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool WriteLong(FILE* pf, long w)
|
|
||||||
{
|
|
||||||
size_t lg;
|
|
||||||
|
|
||||||
lg = fwrite(&w, sizeof( long ), 1, pf );
|
|
||||||
|
|
||||||
return (lg == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ReadLong(FILE* pf, long& w)
|
|
||||||
{
|
|
||||||
size_t lg;
|
|
||||||
|
|
||||||
lg = fread(&w, sizeof( long ), 1, pf );
|
|
||||||
|
|
||||||
return (lg == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ReadString(FILE* pf, std::string& s)
|
|
||||||
{
|
|
||||||
unsigned short w;
|
|
||||||
char buf[1000];
|
|
||||||
size_t lg1, lg2;
|
|
||||||
|
|
||||||
if (!ReadWord(pf, w)) return false;
|
|
||||||
lg1 = w;
|
|
||||||
lg2 = fread(buf, 1, lg1, pf );
|
|
||||||
buf[lg2] = 0;
|
|
||||||
|
|
||||||
s = buf;
|
|
||||||
return (lg1 == lg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool WriteType(FILE* pf, const CBotTypResult &type)
|
|
||||||
{
|
|
||||||
int typ = type.GetType();
|
|
||||||
if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
|
|
||||||
if ( !WriteWord(pf, typ) ) return false;
|
|
||||||
if ( typ == CBotTypClass )
|
|
||||||
{
|
{
|
||||||
CBotClass* p = type.GetClass();
|
++count;
|
||||||
if ( !WriteString(pf, p->GetName()) ) return false;
|
chr = (value & 0x7F) | 0x80;
|
||||||
|
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||||
|
value >>= 7;
|
||||||
}
|
}
|
||||||
if ( type.Eq( CBotTypArrayBody ) ||
|
chr = value & 0x7F;
|
||||||
type.Eq( CBotTypArrayPointer ) )
|
if (count < padTo) chr |= 0x80;
|
||||||
|
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||||
|
|
||||||
|
if (count < padTo)
|
||||||
{
|
{
|
||||||
if ( !WriteWord(pf, type.GetLimite()) ) return false;
|
while (++count < padTo)
|
||||||
if ( !WriteType(pf, type.GetTypElem()) ) return false;
|
if (!(ostr << '\x80')) return false;
|
||||||
|
if (!(ostr << '\x00')) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template<typename T>
|
||||||
bool ReadType(FILE* pf, CBotTypResult &type)
|
static bool ReadBinary(std::istream &istr, T &value)
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
unsigned char chr;
|
||||||
|
unsigned shift = 0;
|
||||||
|
while (true) // unsigned LEB128
|
||||||
|
{
|
||||||
|
if (!istr.read(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||||
|
if (shift < sizeof(T) * 8 - 1)
|
||||||
|
value |= static_cast<T>(chr & 0x7F) << shift;
|
||||||
|
shift += 7;
|
||||||
|
if ((chr & 0x80) == 0) break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static bool WriteSignedBinary(std::ostream &ostr, T value, unsigned padTo = 0)
|
||||||
|
{
|
||||||
|
signed char sign = value >> (8 * sizeof(T) - 1);
|
||||||
|
unsigned count = 0;
|
||||||
|
while (true) // signed LEB128
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
unsigned char chr = value & 0x7F;
|
||||||
|
value >>= 7;
|
||||||
|
if (!(value != sign || ((chr ^ sign) & 0x40) != 0))
|
||||||
|
{
|
||||||
|
if (count < padTo) chr |= 0x80;
|
||||||
|
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chr |= 0x80;
|
||||||
|
if (!ostr.put(chr)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < padTo)
|
||||||
|
{
|
||||||
|
char chr = (sign < 0) ? 0x7F : 0x00;
|
||||||
|
while (++count < padTo)
|
||||||
|
if (!ostr.put(chr | 0x80)) return false;
|
||||||
|
if (!ostr.put(chr)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static bool ReadSignedBinary(std::istream &istr, T &value)
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
unsigned char chr;
|
||||||
|
unsigned shift = 0;
|
||||||
|
while (true) // signed LEB128
|
||||||
|
{
|
||||||
|
if (!istr.read(reinterpret_cast<char*>(&chr), 1)) return false;
|
||||||
|
if (shift < sizeof(T) * 8 - 1)
|
||||||
|
value |= (static_cast<T>(chr & 0x7F) << shift);
|
||||||
|
shift += 7;
|
||||||
|
if ((chr & 0x80) == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shift >= 8 * sizeof(T) - 1) shift = 8 * sizeof(T) - 1;
|
||||||
|
if ((chr & 0x40) != 0)
|
||||||
|
value |= static_cast<T>(-1) << shift;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteWord(std::ostream &ostr, unsigned short w)
|
||||||
|
{
|
||||||
|
return WriteBinary<unsigned short>(ostr, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadWord(std::istream &istr, unsigned short &w)
|
||||||
|
{
|
||||||
|
return ReadBinary<unsigned short>(istr, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteByte(std::ostream &ostr, char c)
|
||||||
|
{
|
||||||
|
if (!ostr.put(c)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadByte(std::istream &istr, char& c)
|
||||||
|
{
|
||||||
|
if (!istr.get(c)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteShort(std::ostream &ostr, short s)
|
||||||
|
{
|
||||||
|
return WriteSignedBinary<short>(ostr, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadShort(std::istream &istr, short &s)
|
||||||
|
{
|
||||||
|
return ReadSignedBinary<short>(istr, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteUInt32(std::ostream &ostr, uint32_t i)
|
||||||
|
{
|
||||||
|
return WriteBinary<uint32_t>(ostr, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadUInt32(std::istream &istr, uint32_t &i)
|
||||||
|
{
|
||||||
|
return ReadBinary<uint32_t>(istr, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteInt(std::ostream &ostr, int i)
|
||||||
|
{
|
||||||
|
return WriteSignedBinary<int>(ostr, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadInt(std::istream &istr, int &i)
|
||||||
|
{
|
||||||
|
return ReadSignedBinary<int>(istr, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteLong(std::ostream &ostr, long l, unsigned padTo)
|
||||||
|
{
|
||||||
|
return WriteSignedBinary<long>(ostr, l, padTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadLong(std::istream &istr, long &l)
|
||||||
|
{
|
||||||
|
return ReadSignedBinary<long>(istr, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteFloat(std::ostream &ostr, float f)
|
||||||
|
{
|
||||||
|
union {float fValue; unsigned int iValue;} u;
|
||||||
|
u.fValue = 0.0f;
|
||||||
|
u.iValue = 0;
|
||||||
|
|
||||||
|
u.fValue = f;
|
||||||
|
return WriteBinary<unsigned int>(ostr, u.iValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadFloat(std::istream &istr, float &f)
|
||||||
|
{
|
||||||
|
union {float fValue; unsigned int iValue;} u;
|
||||||
|
u.fValue = 0.0f;
|
||||||
|
u.iValue = 0;
|
||||||
|
|
||||||
|
if (!ReadBinary<unsigned int>(istr, u.iValue)) return false;
|
||||||
|
f = u.fValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteDouble(std::ostream &ostr, double d)
|
||||||
|
{
|
||||||
|
union {double dValue; unsigned long iValue;} u;
|
||||||
|
u.dValue = 0.0;
|
||||||
|
u.iValue = 0;
|
||||||
|
|
||||||
|
u.dValue = d;
|
||||||
|
return WriteBinary<unsigned long>(ostr, u.iValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadDouble(std::istream &istr, double &d)
|
||||||
|
{
|
||||||
|
union {double dValue; unsigned long iValue;} u;
|
||||||
|
u.dValue = 0.0;
|
||||||
|
u.iValue = 0;
|
||||||
|
|
||||||
|
if (!ReadBinary<unsigned long>(istr, u.iValue)) return false;
|
||||||
|
d = u.dValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteString(std::ostream &ostr, const std::string &s)
|
||||||
|
{
|
||||||
|
if (!WriteBinary<size_t>(ostr, s.size())) return false;
|
||||||
|
if (!ostr.write(&(s[0]), s.size())) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadString(std::istream &istr, std::string &s)
|
||||||
|
{
|
||||||
|
size_t length = 0;
|
||||||
|
if (!ReadBinary<size_t>(istr, length)) return false;
|
||||||
|
|
||||||
|
s.resize(length);
|
||||||
|
if (length != 0)
|
||||||
|
{
|
||||||
|
if (!istr.read(&(s[0]), length)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteType(std::ostream &ostr, const CBotTypResult &type)
|
||||||
|
{
|
||||||
|
int typ = type.GetType();
|
||||||
|
if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
|
||||||
|
if ( !WriteWord(ostr, typ) ) return false;
|
||||||
|
if ( typ == CBotTypClass )
|
||||||
|
{
|
||||||
|
CBotClass* p = type.GetClass();
|
||||||
|
if (!WriteString(ostr, p->GetName())) return false;
|
||||||
|
}
|
||||||
|
if ( type.Eq( CBotTypArrayBody ) ||
|
||||||
|
type.Eq( CBotTypArrayPointer ) )
|
||||||
|
{
|
||||||
|
if (!WriteWord(ostr, type.GetLimite())) return false;
|
||||||
|
if (!WriteType(ostr, type.GetTypElem())) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type.Eq(CBotTypPointer) )
|
||||||
|
{
|
||||||
|
if (type.GetClass() != nullptr)
|
||||||
|
{
|
||||||
|
if (!WriteString(ostr, type.GetClass()->GetName())) return false;
|
||||||
|
}
|
||||||
|
else if (!WriteString(ostr, "")) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadType(std::istream &istr, CBotTypResult &type)
|
||||||
{
|
{
|
||||||
unsigned short w, ww;
|
unsigned short w, ww;
|
||||||
if ( !ReadWord(pf, w) ) return false;
|
if (!ReadWord(istr, w)) return false;
|
||||||
type.SetType(w);
|
type.SetType(w);
|
||||||
|
|
||||||
if ( type.Eq( CBotTypIntrinsic ) )
|
if ( type.Eq( CBotTypIntrinsic ) )
|
||||||
|
@ -154,7 +286,7 @@ bool ReadType(FILE* pf, CBotTypResult &type)
|
||||||
if ( type.Eq( CBotTypClass ) )
|
if ( type.Eq( CBotTypClass ) )
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
if ( !ReadString(pf, s) ) return false;
|
if (!ReadString(istr, s)) return false;
|
||||||
type = CBotTypResult( w, s );
|
type = CBotTypResult( w, s );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,11 +294,45 @@ bool ReadType(FILE* pf, CBotTypResult &type)
|
||||||
type.Eq( CBotTypArrayBody ) )
|
type.Eq( CBotTypArrayBody ) )
|
||||||
{
|
{
|
||||||
CBotTypResult r;
|
CBotTypResult r;
|
||||||
if ( !ReadWord(pf, ww) ) return false;
|
if (!ReadWord(istr, ww)) return false;
|
||||||
if ( !ReadType(pf, r) ) return false;
|
if (!ReadType(istr, r)) return false;
|
||||||
type = CBotTypResult( w, r );
|
type = CBotTypResult( w, r );
|
||||||
type.SetLimite(static_cast<short>(ww));
|
type.SetLimite(static_cast<short>(ww));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( type.Eq(CBotTypPointer) )
|
||||||
|
{
|
||||||
|
std::string className;
|
||||||
|
if (!ReadString(istr, className)) return false;
|
||||||
|
type = CBotTypResult(w, className);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteStream(std::ostream &ostr, std::istream& istr)
|
||||||
|
{
|
||||||
|
if (!istr.seekg(0, istr.end)) return false;
|
||||||
|
auto size = istr.tellg();
|
||||||
|
|
||||||
|
if (size == 0) return WriteLong(ostr, 0);
|
||||||
|
if (!WriteLong(ostr, size)) return false;
|
||||||
|
|
||||||
|
if (!istr.seekg(0, istr.beg)) return false;
|
||||||
|
if (!(ostr << istr.rdbuf())) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadStream(std::istream& istr, std::ostream &ostr)
|
||||||
|
{
|
||||||
|
long length;
|
||||||
|
if (!ReadLong(istr, length)) return false;
|
||||||
|
if (length == 0) return true;
|
||||||
|
|
||||||
|
while (length-- > 0)
|
||||||
|
{
|
||||||
|
if (!(ostr << istr.get())) return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdio>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace CBot
|
namespace CBot
|
||||||
|
@ -28,128 +28,189 @@ namespace CBot
|
||||||
class CBotVar;
|
class CBotVar;
|
||||||
class CBotTypResult;
|
class CBotTypResult;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// routines for file management (* FILE)
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief fOpen
|
* \brief Save a linked list if variables
|
||||||
* \param name
|
* \param ostr Output stream
|
||||||
* \param mode
|
* \param pVar First variable in the list
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
FILE* fOpen(const char* name, const char* mode);
|
bool SaveVars(std::ostream &ostr, CBotVar* pVar);
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief fClose
|
|
||||||
* \param filehandle
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
int fClose(FILE* filehandle);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief fWrite
|
|
||||||
* \param buffer
|
|
||||||
* \param elemsize
|
|
||||||
* \param length
|
|
||||||
* \param filehandle
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
std::size_t fWrite(const void *buffer,
|
|
||||||
std::size_t elemsize,
|
|
||||||
std::size_t length,
|
|
||||||
FILE* filehandle);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief fRead
|
|
||||||
* \param buffer
|
|
||||||
* \param elemsize
|
|
||||||
* \param length
|
|
||||||
* \param filehandle
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
std::size_t fRead(void *buffer,
|
|
||||||
std::size_t elemsize,
|
|
||||||
std::size_t length,
|
|
||||||
FILE* filehandle);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief SaveVars
|
|
||||||
* \param pf
|
|
||||||
* \param pVar
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
bool SaveVars(FILE* pf, CBotVar* pVar);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief WriteWord
|
* \brief WriteWord
|
||||||
* \param pf
|
* \param ostr Output stream
|
||||||
* \param w
|
* \param w
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool WriteWord(FILE* pf, unsigned short w);
|
bool WriteWord(std::ostream &ostr, unsigned short w);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief ReadWord
|
* \brief ReadWord
|
||||||
* \param pf
|
* \param istr Input stream
|
||||||
* \param w
|
* \param[out] w
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool ReadWord(FILE* pf, unsigned short& w);
|
bool ReadWord(std::istream &istr, unsigned short &w);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief ReadLong
|
* \brief WriteByte
|
||||||
* \param pf
|
* \param ostr Output stream
|
||||||
* \param w
|
* \param c
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool ReadLong(FILE* pf, long& w);
|
bool WriteByte(std::ostream &ostr, char c);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief WriteFloat
|
* \brief ReadByte
|
||||||
* \param pf
|
* \param istr Input stream
|
||||||
* \param w
|
* \param[out] c
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool WriteFloat(FILE* pf, float w);
|
bool ReadByte(std::istream &istr, char& c);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief WriteShort
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \param s
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool WriteShort(std::ostream &ostr, short s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ReadShort
|
||||||
|
* \param istr Input stream
|
||||||
|
* \param[out] s
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool ReadShort(std::istream &istr, short &s);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief WriteUInt32
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \param i
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool WriteUInt32(std::ostream &ostr, uint32_t i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ReadUInt32
|
||||||
|
* \param istr Input stream
|
||||||
|
* \param[out] i
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool ReadUInt32(std::istream &istr, uint32_t &i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief WriteInt
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \param i
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool WriteInt(std::ostream &ostr, int i);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ReadInt
|
||||||
|
* \param istr Input stream
|
||||||
|
* \param[out] i
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool ReadInt(std::istream &istr, int &i);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief WriteLong
|
* \brief WriteLong
|
||||||
* \param pf
|
* \param ostr Output stream
|
||||||
* \param w
|
* \param l
|
||||||
* \return
|
* \param padTo minimum number of bytes to write
|
||||||
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool WriteLong(FILE* pf, long w);
|
bool WriteLong(std::ostream &ostr, long l, unsigned padTo = 0);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ReadLong
|
||||||
|
* \param istr Input stream
|
||||||
|
* \param[out] l
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool ReadLong(std::istream &istr, long &l);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief WriteFloat
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \param f
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool WriteFloat(std::ostream &ostr, float f);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief ReadFloat
|
* \brief ReadFloat
|
||||||
* \param pf
|
* \param istr Input stream
|
||||||
* \param w
|
* \param[out] f
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool ReadFloat(FILE* pf, float& w);
|
bool ReadFloat(std::istream &istr, float &f);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief WriteDouble
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \param d
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool WriteDouble(std::ostream &ostr, double d);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ReadDouble
|
||||||
|
* \param istr Input stream
|
||||||
|
* \param[out] d
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool ReadDouble(std::istream &istr, double &d);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief WriteString
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \param s
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool WriteString(std::ostream &ostr, const std::string &s);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief ReadString
|
* \brief ReadString
|
||||||
* \param pf
|
* \param istr Input stream
|
||||||
* \param s
|
* \param[out] s
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool ReadString(FILE* pf, std::string& s);
|
bool ReadString(std::istream &istr, std::string &s);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief WriteType
|
* \brief WriteType
|
||||||
* \param pf
|
* \param ostr Output stream
|
||||||
* \param type
|
* \param type
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool WriteType(FILE* pf, const CBotTypResult &type);
|
bool WriteType(std::ostream &ostr, const CBotTypResult &type);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief ReadType
|
* \brief ReadType
|
||||||
* \param pf
|
* \param istr Input stream
|
||||||
* \param type
|
* \param[out] type
|
||||||
* \return
|
* \return true on success
|
||||||
*/
|
*/
|
||||||
bool ReadType(FILE* pf, CBotTypResult &type);
|
bool ReadType(std::istream &istr, CBotTypResult &type);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief WriteStream
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \param istr Input stream
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool WriteStream(std::ostream &ostr, std::istream& istr);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief ReadStream
|
||||||
|
* \param istr Input stream
|
||||||
|
* \param ostr Output stream
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool ReadStream(std::istream& istr, std::ostream &ostr);
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotCase.h"
|
#include "CBot/CBotInstr/CBotCase.h"
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotExprLitNum.h"
|
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
|
||||||
|
|
||||||
#include "CBot/CBotStack.h"
|
#include "CBot/CBotStack.h"
|
||||||
#include "CBot/CBotCStack.h"
|
#include "CBot/CBotCStack.h"
|
||||||
|
@ -30,69 +30,107 @@ namespace CBot
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CBotCase::CBotCase()
|
CBotCase::CBotCase()
|
||||||
{
|
{
|
||||||
m_value = nullptr;
|
m_instr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CBotCase::~CBotCase()
|
CBotCase::~CBotCase()
|
||||||
{
|
{
|
||||||
delete m_value;
|
delete m_instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map<long, CBotInstr*>& labels)
|
||||||
CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
||||||
{
|
{
|
||||||
CBotCase* inst = new CBotCase(); // creates the object
|
|
||||||
CBotToken* pp = p; // preserves at the ^ token (starting position)
|
CBotToken* pp = p; // preserves at the ^ token (starting position)
|
||||||
|
|
||||||
inst->SetToken(p);
|
|
||||||
if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return nullptr; // should never happen
|
if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return nullptr; // should never happen
|
||||||
|
pStack->SetStartError(pp->GetStart());
|
||||||
|
|
||||||
if ( pp->GetType() == ID_CASE )
|
long labelValue = 0;
|
||||||
|
|
||||||
|
if (pp->GetType() == ID_CASE)
|
||||||
{
|
{
|
||||||
pp = p;
|
CBotInstr* i = nullptr;
|
||||||
inst->m_value = CBotExprLitNum::Compile(p, pStack);
|
if (nullptr != (i = CBotTwoOpExpr::Compile(p, pStack, nullptr, true)))
|
||||||
if (inst->m_value == nullptr )
|
|
||||||
{
|
{
|
||||||
pStack->SetError( CBotErrBadNum, pp );
|
if (pStack->GetType() <= CBotTypLong)
|
||||||
delete inst;
|
{
|
||||||
return nullptr;
|
CBotStack* pile = CBotStack::AllocateStack();
|
||||||
|
while ( !i->Execute(pile) );
|
||||||
|
labelValue = pile->GetVar()->GetValLong();
|
||||||
|
pile->Delete();
|
||||||
|
|
||||||
|
if (labels.count(labelValue) > 0)
|
||||||
|
{
|
||||||
|
pStack->SetError(CBotErrRedefCase, p->GetStart());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pStack->SetError(CBotErrBadNum, p->GetStart());
|
||||||
|
delete i;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
if ( !IsOfType( p, ID_DOTS ))
|
pStack->SetError(CBotErrBadNum, p->GetStart());
|
||||||
{
|
|
||||||
pStack->SetError( CBotErrNoDoubleDots, p->GetStart() );
|
|
||||||
delete inst;
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return inst;
|
if (pStack->IsOk() && IsOfType(p, ID_DOTS))
|
||||||
|
{
|
||||||
|
CBotCase* newCase = new CBotCase();
|
||||||
|
newCase->SetToken(pp);
|
||||||
|
if (pp->GetType() == ID_CASE)
|
||||||
|
labels[labelValue] = newCase;
|
||||||
|
return newCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
pStack->SetError(CBotErrNoDoubleDots, p->GetStart());
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotCase::Execute(CBotStack* &pj)
|
bool CBotCase::Execute(CBotStack* &pj)
|
||||||
{
|
{
|
||||||
return true; // the "case" statement does nothing!
|
if (m_instr == nullptr) return true;
|
||||||
|
CBotStack* pile = pj->AddStack(this, CBotStack::BlockVisibilityType::BLOCK);
|
||||||
|
|
||||||
|
int state = pile->GetState();
|
||||||
|
CBotInstr* p = m_instr;
|
||||||
|
while (state-- > 0) p = p->GetNext();
|
||||||
|
|
||||||
|
while (p != nullptr)
|
||||||
|
{
|
||||||
|
if (!p->Execute(pile)) return false;
|
||||||
|
pile->IncState();
|
||||||
|
p = p->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
pile->Delete();
|
||||||
|
return pj->IsOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
|
void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
|
||||||
{
|
{
|
||||||
}
|
if (!bMain) return;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
CBotStack* pile = pj->RestoreStack(this);
|
||||||
bool CBotCase::CompCase(CBotStack* &pile, int val)
|
if (pile == nullptr) return;
|
||||||
{
|
|
||||||
if (m_value == nullptr ) return true; // "default" case
|
|
||||||
|
|
||||||
while (!m_value->Execute(pile)); // puts the value on the correspondent stack (without interruption)
|
CBotInstr* p = m_instr;
|
||||||
return (pile->GetVal() == val); // compared with the given value
|
|
||||||
|
int state = pile->GetState();
|
||||||
|
while (p != nullptr && state-- > 0)
|
||||||
|
{
|
||||||
|
p->RestoreState(pile, bMain);
|
||||||
|
p = p->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p != nullptr) p->RestoreState(pile, bMain);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, CBotInstr*> CBotCase::GetDebugLinks()
|
std::map<std::string, CBotInstr*> CBotCase::GetDebugLinks()
|
||||||
{
|
{
|
||||||
auto links = CBotInstr::GetDebugLinks();
|
auto links = CBotInstr::GetDebugLinks();
|
||||||
links["m_value"] = m_value;
|
links["m_instr"] = m_instr;
|
||||||
return links;
|
return links;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotInstr.h"
|
#include "CBot/CBotInstr/CBotInstr.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace CBot
|
namespace CBot
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@ public:
|
||||||
* \param pStack
|
* \param pStack
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map<long, CBotInstr*>& labels);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Execute Execution of instruction "case".
|
* \brief Execute Execution of instruction "case".
|
||||||
|
@ -58,22 +60,15 @@ public:
|
||||||
*/
|
*/
|
||||||
void RestoreState(CBotStack* &pj, bool bMain) override;
|
void RestoreState(CBotStack* &pj, bool bMain) override;
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief CompCase Routine to find the entry point of "case" corresponding
|
|
||||||
* to the value seen.
|
|
||||||
* \param pj
|
|
||||||
* \param val
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
bool CompCase(CBotStack* &pj, int val) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const std::string GetDebugName() override { return "CBotCase"; }
|
virtual const std::string GetDebugName() override { return "CBotCase"; }
|
||||||
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;
|
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Value to compare.
|
//! List of instructions after case label
|
||||||
CBotInstr* m_value;
|
CBotInstr* m_instr;
|
||||||
|
|
||||||
|
friend class CBotSwitch;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -46,13 +46,22 @@ CBotDefFloat::~CBotDefFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
|
CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip, CBotTypResult vartype)
|
||||||
{
|
{
|
||||||
CBotToken* pp = cont ? nullptr : p;
|
CBotToken* pp = cont ? nullptr : p;
|
||||||
|
|
||||||
if (!cont && !IsOfType(p, ID_FLOAT)) return nullptr;
|
if (!cont)
|
||||||
|
{
|
||||||
|
switch (p->GetType())
|
||||||
|
{
|
||||||
|
case ID_FLOAT: vartype.SetType(CBotTypFloat ); break;
|
||||||
|
case ID_DOUBLE: vartype.SetType(CBotTypDouble); break;
|
||||||
|
default: return nullptr;
|
||||||
|
}
|
||||||
|
p = p->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
CBotDefFloat* inst = static_cast<CBotDefFloat*>(CompileArray(p, pStack, CBotTypFloat));
|
CBotDefFloat* inst = static_cast<CBotDefFloat*>(CompileArray(p, pStack, vartype));
|
||||||
if (inst != nullptr || !pStack->IsOk()) return inst;
|
if (inst != nullptr || !pStack->IsOk()) return inst;
|
||||||
|
|
||||||
CBotCStack* pStk = pStack->TokenStack(pp);
|
CBotCStack* pStk = pStack->TokenStack(pp);
|
||||||
|
@ -67,7 +76,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b
|
||||||
|
|
||||||
if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
|
if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
|
||||||
{
|
{
|
||||||
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_typevar = CBotTypFloat;
|
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_typevar = vartype;
|
||||||
if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable
|
if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable
|
||||||
{
|
{
|
||||||
pStk->SetStartError(vartoken->GetStart());
|
pStk->SetStartError(vartoken->GetStart());
|
||||||
|
@ -79,7 +88,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b
|
||||||
{
|
{
|
||||||
delete inst;
|
delete inst;
|
||||||
p = vartoken;
|
p = vartoken;
|
||||||
inst = static_cast<CBotDefFloat*>(CBotDefArray::Compile(p, pStk, CBotTypFloat));
|
inst = static_cast<CBotDefFloat*>(CBotDefArray::Compile(p, pStk, vartype));
|
||||||
|
|
||||||
goto suite; // no assignment, variable already created
|
goto suite; // no assignment, variable already created
|
||||||
}
|
}
|
||||||
|
@ -103,7 +112,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var = CBotVar::Create(*vartoken, CBotTypFloat);
|
var = CBotVar::Create(*vartoken, vartype);
|
||||||
var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF);
|
var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF);
|
||||||
var->SetUniqNum(
|
var->SetUniqNum(
|
||||||
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
|
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
|
||||||
|
@ -111,7 +120,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b
|
||||||
suite:
|
suite:
|
||||||
if (pStk->IsOk() && IsOfType(p, ID_COMMA))
|
if (pStk->IsOk() && IsOfType(p, ID_COMMA))
|
||||||
{
|
{
|
||||||
if (nullptr != ( inst->m_next2b = CBotDefFloat::Compile(p, pStk, true, noskip)))
|
if (nullptr != ( inst->m_next2b = CBotDefFloat::Compile(p, pStk, true, noskip, vartype)))
|
||||||
{
|
{
|
||||||
return pStack->Return(inst, pStk);
|
return pStack->Return(inst, pStk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ public:
|
||||||
* \param noskip
|
* \param noskip
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false, CBotTypResult vartype = CBotTypFloat);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Execute Executes the definition of a real variable.
|
* \brief Execute Executes the definition of a real variable.
|
||||||
|
|
|
@ -47,13 +47,25 @@ CBotDefInt::~CBotDefInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
|
CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip, CBotTypResult vartype)
|
||||||
{
|
{
|
||||||
CBotToken* pp = cont ? nullptr : p; // no repetition of the token "int"
|
CBotToken* pp = cont ? nullptr : p; // no repetition of the token "int"
|
||||||
|
|
||||||
if (!cont && !IsOfType(p, ID_INT)) return nullptr;
|
if (!cont)
|
||||||
|
{
|
||||||
|
switch (p->GetType())
|
||||||
|
{
|
||||||
|
case ID_BYTE: vartype.SetType(CBotTypByte ); break;
|
||||||
|
case ID_SHORT: vartype.SetType(CBotTypShort); break;
|
||||||
|
case ID_CHAR: vartype.SetType(CBotTypChar ); break;
|
||||||
|
case ID_INT: vartype.SetType(CBotTypInt ); break;
|
||||||
|
case ID_LONG: vartype.SetType(CBotTypLong ); break;
|
||||||
|
default: return nullptr;
|
||||||
|
}
|
||||||
|
p = p->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
CBotDefInt* inst = static_cast<CBotDefInt*>(CompileArray(p, pStack, CBotTypInt));
|
CBotDefInt* inst = static_cast<CBotDefInt*>(CompileArray(p, pStack, vartype));
|
||||||
if (inst != nullptr || !pStack->IsOk()) return inst;
|
if (inst != nullptr || !pStack->IsOk()) return inst;
|
||||||
|
|
||||||
CBotCStack* pStk = pStack->TokenStack(pp);
|
CBotCStack* pStk = pStack->TokenStack(pp);
|
||||||
|
@ -68,7 +80,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo
|
||||||
// determines the expression is valid for the item on the left side
|
// determines the expression is valid for the item on the left side
|
||||||
if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
|
if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
|
||||||
{
|
{
|
||||||
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_typevar = CBotTypInt;
|
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_typevar = vartype;
|
||||||
if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable
|
if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable
|
||||||
{
|
{
|
||||||
pStk->SetError(CBotErrRedefVar, vartoken);
|
pStk->SetError(CBotErrRedefVar, vartoken);
|
||||||
|
@ -82,7 +94,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo
|
||||||
|
|
||||||
// compiles an array declaration
|
// compiles an array declaration
|
||||||
|
|
||||||
CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypInt);
|
CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, vartype);
|
||||||
|
|
||||||
inst = static_cast<CBotDefInt*>(inst2);
|
inst = static_cast<CBotDefInt*>(inst2);
|
||||||
goto suite; // no assignment, variable already created
|
goto suite; // no assignment, variable already created
|
||||||
|
@ -108,7 +120,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CBotVar* var = CBotVar::Create(*vartoken, CBotTypInt);// create the variable (evaluated after the assignment)
|
CBotVar* var = CBotVar::Create(*vartoken, vartype); // create the variable (evaluated after the assignment)
|
||||||
var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF); // if initialized with assignment
|
var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF); // if initialized with assignment
|
||||||
var->SetUniqNum( //set it with a unique number
|
var->SetUniqNum( //set it with a unique number
|
||||||
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
|
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
|
||||||
|
@ -117,7 +129,7 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo
|
||||||
suite:
|
suite:
|
||||||
if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // chained several definitions
|
if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // chained several definitions
|
||||||
{
|
{
|
||||||
if (nullptr != ( inst->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip))) // compile next one
|
if (nullptr != ( inst->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip, vartype))) // compile next one
|
||||||
{
|
{
|
||||||
return pStack->Return(inst, pStk);
|
return pStack->Return(inst, pStk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ public:
|
||||||
* \param noskip
|
* \param noskip
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false);
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false, CBotTypResult vartype = CBotTypInt);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Execute Execute the definition of the integer variable.
|
* \brief Execute Execute the definition of the integer variable.
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CBot/CBotInstr/CBotExprLitChar.h"
|
||||||
|
|
||||||
|
#include "CBot/CBotStack.h"
|
||||||
|
#include "CBot/CBotCStack.h"
|
||||||
|
|
||||||
|
#include "CBot/CBotVar/CBotVar.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
CBotExprLitChar::CBotExprLitChar()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CBotExprLitChar::~CBotExprLitChar()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CBotInstr* CBotExprLitChar::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
|
{
|
||||||
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
|
||||||
|
const auto& s = p->GetString();
|
||||||
|
|
||||||
|
auto it = s.cbegin();
|
||||||
|
if (++it != s.cend())
|
||||||
|
{
|
||||||
|
if (*it != '\'') // not empty quotes ?
|
||||||
|
{
|
||||||
|
uint32_t valchar = 0;
|
||||||
|
int pos = p->GetStart() + 1;
|
||||||
|
|
||||||
|
if (*it != '\\') valchar = *(it++); // not escape sequence ?
|
||||||
|
else if (++it != s.cend())
|
||||||
|
{
|
||||||
|
pStk->SetStartError(pos++);
|
||||||
|
unsigned char c = *(it++);
|
||||||
|
if (c == '\"' || c == '\'' || c == '\\') valchar = c;
|
||||||
|
else if (c == 'a') valchar = '\a'; // alert bell
|
||||||
|
else if (c == 'b') valchar = '\b'; // backspace
|
||||||
|
else if (c == 'f') valchar = '\f'; // form feed
|
||||||
|
else if (c == 'n') valchar = '\n'; // new line
|
||||||
|
else if (c == 'r') valchar = '\r'; // carriage return
|
||||||
|
else if (c == 't') valchar = '\t'; // horizontal tab
|
||||||
|
else if (c == 'v') valchar = '\v'; // vertical tab
|
||||||
|
else if (c == 'u' || c == 'U') // unicode escape
|
||||||
|
{
|
||||||
|
if (it != s.cend())
|
||||||
|
{
|
||||||
|
std::string hex = "";
|
||||||
|
size_t maxlen = (c == 'u') ? 4 : 8;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < maxlen; i++)
|
||||||
|
{
|
||||||
|
if (!CharInList(*it, "0123456789ABCDEFabcdef")) break;
|
||||||
|
++pos;
|
||||||
|
hex += *it;
|
||||||
|
if (++it == s.cend()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxlen == hex.length()) // unicode character
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
valchar = std::stoi(hex, nullptr, 16);
|
||||||
|
if (0x10FFFF < valchar || (0xD7FF < valchar && valchar < 0xE000))
|
||||||
|
pStk->SetError(CBotErrUnicodeName, pos + 1);
|
||||||
|
}
|
||||||
|
catch (const std::out_of_range& e)
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrHexRange, pos + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pStk->SetError(CBotErrHexDigits, pos + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pStk->SetError(CBotErrHexDigits, pos + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pStk->SetError(CBotErrBadEscape, pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it == s.cend() || *it != '\'')
|
||||||
|
pStk->SetError(CBotErrEndQuote, p);
|
||||||
|
|
||||||
|
if (pStk->IsOk())
|
||||||
|
{
|
||||||
|
CBotExprLitChar* inst = new CBotExprLitChar();
|
||||||
|
inst->m_valchar = valchar;
|
||||||
|
inst->SetToken(p);
|
||||||
|
p = p->GetNext();
|
||||||
|
|
||||||
|
CBotVar* var = CBotVar::Create("", CBotTypChar);
|
||||||
|
pStk->SetVar(var);
|
||||||
|
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pStk->SetError(CBotErrCharEmpty, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
pStk->SetError(CBotErrEndQuote, p);
|
||||||
|
return pStack->Return(nullptr, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBotExprLitChar::Execute(CBotStack* &pj)
|
||||||
|
{
|
||||||
|
CBotStack* pile = pj->AddStack(this);
|
||||||
|
|
||||||
|
if (pile->IfStep()) return false;
|
||||||
|
|
||||||
|
CBotVar* var = CBotVar::Create("", CBotTypChar);
|
||||||
|
|
||||||
|
var->SetValChar(m_valchar);
|
||||||
|
|
||||||
|
pile->SetVar(var);
|
||||||
|
|
||||||
|
return pj->Return(pile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBotExprLitChar::RestoreState(CBotStack* &pj, bool bMain)
|
||||||
|
{
|
||||||
|
if (bMain) pj->RestoreStack(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CBotExprLitChar::GetDebugData()
|
||||||
|
{
|
||||||
|
return m_token.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CBot/CBotInstr/CBotInstr.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A character literal
|
||||||
|
* \verbatim 'a', '\n', '\t', '\uFFFD', '\U0000FFFD', etc. \endverbatim
|
||||||
|
*/
|
||||||
|
class CBotExprLitChar : public CBotInstr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotExprLitChar();
|
||||||
|
~CBotExprLitChar();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Compile a character literal
|
||||||
|
*/
|
||||||
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Execute, returns the corresponding char.
|
||||||
|
*/
|
||||||
|
bool Execute(CBotStack* &pj) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief RestoreState
|
||||||
|
*/
|
||||||
|
void RestoreState(CBotStack* &pj, bool bMain) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual const std::string GetDebugName() override { return "CBotExprLitChar"; }
|
||||||
|
virtual std::string GetDebugData() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t m_valchar = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -25,52 +25,85 @@
|
||||||
|
|
||||||
#include "CBot/CBotUtils.h"
|
#include "CBot/CBotUtils.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace CBot
|
namespace CBot
|
||||||
{
|
{
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template <>
|
||||||
CBotExprLitNum::CBotExprLitNum()
|
CBotExprLitNum<int>::CBotExprLitNum(int val) : m_numtype(CBotTypInt), m_value(val)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template <>
|
||||||
CBotExprLitNum::~CBotExprLitNum()
|
CBotExprLitNum<long>::CBotExprLitNum(long val) : m_numtype(CBotTypLong), m_value(val)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template <>
|
||||||
CBotInstr* CBotExprLitNum::Compile(CBotToken* &p, CBotCStack* pStack)
|
CBotExprLitNum<float>::CBotExprLitNum(float val) : m_numtype(CBotTypFloat), m_value(val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
CBotExprLitNum<double>::CBotExprLitNum(double val) : m_numtype(CBotTypDouble), m_value(val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
CBotExprLitNum<T>::~CBotExprLitNum()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CBotInstr* CompileExprLitNum(CBotToken* &p, CBotCStack* pStack)
|
||||||
{
|
{
|
||||||
CBotCStack* pStk = pStack->TokenStack();
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
|
||||||
CBotExprLitNum* inst = new CBotExprLitNum();
|
const auto& s = p->GetString();
|
||||||
|
|
||||||
inst->SetToken(p);
|
CBotInstr* inst = nullptr;
|
||||||
std::string s = p->GetString();
|
CBotType numtype = CBotTypInt;
|
||||||
|
|
||||||
inst->m_numtype = CBotTypInt;
|
|
||||||
if (p->GetType() == TokenTypDef)
|
if (p->GetType() == TokenTypDef)
|
||||||
{
|
{
|
||||||
inst->m_valint = p->GetKeywordId();
|
inst = new CBotExprLitNum<int>(static_cast<int>(p->GetKeywordId()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (s.find('.') != std::string::npos || ( s.find('x') == std::string::npos && ( s.find_first_of("eE") != std::string::npos ) ))
|
if (s.find('.') != std::string::npos || ( s.find('x') == std::string::npos && ( s.find_first_of("eE") != std::string::npos ) ))
|
||||||
{
|
{
|
||||||
inst->m_numtype = CBotTypFloat;
|
double val = GetNumFloat(s);
|
||||||
inst->m_valfloat = GetNumFloat(s);
|
if (val > static_cast<double>(std::numeric_limits<float>::max()))
|
||||||
|
{
|
||||||
|
numtype = CBotTypDouble;
|
||||||
|
inst = new CBotExprLitNum<double>(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
numtype = CBotTypFloat;
|
||||||
|
inst = new CBotExprLitNum<float>(static_cast<float>(val));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inst->m_valint = GetNumInt(s);
|
long val = GetNumInt(s);
|
||||||
|
if (val > std::numeric_limits<int>::max())
|
||||||
|
{
|
||||||
|
numtype = CBotTypLong;
|
||||||
|
inst = new CBotExprLitNum<long>(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inst = new CBotExprLitNum<int>(static_cast<int>(val));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inst->SetToken(p);
|
||||||
if (pStk->NextToken(p))
|
if (pStk->NextToken(p))
|
||||||
{
|
{
|
||||||
CBotVar* var = CBotVar::Create("", inst->m_numtype);
|
CBotVar* var = CBotVar::Create("", numtype);
|
||||||
pStk->SetVar(var);
|
pStk->SetVar(var);
|
||||||
|
|
||||||
return pStack->Return(inst, pStk);
|
return pStack->Return(inst, pStk);
|
||||||
|
@ -79,8 +112,48 @@ CBotInstr* CBotExprLitNum::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
return pStack->Return(nullptr, pStk);
|
return pStack->Return(nullptr, pStk);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
CBotInstr* CompileSizeOf(CBotToken* &p, CBotCStack* pStack)
|
||||||
bool CBotExprLitNum::Execute(CBotStack* &pj)
|
{
|
||||||
|
CBotToken* pp = p;
|
||||||
|
|
||||||
|
if (!IsOfType(p, TokenTypVar)) return nullptr;
|
||||||
|
if (pp->GetString() == "sizeof" && IsOfType(p, ID_OPENPAR))
|
||||||
|
{
|
||||||
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
|
||||||
|
int value;
|
||||||
|
|
||||||
|
if (IsOfType(p, ID_BYTE)) value = sizeof(signed char);
|
||||||
|
else if (IsOfType(p, ID_SHORT)) value = sizeof(short);
|
||||||
|
else if (IsOfType(p, ID_CHAR)) value = sizeof(uint32_t);
|
||||||
|
else if (IsOfType(p, ID_INT)) value = sizeof(int);
|
||||||
|
else if (IsOfType(p, ID_LONG)) value = sizeof(long);
|
||||||
|
else if (IsOfType(p, ID_FLOAT)) value = sizeof(float);
|
||||||
|
else if (IsOfType(p, ID_DOUBLE)) value = sizeof(double);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p = pp;
|
||||||
|
return pStack->Return(nullptr, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsOfType(p, ID_CLOSEPAR))
|
||||||
|
{
|
||||||
|
auto inst = new CBotExprLitNum<int>(value);
|
||||||
|
inst->SetToken(pp);
|
||||||
|
|
||||||
|
CBotVar* var = CBotVar::Create("", CBotTypInt);
|
||||||
|
pStk->SetVar(var);
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
pStk->SetError(CBotErrClosePar, p->GetStart());
|
||||||
|
return pStack->Return(nullptr, pStk);
|
||||||
|
}
|
||||||
|
p = pp;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool CBotExprLitNum<T>::Execute(CBotStack* &pj)
|
||||||
{
|
{
|
||||||
CBotStack* pile = pj->AddStack(this);
|
CBotStack* pile = pj->AddStack(this);
|
||||||
|
|
||||||
|
@ -88,39 +161,38 @@ bool CBotExprLitNum::Execute(CBotStack* &pj)
|
||||||
|
|
||||||
CBotVar* var = CBotVar::Create("", m_numtype);
|
CBotVar* var = CBotVar::Create("", m_numtype);
|
||||||
|
|
||||||
std::string nombre ;
|
|
||||||
if (m_token.GetType() == TokenTypDef)
|
if (m_token.GetType() == TokenTypDef)
|
||||||
{
|
{
|
||||||
nombre = m_token.GetString();
|
var->SetValInt(m_value, m_token.GetString());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
switch (m_numtype)
|
|
||||||
{
|
{
|
||||||
case CBotTypShort:
|
*var = m_value;
|
||||||
case CBotTypInt:
|
|
||||||
var->SetValInt(m_valint, nombre);
|
|
||||||
break;
|
|
||||||
case CBotTypFloat:
|
|
||||||
var->SetValFloat(m_valfloat);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
pile->SetVar(var); // place on the stack
|
pile->SetVar(var); // place on the stack
|
||||||
|
|
||||||
return pj->Return(pile); // it's ok
|
return pj->Return(pile); // it's ok
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
template <typename T>
|
||||||
void CBotExprLitNum::RestoreState(CBotStack* &pj, bool bMain)
|
void CBotExprLitNum<T>::RestoreState(CBotStack* &pj, bool bMain)
|
||||||
{
|
{
|
||||||
if (bMain) pj->RestoreStack(this);
|
if (bMain) pj->RestoreStack(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CBotExprLitNum::GetDebugData()
|
template <typename T>
|
||||||
|
std::string CBotExprLitNum<T>::GetDebugData()
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "(" << (m_numtype == CBotTypFloat ? "float" : "int") << ") " << (m_numtype == CBotTypFloat ? m_valfloat : m_valint);
|
switch (m_numtype)
|
||||||
|
{
|
||||||
|
case CBotTypInt : ss << "(int) "; break;
|
||||||
|
case CBotTypLong : ss << "(long) "; break;
|
||||||
|
case CBotTypFloat : ss << "(float) "; break;
|
||||||
|
case CBotTypDouble: ss << "(double) "; break;
|
||||||
|
default: assert(false);
|
||||||
|
}
|
||||||
|
ss << m_value;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,26 +24,23 @@
|
||||||
namespace CBot
|
namespace CBot
|
||||||
{
|
{
|
||||||
|
|
||||||
|
CBotInstr* CompileExprLitNum(CBotToken* &p, CBotCStack* pStack);
|
||||||
|
|
||||||
|
CBotInstr* CompileSizeOf(CBotToken* &p, CBotCStack* pStack);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief A number literal - 5, 1, 2.5, 3.75, etc. or a predefined numerical constant (see CBotToken::DefineNum())
|
* \brief A number literal - 5, 1, 2.5, 3.75, etc. or a predefined numerical constant (see CBotToken::DefineNum())
|
||||||
*
|
*
|
||||||
* Can be of type ::CBotTypInt or ::CBotTypFloat
|
* Can be of type ::CBotTypInt, ::CBotTypLong, ::CBotTypFloat, or ::CBotTypDouble
|
||||||
*/
|
*/
|
||||||
|
template <typename T>
|
||||||
class CBotExprLitNum : public CBotInstr
|
class CBotExprLitNum : public CBotInstr
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CBotExprLitNum();
|
CBotExprLitNum(T val);
|
||||||
~CBotExprLitNum();
|
~CBotExprLitNum();
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Compile
|
|
||||||
* \param p
|
|
||||||
* \param pStack
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Execute Execute, returns the corresponding number.
|
* \brief Execute Execute, returns the corresponding number.
|
||||||
* \param pj
|
* \param pj
|
||||||
|
@ -65,10 +62,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
//! The type of number.
|
//! The type of number.
|
||||||
CBotType m_numtype;
|
CBotType m_numtype;
|
||||||
//! Value for an int.
|
//! Value
|
||||||
long m_valint;
|
T m_value;
|
||||||
//! Value for a float.
|
|
||||||
float m_valfloat;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
{
|
{
|
||||||
CBotCStack* pStk = pStack->TokenStack();
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
|
||||||
std::string s = p->GetString();
|
const auto& s = p->GetString();
|
||||||
|
|
||||||
auto it = s.cbegin();
|
auto it = s.cbegin();
|
||||||
if (++it != s.cend())
|
if (++it != s.cend())
|
||||||
|
@ -51,7 +51,7 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
std::string valstring = "";
|
std::string valstring = "";
|
||||||
while (it != s.cend() && *it != '\"')
|
while (it != s.cend() && *it != '\"')
|
||||||
{
|
{
|
||||||
pStk->SetStartError(++pos);
|
++pos;
|
||||||
if (*it != '\\') // not escape sequence ?
|
if (*it != '\\') // not escape sequence ?
|
||||||
{
|
{
|
||||||
valstring += *(it++);
|
valstring += *(it++);
|
||||||
|
@ -59,6 +59,7 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++it == s.cend()) break;
|
if (++it == s.cend()) break;
|
||||||
|
pStk->SetStartError(pos);
|
||||||
|
|
||||||
if (CharInList(*it, "01234567")) // octal
|
if (CharInList(*it, "01234567")) // octal
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,8 +40,7 @@ CBotExprUnaire::~CBotExprUnaire()
|
||||||
delete m_expr;
|
delete m_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral, bool bConstExpr)
|
||||||
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral)
|
|
||||||
{
|
{
|
||||||
int op = p->GetType();
|
int op = p->GetType();
|
||||||
CBotToken* pp = p;
|
CBotToken* pp = p;
|
||||||
|
@ -52,8 +51,10 @@ CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLite
|
||||||
CBotExprUnaire* inst = new CBotExprUnaire();
|
CBotExprUnaire* inst = new CBotExprUnaire();
|
||||||
inst->SetToken(pp);
|
inst->SetToken(pp);
|
||||||
|
|
||||||
if (!bLiteral) inst->m_expr = CBotParExpr::Compile(p, pStk);
|
if (bConstExpr || !bLiteral)
|
||||||
else inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk);
|
inst->m_expr = CBotParExpr::Compile(p, pStk, bConstExpr);
|
||||||
|
else
|
||||||
|
inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk);
|
||||||
|
|
||||||
if (inst->m_expr != nullptr)
|
if (inst->m_expr != nullptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
* \param bLiteral If true, compiles only literal expressions Ex: ~11, -4.0, !false, not true
|
* \param bLiteral If true, compiles only literal expressions Ex: ~11, -4.0, !false, not true
|
||||||
* \return The compiled instruction or nullptr
|
* \return The compiled instruction or nullptr
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false);
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false, bool bConstExpr = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Execute
|
* \brief Execute
|
||||||
|
|
|
@ -208,10 +208,15 @@ CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
case ID_THROW:
|
case ID_THROW:
|
||||||
return CBotThrow::Compile(p, pStack);
|
return CBotThrow::Compile(p, pStack);
|
||||||
|
|
||||||
|
case ID_BYTE:
|
||||||
|
case ID_SHORT:
|
||||||
|
case ID_CHAR:
|
||||||
case ID_INT:
|
case ID_INT:
|
||||||
|
case ID_LONG:
|
||||||
return CBotDefInt::Compile(p, pStack);
|
return CBotDefInt::Compile(p, pStack);
|
||||||
|
|
||||||
case ID_FLOAT:
|
case ID_FLOAT:
|
||||||
|
case ID_DOUBLE:
|
||||||
return CBotDefFloat::Compile(p, pStack);
|
return CBotDefFloat::Compile(p, pStack);
|
||||||
|
|
||||||
case ID_STRING:
|
case ID_STRING:
|
||||||
|
@ -312,13 +317,6 @@ void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain)
|
||||||
assert(0); // dad do not know, see the girls
|
assert(0); // dad do not know, see the girls
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool CBotInstr::CompCase(CBotStack* &pj, int val)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first)
|
CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first)
|
||||||
{
|
{
|
||||||
if (IsOfType(p, ID_OPBRK))
|
if (IsOfType(p, ID_OPBRK))
|
||||||
|
|
|
@ -191,17 +191,6 @@ public:
|
||||||
virtual void RestoreStateVar(CBotStack* &pile,
|
virtual void RestoreStateVar(CBotStack* &pile,
|
||||||
bool bMain);
|
bool bMain);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief CompCase This routine is defined only for the subclass CBotCase
|
|
||||||
* this allows to make the call on all instructions CompCase to see if it's
|
|
||||||
* a case to the desired value..
|
|
||||||
* \param pj
|
|
||||||
* \param val
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
virtual bool CompCase(CBotStack* &pj,
|
|
||||||
int val);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief SetToken Set the token corresponding to the instruction.
|
* \brief SetToken Set the token corresponding to the instruction.
|
||||||
* \param p
|
* \param p
|
||||||
|
|
|
@ -129,6 +129,13 @@ bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (op == ID_ASR || op == ID_SR || op == ID_SL ||
|
||||||
|
op == ID_ASSOR || op == ID_ASSSL || op == ID_ASSSR ||
|
||||||
|
op == ID_ASSAND || op == ID_ASSXOR || op == ID_ASSASR)
|
||||||
|
{
|
||||||
|
if (max > CBotTypLong) return false;
|
||||||
|
}
|
||||||
|
|
||||||
type1.SetType(max);
|
type1.SetType(max);
|
||||||
type2.SetType(max);
|
type2.SetType(max);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotExpression.h"
|
#include "CBot/CBotInstr/CBotExpression.h"
|
||||||
#include "CBot/CBotInstr/CBotExprLitBool.h"
|
#include "CBot/CBotInstr/CBotExprLitBool.h"
|
||||||
|
#include "CBot/CBotInstr/CBotExprLitChar.h"
|
||||||
#include "CBot/CBotInstr/CBotExprLitNan.h"
|
#include "CBot/CBotInstr/CBotExprLitNan.h"
|
||||||
#include "CBot/CBotInstr/CBotExprLitNull.h"
|
#include "CBot/CBotInstr/CBotExprLitNull.h"
|
||||||
#include "CBot/CBotInstr/CBotExprLitNum.h"
|
#include "CBot/CBotInstr/CBotExprLitNum.h"
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
#include "CBot/CBotInstr/CBotNew.h"
|
#include "CBot/CBotInstr/CBotNew.h"
|
||||||
#include "CBot/CBotInstr/CBotPostIncExpr.h"
|
#include "CBot/CBotInstr/CBotPostIncExpr.h"
|
||||||
#include "CBot/CBotInstr/CBotPreIncExpr.h"
|
#include "CBot/CBotInstr/CBotPreIncExpr.h"
|
||||||
|
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
|
||||||
|
|
||||||
#include "CBot/CBotVar/CBotVar.h"
|
#include "CBot/CBotVar/CBotVar.h"
|
||||||
|
|
||||||
|
@ -39,13 +41,15 @@
|
||||||
namespace CBot
|
namespace CBot
|
||||||
{
|
{
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack, bool bConstExpr)
|
||||||
CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
||||||
{
|
{
|
||||||
CBotCStack* pStk = pStack->TokenStack();
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
|
||||||
pStk->SetStartError(p->GetStart());
|
pStk->SetStartError(p->GetStart());
|
||||||
|
|
||||||
|
if (bConstExpr)
|
||||||
|
return CBotParExpr::CompileConstExpr(p, pStack);
|
||||||
|
|
||||||
// is it an expression in parentheses?
|
// is it an expression in parentheses?
|
||||||
if (IsOfType(p, ID_OPENPAR))
|
if (IsOfType(p, ID_OPENPAR))
|
||||||
{
|
{
|
||||||
|
@ -68,6 +72,13 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
if (inst != nullptr || !pStk->IsOk())
|
if (inst != nullptr || !pStk->IsOk())
|
||||||
return pStack->Return(inst, pStk);
|
return pStack->Return(inst, pStk);
|
||||||
|
|
||||||
|
// is it sizeof operator ?
|
||||||
|
inst = CBot::CompileSizeOf(p, pStk);
|
||||||
|
if (inst != nullptr || !pStk->IsOk())
|
||||||
|
{
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
// is it a variable name?
|
// is it a variable name?
|
||||||
if (p->GetType() == TokenTypVar)
|
if (p->GetType() == TokenTypVar)
|
||||||
{
|
{
|
||||||
|
@ -151,7 +162,21 @@ CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack)
|
||||||
if (p->GetType() == TokenTypNum ||
|
if (p->GetType() == TokenTypNum ||
|
||||||
p->GetType() == TokenTypDef )
|
p->GetType() == TokenTypDef )
|
||||||
{
|
{
|
||||||
CBotInstr* inst = CBotExprLitNum::Compile(p, pStk);
|
CBotInstr* inst = CBot::CompileExprLitNum(p, pStk);
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// is it sizeof operator ?
|
||||||
|
inst = CBot::CompileSizeOf(p, pStk);
|
||||||
|
if (inst != nullptr || !pStk->IsOk())
|
||||||
|
{
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// is this a character?
|
||||||
|
if (p->GetType() == TokenTypChar)
|
||||||
|
{
|
||||||
|
CBotInstr* inst = CBotExprLitChar::Compile(p, pStk);
|
||||||
return pStack->Return(inst, pStk);
|
return pStack->Return(inst, pStk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,4 +227,55 @@ CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack)
|
||||||
return pStack->Return(nullptr, pStk);
|
return pStack->Return(nullptr, pStk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CBotInstr* CBotParExpr::CompileConstExpr(CBotToken* &p, CBotCStack* pStack)
|
||||||
|
{
|
||||||
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
|
||||||
|
// is it an expression in parentheses?
|
||||||
|
if (IsOfType(p, ID_OPENPAR))
|
||||||
|
{
|
||||||
|
CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStk, nullptr, true);
|
||||||
|
|
||||||
|
if (nullptr != inst)
|
||||||
|
{
|
||||||
|
if (IsOfType(p, ID_CLOSEPAR))
|
||||||
|
{
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
pStk->SetError(CBotErrClosePar, p->GetStart());
|
||||||
|
}
|
||||||
|
delete inst;
|
||||||
|
return pStack->Return(nullptr, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// is this a unary operation?
|
||||||
|
CBotInstr* inst = CBotExprUnaire::Compile(p, pStk, true, true);
|
||||||
|
if (inst != nullptr || !pStk->IsOk())
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
|
||||||
|
// is it a number or DefineNum?
|
||||||
|
if (p->GetType() == TokenTypNum ||
|
||||||
|
p->GetType() == TokenTypDef )
|
||||||
|
{
|
||||||
|
CBotInstr* inst = CBot::CompileExprLitNum(p, pStk);
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// is this a character?
|
||||||
|
if (p->GetType() == TokenTypChar)
|
||||||
|
{
|
||||||
|
CBotInstr* inst = CBotExprLitChar::Compile(p, pStk);
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// is it sizeof operator ?
|
||||||
|
inst = CBot::CompileSizeOf(p, pStk);
|
||||||
|
if (inst != nullptr || !pStk->IsOk())
|
||||||
|
{
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pStack->Return(nullptr, pStk);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -52,7 +52,7 @@ public:
|
||||||
* \param pStack
|
* \param pStack
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bConstExpr = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Compile a literal expression ("string", number, true, false, null, nan, new)
|
* \brief Compile a literal expression ("string", number, true, false, null, nan, new)
|
||||||
|
@ -62,6 +62,8 @@ public:
|
||||||
*/
|
*/
|
||||||
static CBotInstr* CompileLitExpr(CBotToken* &p, CBotCStack* pStack);
|
static CBotInstr* CompileLitExpr(CBotToken* &p, CBotCStack* pStack);
|
||||||
|
|
||||||
|
static CBotInstr* CompileConstExpr(CBotToken* &p, CBotCStack* pStack);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CBotParExpr() = delete;
|
CBotParExpr() = delete;
|
||||||
CBotParExpr(const CBotParExpr&) = delete;
|
CBotParExpr(const CBotParExpr&) = delete;
|
||||||
|
|
|
@ -57,7 +57,7 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
{
|
{
|
||||||
if ( nullptr != (inst->m_value = CBotExpression::Compile(p, pStk )) )
|
if ( nullptr != (inst->m_value = CBotExpression::Compile(p, pStk )) )
|
||||||
{
|
{
|
||||||
if ( pStk->GetType() < CBotTypLong )
|
if ( pStk->GetType() <= CBotTypLong )
|
||||||
{
|
{
|
||||||
if ( IsOfType(p, ID_CLOSEPAR ) )
|
if ( IsOfType(p, ID_CLOSEPAR ) )
|
||||||
{
|
{
|
||||||
|
@ -65,21 +65,35 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
{
|
{
|
||||||
IncLvl();
|
IncLvl();
|
||||||
|
|
||||||
|
CBotCase* caseInst = nullptr;
|
||||||
|
CBotCStack* pStk2 = nullptr;
|
||||||
while( !IsOfType( p, ID_CLBLK ) )
|
while( !IsOfType( p, ID_CLBLK ) )
|
||||||
{
|
{
|
||||||
if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT)
|
if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT)
|
||||||
{
|
{
|
||||||
CBotCStack* pStk2 = pStk->TokenStack(p); // some space for a stack, plz
|
delete pStk2;
|
||||||
|
pStk2 = pStk->TokenStack(p, true); // some space for a stack, plz
|
||||||
|
|
||||||
CBotInstr* i = CBotCase::Compile( p, pStk2 );
|
caseInst = static_cast<CBotCase*>(CBotCase::Compile(p, pStk2, inst->m_labels));
|
||||||
if (i == nullptr)
|
if (caseInst == nullptr)
|
||||||
{
|
{
|
||||||
delete inst;
|
delete inst;
|
||||||
return pStack->Return(nullptr, pStk2);
|
return pStack->Return(nullptr, pStk2);
|
||||||
}
|
}
|
||||||
delete pStk2;
|
|
||||||
if (inst->m_block == nullptr ) inst->m_block = i;
|
if (inst->m_block == nullptr ) inst->m_block = caseInst;
|
||||||
else inst->m_block->AddNext(i);
|
else inst->m_block->AddNext(caseInst);
|
||||||
|
|
||||||
|
if (ID_DEFAULT == caseInst->GetTokenType())
|
||||||
|
{
|
||||||
|
if (inst->m_default != nullptr)
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrRedefCase, caseInst->GetToken());
|
||||||
|
delete inst;
|
||||||
|
return pStack->Return(nullptr, pStk);
|
||||||
|
}
|
||||||
|
inst->m_default = caseInst;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,13 +104,14 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
return pStack->Return(nullptr, pStk);
|
return pStack->Return(nullptr, pStk);
|
||||||
}
|
}
|
||||||
|
|
||||||
CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true );
|
CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk2);
|
||||||
if ( !pStk->IsOk() )
|
if ( !pStk2->IsOk() )
|
||||||
{
|
{
|
||||||
delete inst;
|
delete inst;
|
||||||
return pStack->Return(nullptr, pStk);
|
return pStack->Return(nullptr, pStk2);
|
||||||
}
|
}
|
||||||
inst->m_block->AddNext(i);
|
if (caseInst->m_instr == nullptr ) caseInst->m_instr = i;
|
||||||
|
else caseInst->m_instr->AddNext(i);
|
||||||
|
|
||||||
if ( p == nullptr )
|
if ( p == nullptr )
|
||||||
{
|
{
|
||||||
|
@ -133,40 +148,21 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
bool CBotSwitch :: Execute(CBotStack* &pj)
|
bool CBotSwitch :: Execute(CBotStack* &pj)
|
||||||
{
|
{
|
||||||
CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack
|
CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack
|
||||||
// if ( pile1 == EOX ) return true;
|
|
||||||
|
|
||||||
CBotInstr* p = m_block; // first expression
|
|
||||||
|
|
||||||
int state = pile1->GetState();
|
int state = pile1->GetState();
|
||||||
if (state == 0)
|
if (state == 0)
|
||||||
{
|
{
|
||||||
if ( !m_value->Execute(pile1) ) return false;
|
if ( !m_value->Execute(pile1) ) return false;
|
||||||
pile1->SetState(state = -1);
|
pile1->SetState(state = 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pile1->IfStep() ) return false;
|
if ( pile1->IfStep() ) return false;
|
||||||
|
|
||||||
if ( state == -1 )
|
auto it = m_labels.find(pile1->GetVar()->GetValLong());
|
||||||
{
|
|
||||||
state = 0;
|
|
||||||
int val = pile1->GetVal(); // result of the value
|
|
||||||
|
|
||||||
CBotStack* pile2 = pile1->AddStack();
|
CBotInstr* p = (it != m_labels.end()) ? it->second : m_default;
|
||||||
while ( p != nullptr ) // search for the corresponding case in a list
|
|
||||||
{
|
|
||||||
state++;
|
|
||||||
if ( p->CompCase( pile2, val ) ) break; // found the case
|
|
||||||
p = p->GetNext();
|
|
||||||
}
|
|
||||||
pile2->Delete();
|
|
||||||
|
|
||||||
if ( p == nullptr ) return pj->Return(pile1); // completed if nothing
|
while (--state > 0) p = p->GetNext();
|
||||||
|
|
||||||
if ( !pile1->SetState(state) ) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = m_block; // returns to the beginning
|
|
||||||
while (state-->0) p = p->GetNext(); // advance in the list
|
|
||||||
|
|
||||||
while( p != nullptr )
|
while( p != nullptr )
|
||||||
{
|
{
|
||||||
|
@ -185,8 +181,6 @@ void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
|
||||||
CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack
|
CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack
|
||||||
if ( pile1 == nullptr ) return;
|
if ( pile1 == nullptr ) return;
|
||||||
|
|
||||||
CBotInstr* p = m_block; // first expression
|
|
||||||
|
|
||||||
int state = pile1->GetState();
|
int state = pile1->GetState();
|
||||||
if (state == 0)
|
if (state == 0)
|
||||||
{
|
{
|
||||||
|
@ -194,13 +188,11 @@ void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( state == -1 )
|
auto it = m_labels.find(pile1->GetVar()->GetValLong());
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// p = m_block; // returns to the beginning
|
CBotInstr* p = (it != m_labels.end()) ? it->second : m_default;
|
||||||
while ( p != nullptr && state-- > 0 )
|
|
||||||
|
while (p != nullptr && --state > 0)
|
||||||
{
|
{
|
||||||
p->RestoreState(pile1, false);
|
p->RestoreState(pile1, false);
|
||||||
p = p->GetNext(); // advance in the list
|
p = p->GetNext(); // advance in the list
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotInstr.h"
|
#include "CBot/CBotInstr/CBotInstr.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace CBot
|
namespace CBot
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -64,8 +66,12 @@ protected:
|
||||||
private:
|
private:
|
||||||
//! Value to seek
|
//! Value to seek
|
||||||
CBotInstr* m_value;
|
CBotInstr* m_value;
|
||||||
//! Instructions
|
//! List of case instructions
|
||||||
CBotInstr* m_block;
|
CBotInstr* m_block = nullptr;
|
||||||
|
//! Pointer to default label
|
||||||
|
CBotInstr* m_default = nullptr;
|
||||||
|
//! Map of case labels
|
||||||
|
std::unordered_map<long, CBotInstr*> m_labels;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -133,8 +133,7 @@ static bool TypeOk(int type, int test)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations, bool bConstExpr)
|
||||||
CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations)
|
|
||||||
{
|
{
|
||||||
int typeMask;
|
int typeMask;
|
||||||
|
|
||||||
|
@ -146,8 +145,8 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
||||||
|
|
||||||
// search the intructions that may be suitable to the left of the operation
|
// search the intructions that may be suitable to the left of the operation
|
||||||
CBotInstr* left = (*pOp == 0) ?
|
CBotInstr* left = (*pOp == 0) ?
|
||||||
CBotParExpr::Compile( p, pStk ) : // expression (...) left
|
CBotParExpr::Compile(p, pStk, bConstExpr) : // expression (...) left
|
||||||
CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B left
|
CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr); // expression A * B left
|
||||||
|
|
||||||
if (left == nullptr) return pStack->Return(nullptr, pStk); // if error, transmit
|
if (left == nullptr) return pStack->Return(nullptr, pStk); // if error, transmit
|
||||||
|
|
||||||
|
@ -158,7 +157,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
||||||
CBotTypResult type1, type2;
|
CBotTypResult type1, type2;
|
||||||
type1 = pStk->GetTypResult(); // what kind of the first operand?
|
type1 = pStk->GetTypResult(); // what kind of the first operand?
|
||||||
|
|
||||||
if (typeOp == ID_LOGIC) // special case provided for: ? op1: op2;
|
if (!bConstExpr && typeOp == ID_LOGIC) // special case provided for: ? op1: op2;
|
||||||
{
|
{
|
||||||
if ( !type1.Eq(CBotTypBoolean) )
|
if ( !type1.Eq(CBotTypBoolean) )
|
||||||
{
|
{
|
||||||
|
@ -207,7 +206,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
||||||
|
|
||||||
// looking statements that may be suitable for right
|
// looking statements that may be suitable for right
|
||||||
|
|
||||||
if ( nullptr != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) )
|
if ( nullptr != (inst->m_rightop = CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr)) )
|
||||||
// expression (...) right
|
// expression (...) right
|
||||||
{
|
{
|
||||||
// there is an second operand acceptable
|
// there is an second operand acceptable
|
||||||
|
@ -264,7 +263,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
||||||
type1 = TypeRes;
|
type1 = TypeRes;
|
||||||
|
|
||||||
p = p->GetNext(); // advance after
|
p = p->GetNext(); // advance after
|
||||||
i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp );
|
i->m_rightop = CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr);
|
||||||
type2 = pStk->GetTypResult();
|
type2 = pStk->GetTypResult();
|
||||||
|
|
||||||
if ( !TypeCompatible (type1, type2, typeOp) ) // the results are compatible
|
if ( !TypeCompatible (type1, type2, typeOp) ) // the results are compatible
|
||||||
|
@ -399,7 +398,10 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
|
||||||
TypeRes = CBotTypBoolean;
|
TypeRes = CBotTypBoolean;
|
||||||
break;
|
break;
|
||||||
case ID_DIV:
|
case ID_DIV:
|
||||||
TypeRes = std::max(TypeRes, static_cast<int>(CBotTypFloat));
|
if (TypeRes == CBotTypFloat)
|
||||||
|
{
|
||||||
|
if (type1.Eq(CBotTypLong) || type2.Eq(CBotTypLong)) TypeRes = CBotTypDouble;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates a variable for the result
|
// creates a variable for the result
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
* \param pOperations
|
* \param pOperations
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = nullptr);
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = nullptr, bool bConstExpr = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Execute Performes the operation on two operands.
|
* \brief Execute Performes the operation on two operands.
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "CBot/CBotCStack.h"
|
#include "CBot/CBotCStack.h"
|
||||||
#include "CBot/CBotClass.h"
|
#include "CBot/CBotClass.h"
|
||||||
#include "CBot/CBotUtils.h"
|
#include "CBot/CBotUtils.h"
|
||||||
#include "CBot/CBotFileUtils.h"
|
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotFunction.h"
|
#include "CBot/CBotInstr/CBotFunction.h"
|
||||||
|
|
||||||
|
@ -332,51 +331,56 @@ bool CBotProgram::DefineNum(const std::string& name, long val)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotProgram::SaveState(FILE* pf)
|
bool CBotProgram::SaveState(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if (!WriteWord( pf, CBOTVERSION)) return false;
|
if (!WriteLong(ostr, CBOTVERSION)) return false;
|
||||||
|
|
||||||
|
|
||||||
if (m_stack != nullptr )
|
if (m_stack != nullptr )
|
||||||
{
|
{
|
||||||
if (!WriteWord( pf, 1)) return false;
|
if (!WriteWord(ostr, 1)) return false;
|
||||||
if (!WriteString( pf, m_entryPoint->GetName() )) return false;
|
if (!WriteString(ostr, m_entryPoint->GetName())) return false;
|
||||||
if (!m_stack->SaveState(pf)) return false;
|
if (!m_stack->SaveState(ostr)) return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!WriteWord( pf, 0)) return false;
|
if (!WriteWord(ostr, 0)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBotProgram::RestoreState(FILE* pf)
|
bool CBotProgram::RestoreState(std::istream &istr)
|
||||||
{
|
{
|
||||||
unsigned short w;
|
unsigned short w;
|
||||||
std::string s;
|
std::string s;
|
||||||
|
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
if (!ReadWord( pf, w )) return false;
|
long version;
|
||||||
if ( w != CBOTVERSION ) return false;
|
if (!ReadLong(istr, version)) return false;
|
||||||
|
if ( version != CBOTVERSION ) return false;
|
||||||
|
|
||||||
if (!ReadWord( pf, w )) return false;
|
if (!ReadWord(istr, w)) return false;
|
||||||
if ( w == 0 ) return true;
|
if ( w == 0 ) return true;
|
||||||
|
|
||||||
if (!ReadString( pf, s )) return false;
|
// don't restore if compile error exists
|
||||||
Start(s); // point de reprise
|
if (m_error != CBotNoErr) return false;
|
||||||
|
|
||||||
if (m_stack != nullptr)
|
if (!ReadString(istr, s)) return false;
|
||||||
|
if (!Start(s)) return false; // point de reprise
|
||||||
|
// Start() already created the new stack
|
||||||
|
// and called m_stack->SetProgram(this);
|
||||||
|
|
||||||
|
// retrieves the stack from the memory
|
||||||
|
if (!m_stack->RestoreState(istr, m_stack))
|
||||||
{
|
{
|
||||||
m_stack->Delete();
|
m_stack->Delete();
|
||||||
m_stack = nullptr;
|
m_stack = nullptr;
|
||||||
|
m_stack = CBotStack::AllocateStack(); // start from the top
|
||||||
|
m_stack->SetProgram(this);
|
||||||
|
return false; // signal error
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieves the stack from the memory
|
|
||||||
m_stack = CBotStack::AllocateStack();
|
|
||||||
if (!m_stack->RestoreState(pf, m_stack)) return false;
|
|
||||||
m_stack->SetProgram(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_entryPoint->RestoreState(nullptr, m_stack, m_thisVar);
|
m_entryPoint->RestoreState(nullptr, m_stack, m_thisVar);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -282,27 +282,20 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Save the current execution status into a file
|
* \brief Save the current execution status into a file
|
||||||
* \param pf
|
* \param ostr Output stream
|
||||||
* \parblock
|
|
||||||
* file handle
|
|
||||||
*
|
|
||||||
* This file handle must have been opened by this library! Otherwise crashes on Windows
|
|
||||||
*
|
|
||||||
* TODO: Verify this
|
|
||||||
* \endparblock
|
|
||||||
* \return true on success, false on write error
|
* \return true on success, false on write error
|
||||||
*/
|
*/
|
||||||
bool SaveState(FILE* pf);
|
bool SaveState(std::ostream &ostr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Restore the execution state from a file
|
* \brief Restore the execution state from a file
|
||||||
*
|
*
|
||||||
* The previous program code must already have been recompiled with Compile() before calling this function
|
* The previous program code must already have been recompiled with Compile() before calling this function
|
||||||
*
|
*
|
||||||
* \param pf file handle
|
* \param istr Input stream
|
||||||
* \return true on success, false on read error
|
* \return true on success, false on read error
|
||||||
*/
|
*/
|
||||||
bool RestoreState(FILE* pf);
|
bool RestoreState(std::istream &istr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief GetPosition Gives the position of a routine in the original text
|
* \brief GetPosition Gives the position of a routine in the original text
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include "CBot/CBotVar/CBotVarPointer.h"
|
#include "CBot/CBotVar/CBotVarPointer.h"
|
||||||
#include "CBot/CBotVar/CBotVarClass.h"
|
#include "CBot/CBotVar/CBotVarClass.h"
|
||||||
|
|
||||||
#include "CBot/CBotFileUtils.h"
|
|
||||||
#include "CBot/CBotUtils.h"
|
#include "CBot/CBotUtils.h"
|
||||||
#include "CBot/CBotExternalCall.h"
|
#include "CBot/CBotExternalCall.h"
|
||||||
|
|
||||||
|
@ -687,108 +686,106 @@ CBotVar* CBotStack::GetStackVars(std::string& functionName, int level)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotStack::SaveState(FILE* pf)
|
bool CBotStack::SaveState(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if (m_next2 != nullptr)
|
if (m_next2 != nullptr)
|
||||||
{
|
{
|
||||||
if (!WriteWord(pf, 2)) return false; // a marker of type (m_next2)
|
if (!WriteWord(ostr, 2)) return false; // a marker of type (m_next2)
|
||||||
if (!m_next2->SaveState(pf)) return false; // saves the next element
|
if (!m_next2->SaveState(ostr)) return false; // saves the next element
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!WriteWord(pf, 1)) return false; // a marker of type (m_next)
|
if (!WriteWord(ostr, 1)) return false; // a marker of type (m_next)
|
||||||
}
|
}
|
||||||
if (!WriteWord(pf, static_cast<unsigned short>(m_block))) return false;
|
if (!WriteWord(ostr, static_cast<unsigned short>(m_block))) return false;
|
||||||
if (!WriteWord(pf, m_state)) return false;
|
if (!WriteInt(ostr, m_state)) return false;
|
||||||
if (!WriteWord(pf, 0)) return false; // for backwards combatibility (m_bDontDelete)
|
if (!WriteWord(ostr, 0)) return false; // for backwards combatibility (m_bDontDelete)
|
||||||
if (!WriteWord(pf, m_step)) return false;
|
if (!WriteInt(ostr, m_step)) return false;
|
||||||
|
|
||||||
|
if (!SaveVars(ostr, m_var)) return false; // current result
|
||||||
if (!SaveVars(pf, m_var)) return false; // current result
|
if (!SaveVars(ostr, m_listVar)) return false; // local variables
|
||||||
if (!SaveVars(pf, m_listVar)) return false; // local variables
|
|
||||||
|
|
||||||
if (m_next != nullptr)
|
if (m_next != nullptr)
|
||||||
{
|
{
|
||||||
if (!m_next->SaveState(pf)) return false; // saves the next element
|
if (!m_next->SaveState(ostr)) return false; // saves the next element
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!WriteWord(pf, 0)) return false; // terminator
|
if (!WriteWord(ostr, 0)) return false; // 0 - CBotStack::SaveState terminator
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SaveVars(FILE* pf, CBotVar* pVar)
|
bool SaveVars(std::ostream &ostr, CBotVar* pVar)
|
||||||
{
|
{
|
||||||
while (pVar != nullptr)
|
while (pVar != nullptr)
|
||||||
{
|
{
|
||||||
if (!pVar->Save0State(pf)) return false; // common header
|
if (!pVar->Save0State(ostr)) return false; // common header
|
||||||
if (!pVar->Save1State(pf)) return false; // saves the data
|
if (!pVar->Save1State(ostr)) return false; // saves the data
|
||||||
|
|
||||||
pVar = pVar->GetNext();
|
pVar = pVar->GetNext();
|
||||||
}
|
}
|
||||||
return WriteWord(pf, 0); // terminator
|
return WriteWord(ostr, 0); // 0 - CBot::SaveVars terminator
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
|
bool CBotStack::RestoreState(std::istream &istr, CBotStack* &pStack)
|
||||||
{
|
{
|
||||||
unsigned short w;
|
unsigned short w;
|
||||||
|
|
||||||
if (pStack != this) pStack = nullptr;
|
if (pStack != this) pStack = nullptr;
|
||||||
if (!ReadWord(pf, w)) return false;
|
if (!ReadWord(istr, w)) return false;
|
||||||
if ( w == 0 ) return true; // 0 - terminator
|
if ( w == 0 ) return true; // 0 - CBotStack::SaveState terminator
|
||||||
|
|
||||||
if (pStack == nullptr) pStack = AddStack();
|
if (pStack == nullptr) pStack = AddStack();
|
||||||
|
|
||||||
if ( w == 2 ) // 2 - m_next2
|
if ( w == 2 ) // 2 - m_next2
|
||||||
{
|
{
|
||||||
if (!pStack->RestoreState(pf, pStack->m_next2)) return false;
|
if (!pStack->RestoreState(istr, pStack->m_next2)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ReadWord(pf, w)) return false;
|
if (!ReadWord(istr, w)) return false;
|
||||||
pStack->m_block = static_cast<BlockVisibilityType>(w);
|
pStack->m_block = static_cast<BlockVisibilityType>(w);
|
||||||
|
|
||||||
if (!ReadWord(pf, w)) return false;
|
int state;
|
||||||
pStack->SetState(static_cast<short>(w));
|
if (!ReadInt(istr, state)) return false;
|
||||||
|
pStack->SetState(state);
|
||||||
|
|
||||||
if (!ReadWord(pf, w)) return false; // backwards compatibility (m_bDontDelete)
|
if (!ReadWord(istr, w)) return false; // backwards compatibility (m_bDontDelete)
|
||||||
|
|
||||||
if (!ReadWord(pf, w)) return false;
|
if (!ReadInt(istr, state)) return false;
|
||||||
pStack->m_step = w;
|
pStack->m_step = state;
|
||||||
|
|
||||||
if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // temp variable
|
if (!CBotVar::RestoreState(istr, pStack->m_var)) return false; // temp variable
|
||||||
if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// local variables
|
if (!CBotVar::RestoreState(istr, pStack->m_listVar)) return false; // local variables
|
||||||
|
|
||||||
return pStack->RestoreState(pf, pStack->m_next);
|
return pStack->RestoreState(istr, pStack->m_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotVar::Save0State(FILE* pf)
|
bool CBotVar::Save0State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if (!WriteWord(pf, 100+static_cast<int>(m_mPrivate)))return false; // private variable?
|
if (!WriteWord(ostr, 100+static_cast<int>(m_mPrivate)))return false; // private variable?
|
||||||
if (!WriteWord(pf, m_bStatic))return false; // static variable?
|
if (!WriteWord(ostr, m_bStatic))return false; // static variable?
|
||||||
if (!WriteWord(pf, m_type.GetType()))return false; // saves the type (always non-zero)
|
if (!WriteWord(ostr, m_type.GetType()))return false; // saves the type (always non-zero)
|
||||||
|
|
||||||
if (m_type.Eq(CBotTypPointer) && GetPointer() != nullptr)
|
if (m_type.Eq(CBotTypPointer) && GetPointer() != nullptr)
|
||||||
{
|
{
|
||||||
if (GetPointer()->m_bConstructor) // constructor was called?
|
if (GetPointer()->m_bConstructor) // constructor was called?
|
||||||
{
|
{
|
||||||
if (!WriteWord(pf, (2000 + static_cast<unsigned short>(m_binit)) )) return false;
|
if (!WriteWord(ostr, (2000 + static_cast<unsigned short>(m_binit)) )) return false;
|
||||||
return WriteString(pf, m_token->GetString()); // and variable name
|
return WriteString(ostr, m_token->GetString()); // and variable name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteWord(pf, static_cast<unsigned short>(m_binit))) return false; // variable defined?
|
if (!WriteWord(ostr, static_cast<unsigned short>(m_binit))) return false; // variable defined?
|
||||||
return WriteString(pf, m_token->GetString()); // and variable name
|
return WriteString(ostr, m_token->GetString()); // and variable name
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
bool CBotVar::RestoreState(std::istream &istr, CBotVar* &pVar)
|
||||||
{
|
{
|
||||||
unsigned short w, wi, prv, st;
|
unsigned short w, wi, prv, st;
|
||||||
float ww;
|
|
||||||
std::string name, s;
|
|
||||||
|
|
||||||
delete pVar;
|
delete pVar;
|
||||||
|
|
||||||
|
@ -798,27 +795,27 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
||||||
|
|
||||||
while ( true ) // retrieves a list
|
while ( true ) // retrieves a list
|
||||||
{
|
{
|
||||||
if (!ReadWord(pf, w)) return false; // private or type?
|
if (!ReadWord(istr, w)) return false; // private or type?
|
||||||
if ( w == 0 ) return true;
|
if ( w == 0 ) return true; // 0 - CBot::SaveVars terminator
|
||||||
|
|
||||||
std::string defnum;
|
std::string defnum;
|
||||||
if ( w == 200 )
|
if ( w == 200 )
|
||||||
{
|
{
|
||||||
if (!ReadString(pf, defnum)) return false; // number with identifier
|
if (!ReadString(istr, defnum)) return false; // number with identifier
|
||||||
if (!ReadWord(pf, w)) return false; // type
|
if (!ReadWord(istr, w)) return false; // type
|
||||||
}
|
}
|
||||||
|
|
||||||
prv = 100; st = 0;
|
prv = 100; st = 0;
|
||||||
if ( w >= 100 )
|
if ( w >= 100 )
|
||||||
{
|
{
|
||||||
prv = w;
|
prv = w;
|
||||||
if (!ReadWord(pf, st)) return false; // static
|
if (!ReadWord(istr, st)) return false; // static
|
||||||
if (!ReadWord(pf, w)) return false; // type
|
if (!ReadWord(istr, w)) return false; // type
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic
|
if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic
|
||||||
|
|
||||||
if (!ReadWord(pf, wi)) return false; // init ?
|
if (!ReadWord(istr, wi)) return false; // init ?
|
||||||
bool bConstructor = false;
|
bool bConstructor = false;
|
||||||
if (w == CBotTypPointer && wi >= 2000)
|
if (w == CBotTypPointer && wi >= 2000)
|
||||||
{
|
{
|
||||||
|
@ -827,31 +824,70 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
||||||
}
|
}
|
||||||
|
|
||||||
CBotVar::InitType initType = static_cast<CBotVar::InitType>(wi);
|
CBotVar::InitType initType = static_cast<CBotVar::InitType>(wi);
|
||||||
if (!ReadString(pf, name)) return false; // variable name
|
std::string varname;
|
||||||
|
if (!ReadString(istr, varname)) return false; // variable name
|
||||||
CBotToken token(name, std::string());
|
CBotToken token(varname, std::string());
|
||||||
|
|
||||||
bool isClass = false;
|
bool isClass = false;
|
||||||
|
|
||||||
switch (w)
|
switch (w)
|
||||||
{
|
{
|
||||||
case CBotTypInt:
|
|
||||||
case CBotTypBoolean:
|
case CBotTypBoolean:
|
||||||
|
char valBool;
|
||||||
|
if (!ReadByte(istr, valBool)) return false;
|
||||||
pNew = CBotVar::Create(token, w); // creates a variable
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
if (!ReadWord(pf, w)) return false;
|
pNew->SetValInt(valBool);
|
||||||
pNew->SetValInt(static_cast<short>(w), defnum);
|
break;
|
||||||
|
case CBotTypByte:
|
||||||
|
char valByte;
|
||||||
|
if (!ReadByte(istr, valByte)) return false;
|
||||||
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
|
pNew->SetValByte(valByte);
|
||||||
|
break;
|
||||||
|
case CBotTypShort:
|
||||||
|
short valShort;
|
||||||
|
if (!ReadShort(istr, valShort)) return false;
|
||||||
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
|
pNew->SetValShort(valShort);
|
||||||
|
break;
|
||||||
|
case CBotTypChar:
|
||||||
|
uint32_t valChar;
|
||||||
|
if (!ReadUInt32(istr, valChar)) return false;
|
||||||
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
|
pNew->SetValChar(valChar);
|
||||||
|
break;
|
||||||
|
case CBotTypInt:
|
||||||
|
int valInt;
|
||||||
|
if (!ReadInt(istr, valInt)) return false;
|
||||||
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
|
pNew->SetValInt(valInt, defnum);
|
||||||
|
break;
|
||||||
|
case CBotTypLong:
|
||||||
|
long valLong;
|
||||||
|
if (!ReadLong(istr, valLong)) return false;
|
||||||
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
|
pNew->SetValInt(valLong);
|
||||||
break;
|
break;
|
||||||
case CBotTypFloat:
|
case CBotTypFloat:
|
||||||
|
float valFloat;
|
||||||
|
if (!ReadFloat(istr, valFloat)) return false;
|
||||||
pNew = CBotVar::Create(token, w); // creates a variable
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
if (!ReadFloat(pf, ww)) return false;
|
pNew->SetValFloat(valFloat);
|
||||||
pNew->SetValFloat(ww);
|
break;
|
||||||
|
case CBotTypDouble:
|
||||||
|
double valDouble;
|
||||||
|
if (!ReadDouble(istr, valDouble)) return false;
|
||||||
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
|
pNew->SetValDouble(valDouble);
|
||||||
break;
|
break;
|
||||||
case CBotTypString:
|
case CBotTypString:
|
||||||
pNew = CBotVar::Create(token, w); // creates a variable
|
{
|
||||||
if (!ReadString(pf, s)) return false;
|
std::string valString;
|
||||||
pNew->SetValString(s);
|
if (!ReadString(istr, valString)) return false;
|
||||||
break;
|
pNew = CBotVar::Create(token, w); // creates a variable
|
||||||
|
pNew->SetValString(valString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
// returns an intrinsic object or element of an array
|
// returns an intrinsic object or element of an array
|
||||||
case CBotTypIntrinsic:
|
case CBotTypIntrinsic:
|
||||||
isClass = true;
|
isClass = true;
|
||||||
|
@ -859,17 +895,16 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
||||||
{
|
{
|
||||||
CBotTypResult r;
|
CBotTypResult r;
|
||||||
long id;
|
long id;
|
||||||
if (!ReadType(pf, r)) return false; // complete type
|
if (!ReadType(istr, r)) return false; // complete type
|
||||||
if (!ReadLong(pf, id) ) return false;
|
if (!ReadLong(istr, id)) return false;
|
||||||
|
|
||||||
// if (!ReadString(pf, s)) return false;
|
|
||||||
{
|
{
|
||||||
CBotVar* p = nullptr;
|
CBotVar* p = nullptr;
|
||||||
if ( id ) p = CBotVarClass::Find(id) ;
|
if ( id ) p = CBotVarClass::Find(id) ;
|
||||||
|
|
||||||
pNew = new CBotVarClass(token, r); // directly creates an instance
|
pNew = new CBotVarClass(token, r); // directly creates an instance
|
||||||
// attention cptuse = 0
|
// attention cptuse = 0
|
||||||
if ( !RestoreState(pf, (static_cast<CBotVarClass*>(pNew))->m_pVar)) return false;
|
if (!RestoreState(istr, (static_cast<CBotVarClass*>(pNew))->m_pVar)) return false;
|
||||||
pNew->SetIdent(id);
|
pNew->SetIdent(id);
|
||||||
|
|
||||||
if (isClass && p == nullptr) // set id for each item in this instance
|
if (isClass && p == nullptr) // set id for each item in this instance
|
||||||
|
@ -895,18 +930,20 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
||||||
|
|
||||||
case CBotTypPointer:
|
case CBotTypPointer:
|
||||||
case CBotTypNullPointer:
|
case CBotTypNullPointer:
|
||||||
if (!ReadString(pf, s)) return false; // name of the class
|
{
|
||||||
|
std::string className;
|
||||||
|
if (!ReadString(istr, className)) return false; // name of the class
|
||||||
{
|
{
|
||||||
CBotTypResult ptrType(w, s);
|
|
||||||
pNew = CBotVar::Create(token, ptrType);// creates a variable
|
|
||||||
// CBotVarClass* p = nullptr;
|
// CBotVarClass* p = nullptr;
|
||||||
long id;
|
long id;
|
||||||
ReadLong(pf, id);
|
if (!ReadLong(istr, id)) return false;
|
||||||
// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance)
|
// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance)
|
||||||
|
|
||||||
|
CBotTypResult ptrType(w, className);
|
||||||
|
pNew = CBotVar::Create(token, ptrType); // creates a variable
|
||||||
// returns a copy of the original instance
|
// returns a copy of the original instance
|
||||||
CBotVar* pInstance = nullptr;
|
CBotVar* pInstance = nullptr;
|
||||||
if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
|
if (!CBotVar::RestoreState(istr, pInstance)) return false;
|
||||||
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
|
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
|
||||||
|
|
||||||
if (bConstructor) pNew->ConstructorSet(); // constructor was called
|
if (bConstructor) pNew->ConstructorSet(); // constructor was called
|
||||||
|
@ -916,22 +953,22 @@ bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CBotTypArrayPointer:
|
case CBotTypArrayPointer:
|
||||||
{
|
{
|
||||||
CBotTypResult r;
|
CBotTypResult r;
|
||||||
if (!ReadType(pf, r)) return false;
|
if (!ReadType(istr, r)) return false;
|
||||||
|
|
||||||
pNew = CBotVar::Create(token, r); // creates a variable
|
pNew = CBotVar::Create(token, r); // creates a variable
|
||||||
|
|
||||||
// returns a copy of the original instance
|
// returns a copy of the original instance
|
||||||
CBotVar* pInstance = nullptr;
|
CBotVar* pInstance = nullptr;
|
||||||
if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
|
if (!CBotVar::RestoreState(istr, pInstance)) return false;
|
||||||
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
|
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
return false; // signal error
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pPrev != nullptr ) pPrev->m_next = pNew;
|
if ( pPrev != nullptr ) pPrev->m_next = pNew;
|
||||||
|
|
|
@ -434,8 +434,8 @@ public:
|
||||||
//! \name Write to file
|
//! \name Write to file
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
bool SaveState(FILE* pf);
|
bool SaveState(std::ostream &ostr);
|
||||||
bool RestoreState(FILE* pf, CBotStack* &pStack);
|
bool RestoreState(std::istream &istr, CBotStack* &pStack);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,11 @@ static const boost::bimap<TokenId, std::string> KEYWORDS = makeBimap<TokenId, st
|
||||||
{ID_STRING, "string"},
|
{ID_STRING, "string"},
|
||||||
{ID_VOID, "void"},
|
{ID_VOID, "void"},
|
||||||
{ID_BOOL, "bool"},
|
{ID_BOOL, "bool"},
|
||||||
|
{ID_BYTE, "byte"},
|
||||||
|
{ID_SHORT, "short"},
|
||||||
|
{ID_CHAR, "char"},
|
||||||
|
{ID_LONG, "long"},
|
||||||
|
{ID_DOUBLE, "double"},
|
||||||
{ID_TRUE, "true"},
|
{ID_TRUE, "true"},
|
||||||
{ID_FALSE, "false"},
|
{ID_FALSE, "false"},
|
||||||
{ID_NULL, "null"},
|
{ID_NULL, "null"},
|
||||||
|
@ -103,7 +108,7 @@ static const boost::bimap<TokenId, std::string> KEYWORDS = makeBimap<TokenId, st
|
||||||
{ID_ASSSR, ">>>="},
|
{ID_ASSSR, ">>>="},
|
||||||
{ID_ASSASR, ">>="},
|
{ID_ASSASR, ">>="},
|
||||||
{ID_SL, "<<"},
|
{ID_SL, "<<"},
|
||||||
{ID_SR, ">>"},
|
{ID_SR, ">>>"},
|
||||||
{ID_ASR, ">>"},
|
{ID_ASR, ">>"},
|
||||||
{ID_INC, "++"},
|
{ID_INC, "++"},
|
||||||
{ID_DEC, "--"},
|
{ID_DEC, "--"},
|
||||||
|
@ -299,12 +304,53 @@ CBotToken* CBotToken::NextToken(const char*& program, bool first)
|
||||||
stop = true;
|
stop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// special case for characters
|
||||||
|
if (token[0] == '\'')
|
||||||
|
{
|
||||||
|
if (c == '\\') // escape sequence
|
||||||
|
{
|
||||||
|
token += c;
|
||||||
|
c = *(program++);
|
||||||
|
|
||||||
|
if (c == 'u' || c == 'U') // unicode escape
|
||||||
|
{
|
||||||
|
int maxlen = (c == 'u') ? 4 : 8;
|
||||||
|
token += c;
|
||||||
|
c = *(program++);
|
||||||
|
for (int i = 0; i < maxlen; i++)
|
||||||
|
{
|
||||||
|
if (c == 0 || !CharInList(c, hexnum)) break;
|
||||||
|
token += c;
|
||||||
|
c = *(program++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c != 0 && !CharInList(c, nch)) // other escape char
|
||||||
|
{
|
||||||
|
token += c;
|
||||||
|
c = *(program++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c != 0 && c != '\'' && !CharInList(c, nch)) // single character
|
||||||
|
{
|
||||||
|
token += c;
|
||||||
|
c = *(program++);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\'') // close quote
|
||||||
|
{
|
||||||
|
token += c;
|
||||||
|
c = *(program++);
|
||||||
|
}
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
// special case for numbers
|
// special case for numbers
|
||||||
if ( CharInList(token[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 bin[] = "01";
|
||||||
char* liste = num;
|
char* liste = num;
|
||||||
if (token[0] == '0' && c == 'x') // hexadecimal value?
|
if (token[0] == '0' && c == 'x') // hexadecimal value?
|
||||||
{
|
{
|
||||||
|
@ -312,6 +358,12 @@ CBotToken* CBotToken::NextToken(const char*& program, bool first)
|
||||||
c = *(program++); // next character
|
c = *(program++); // next character
|
||||||
liste = hexnum;
|
liste = hexnum;
|
||||||
}
|
}
|
||||||
|
else if (token[0] == '0' && c == 'b') // binary literal
|
||||||
|
{
|
||||||
|
liste = bin;
|
||||||
|
token += c;
|
||||||
|
c = *(program++);
|
||||||
|
}
|
||||||
cw:
|
cw:
|
||||||
while (c != 0 && CharInList(c, liste))
|
while (c != 0 && CharInList(c, liste))
|
||||||
{
|
{
|
||||||
|
@ -394,6 +446,7 @@ bis:
|
||||||
|
|
||||||
if (CharInList(token[0], num )) t->m_type = TokenTypNum;
|
if (CharInList(token[0], num )) t->m_type = TokenTypNum;
|
||||||
if (token[0] == '\"') t->m_type = TokenTypString;
|
if (token[0] == '\"') t->m_type = TokenTypString;
|
||||||
|
if (token[0] == '\'') t->m_type = TokenTypChar;
|
||||||
if (first) t->m_type = TokenTypNone;
|
if (first) t->m_type = TokenTypNone;
|
||||||
|
|
||||||
t->m_keywordId = GetKeyWord(token);
|
t->m_keywordId = GetKeyWord(token);
|
||||||
|
|
|
@ -185,8 +185,13 @@ std::string CBotTypResult::ToString()
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case CBotTypVoid: return "void";
|
case CBotTypVoid: return "void";
|
||||||
|
case CBotTypByte: return "byte";
|
||||||
|
case CBotTypShort: return "short";
|
||||||
|
case CBotTypChar: return "char";
|
||||||
case CBotTypInt: return "int";
|
case CBotTypInt: return "int";
|
||||||
|
case CBotTypLong: return "long";
|
||||||
case CBotTypFloat: return "float";
|
case CBotTypFloat: return "float";
|
||||||
|
case CBotTypDouble: return "double";
|
||||||
case CBotTypBoolean: return "bool";
|
case CBotTypBoolean: return "bool";
|
||||||
case CBotTypString: return "string";
|
case CBotTypString: return "string";
|
||||||
case CBotTypArrayPointer: return m_next->ToString() + "[]";
|
case CBotTypArrayPointer: return m_next->ToString() + "[]";
|
||||||
|
|
|
@ -62,12 +62,27 @@ CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
|
||||||
|
|
||||||
switch (p->GetType())
|
switch (p->GetType())
|
||||||
{
|
{
|
||||||
|
case ID_BYTE:
|
||||||
|
p = p->GetNext();
|
||||||
|
return ArrayType(p, pile, CBotTypResult( CBotTypByte ));
|
||||||
|
case ID_SHORT:
|
||||||
|
p = p->GetNext();
|
||||||
|
return ArrayType(p, pile, CBotTypResult( CBotTypShort ));
|
||||||
|
case ID_CHAR:
|
||||||
|
p = p->GetNext();
|
||||||
|
return ArrayType(p, pile, CBotTypResult( CBotTypChar ));
|
||||||
case ID_INT:
|
case ID_INT:
|
||||||
p = p->GetNext();
|
p = p->GetNext();
|
||||||
return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
|
return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
|
||||||
|
case ID_LONG:
|
||||||
|
p = p->GetNext();
|
||||||
|
return ArrayType(p, pile, CBotTypResult( CBotTypLong ));
|
||||||
case ID_FLOAT:
|
case ID_FLOAT:
|
||||||
p = p->GetNext();
|
p = p->GetNext();
|
||||||
return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
|
return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
|
||||||
|
case ID_DOUBLE:
|
||||||
|
p = p->GetNext();
|
||||||
|
return ArrayType(p, pile, CBotTypResult( CBotTypDouble ));
|
||||||
case ID_BOOLEAN:
|
case ID_BOOLEAN:
|
||||||
case ID_BOOL:
|
case ID_BOOL:
|
||||||
p = p->GetNext();
|
p = p->GetNext();
|
||||||
|
@ -108,38 +123,6 @@ CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool WriteWord(FILE* pf, unsigned short w)
|
|
||||||
{
|
|
||||||
size_t lg;
|
|
||||||
|
|
||||||
lg = fwrite(&w, sizeof( unsigned short ), 1, pf );
|
|
||||||
|
|
||||||
return (lg == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool WriteString(FILE* pf, std::string s)
|
|
||||||
{
|
|
||||||
size_t lg1, lg2;
|
|
||||||
|
|
||||||
lg1 = s.size();
|
|
||||||
if (!WriteWord(pf, lg1)) return false;
|
|
||||||
|
|
||||||
lg2 = fwrite(s.c_str(), 1, lg1, pf );
|
|
||||||
return (lg1 == lg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool WriteFloat(FILE* pf, float w)
|
|
||||||
{
|
|
||||||
size_t lg;
|
|
||||||
|
|
||||||
lg = fwrite(&w, sizeof( float ), 1, pf );
|
|
||||||
|
|
||||||
return (lg == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
long GetNumInt(const std::string& str)
|
long GetNumInt(const std::string& str)
|
||||||
{
|
{
|
||||||
|
@ -172,11 +155,23 @@ long GetNumInt(const std::string& str)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (*p == 'b')
|
||||||
|
{
|
||||||
|
while (*++p != 0)
|
||||||
|
{
|
||||||
|
if (*p == '0' || *p == '1')
|
||||||
|
{
|
||||||
|
num = (num << 1) + *p - '0';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
float GetNumFloat(const std::string& str)
|
double GetNumFloat(const std::string& str)
|
||||||
{
|
{
|
||||||
const char* p = str.c_str();
|
const char* p = str.c_str();
|
||||||
double num = 0;
|
double num = 0;
|
||||||
|
@ -233,7 +228,7 @@ float GetNumFloat(const std::string& str)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bNeg) num = -num;
|
if (bNeg) num = -num;
|
||||||
return static_cast<float>(num);
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharInList(const char c, const char* list)
|
bool CharInList(const char c, const char* list)
|
||||||
|
|
|
@ -19,9 +19,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CBot/CBotTypResult.h"
|
#include "CBot/CBotFileUtils.h"
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
@ -31,6 +30,8 @@ namespace CBot
|
||||||
class CBotVar;
|
class CBotVar;
|
||||||
class CBotToken;
|
class CBotToken;
|
||||||
class CBotCStack;
|
class CBotCStack;
|
||||||
|
class CBotTypResult;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief MakeListVars Transforms the array of pointers to variables in a
|
* \brief MakeListVars Transforms the array of pointers to variables in a
|
||||||
|
@ -58,30 +59,6 @@ CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile);
|
||||||
*/
|
*/
|
||||||
CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type);
|
CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type);
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief WriteWord
|
|
||||||
* \param pf
|
|
||||||
* \param w
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
bool WriteWord(FILE* pf, unsigned short w);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief WriteString
|
|
||||||
* \param pf
|
|
||||||
* \param s
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
bool WriteString(FILE* pf, std::string s);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief WriteFloat
|
|
||||||
* \param pf
|
|
||||||
* \param w
|
|
||||||
* \return
|
|
||||||
*/
|
|
||||||
bool WriteFloat(FILE* pf, float w);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief GetNumInt Converts a string into integer may be of the form 0xabc123.
|
* \brief GetNumInt Converts a string into integer may be of the form 0xabc123.
|
||||||
* \param str
|
* \param str
|
||||||
|
@ -94,7 +71,7 @@ long GetNumInt(const std::string& str);
|
||||||
* \param str
|
* \param str
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
float GetNumFloat(const std::string& str);
|
double GetNumFloat(const std::string& str);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Search a null-terminated string for a char value.
|
* \brief Search a null-terminated string for a char value.
|
||||||
|
|
|
@ -24,12 +24,17 @@
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotInstr.h"
|
#include "CBot/CBotInstr/CBotInstr.h"
|
||||||
#include "CBot/CBotVar/CBotVarArray.h"
|
#include "CBot/CBotVar/CBotVarArray.h"
|
||||||
#include "CBot/CBotVar/CBotVarPointer.h"
|
|
||||||
#include "CBot/CBotVar/CBotVarClass.h"
|
|
||||||
#include "CBot/CBotVar/CBotVarBoolean.h"
|
#include "CBot/CBotVar/CBotVarBoolean.h"
|
||||||
#include "CBot/CBotVar/CBotVarString.h"
|
#include "CBot/CBotVar/CBotVarByte.h"
|
||||||
|
#include "CBot/CBotVar/CBotVarChar.h"
|
||||||
|
#include "CBot/CBotVar/CBotVarClass.h"
|
||||||
|
#include "CBot/CBotVar/CBotVarDouble.h"
|
||||||
#include "CBot/CBotVar/CBotVarFloat.h"
|
#include "CBot/CBotVar/CBotVarFloat.h"
|
||||||
#include "CBot/CBotVar/CBotVarInt.h"
|
#include "CBot/CBotVar/CBotVarInt.h"
|
||||||
|
#include "CBot/CBotVar/CBotVarLong.h"
|
||||||
|
#include "CBot/CBotVar/CBotVarPointer.h"
|
||||||
|
#include "CBot/CBotVar/CBotVarShort.h"
|
||||||
|
#include "CBot/CBotVar/CBotVarString.h"
|
||||||
|
|
||||||
#include "CBot/CBotClass.h"
|
#include "CBot/CBotClass.h"
|
||||||
#include "CBot/CBotToken.h"
|
#include "CBot/CBotToken.h"
|
||||||
|
@ -134,7 +139,7 @@ void* CBotVar::GetUserPtr()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotVar::Save1State(FILE* pf)
|
bool CBotVar::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
// this routine "virtual" must never be called,
|
// this routine "virtual" must never be called,
|
||||||
// there must be a routine for each of the subclasses (CBotVarInt, CBotVarFloat, etc)
|
// there must be a routine for each of the subclasses (CBotVarInt, CBotVarFloat, etc)
|
||||||
|
@ -160,11 +165,20 @@ CBotVar* CBotVar::Create(const CBotToken& name, CBotTypResult type)
|
||||||
{
|
{
|
||||||
switch (type.GetType())
|
switch (type.GetType())
|
||||||
{
|
{
|
||||||
|
case CBotTypByte:
|
||||||
|
return new CBotVarByte(name);
|
||||||
case CBotTypShort:
|
case CBotTypShort:
|
||||||
|
return new CBotVarShort(name);
|
||||||
|
case CBotTypChar:
|
||||||
|
return new CBotVarChar(name);
|
||||||
case CBotTypInt:
|
case CBotTypInt:
|
||||||
return new CBotVarInt(name);
|
return new CBotVarInt(name);
|
||||||
|
case CBotTypLong:
|
||||||
|
return new CBotVarLong(name);
|
||||||
case CBotTypFloat:
|
case CBotTypFloat:
|
||||||
return new CBotVarFloat(name);
|
return new CBotVarFloat(name);
|
||||||
|
case CBotTypDouble:
|
||||||
|
return new CBotVarDouble(name);
|
||||||
case CBotTypBoolean:
|
case CBotTypBoolean:
|
||||||
return new CBotVarBoolean(name);
|
return new CBotVarBoolean(name);
|
||||||
case CBotTypString:
|
case CBotTypString:
|
||||||
|
@ -223,11 +237,20 @@ CBotVar* CBotVar::Create(const std::string& n, CBotTypResult type)
|
||||||
|
|
||||||
switch (type.GetType())
|
switch (type.GetType())
|
||||||
{
|
{
|
||||||
|
case CBotTypByte:
|
||||||
|
return new CBotVarByte(name);
|
||||||
case CBotTypShort:
|
case CBotTypShort:
|
||||||
|
return new CBotVarShort(name);
|
||||||
|
case CBotTypChar:
|
||||||
|
return new CBotVarChar(name);
|
||||||
case CBotTypInt:
|
case CBotTypInt:
|
||||||
return new CBotVarInt(name);
|
return new CBotVarInt(name);
|
||||||
|
case CBotTypLong:
|
||||||
|
return new CBotVarLong(name);
|
||||||
case CBotTypFloat:
|
case CBotTypFloat:
|
||||||
return new CBotVarFloat(name);
|
return new CBotVarFloat(name);
|
||||||
|
case CBotTypDouble:
|
||||||
|
return new CBotVarDouble(name);
|
||||||
case CBotTypBoolean:
|
case CBotTypBoolean:
|
||||||
return new CBotVarBoolean(name);
|
return new CBotVarBoolean(name);
|
||||||
case CBotTypString:
|
case CBotTypString:
|
||||||
|
@ -472,12 +495,27 @@ void CBotVar::SetVal(CBotVar* var)
|
||||||
case CBotTypBoolean:
|
case CBotTypBoolean:
|
||||||
SetValInt(var->GetValInt());
|
SetValInt(var->GetValInt());
|
||||||
break;
|
break;
|
||||||
|
case CBotTypByte:
|
||||||
|
SetValByte(var->GetValByte());
|
||||||
|
break;
|
||||||
|
case CBotTypShort:
|
||||||
|
SetValShort(var->GetValShort());
|
||||||
|
break;
|
||||||
|
case CBotTypChar:
|
||||||
|
SetValChar(var->GetValChar());
|
||||||
|
break;
|
||||||
case CBotTypInt:
|
case CBotTypInt:
|
||||||
SetValInt(var->GetValInt(), (static_cast<CBotVarInt*>(var))->m_defnum);
|
SetValInt(var->GetValInt(), (static_cast<CBotVarInt*>(var))->m_defnum);
|
||||||
break;
|
break;
|
||||||
|
case CBotTypLong:
|
||||||
|
SetValLong(var->GetValLong());
|
||||||
|
break;
|
||||||
case CBotTypFloat:
|
case CBotTypFloat:
|
||||||
SetValFloat(var->GetValFloat());
|
SetValFloat(var->GetValFloat());
|
||||||
break;
|
break;
|
||||||
|
case CBotTypDouble:
|
||||||
|
SetValDouble(var->GetValDouble());
|
||||||
|
break;
|
||||||
case CBotTypString:
|
case CBotTypString:
|
||||||
SetValString(var->GetValString());
|
SetValString(var->GetValString());
|
||||||
break;
|
break;
|
||||||
|
@ -545,33 +583,84 @@ CBotVarClass* CBotVar::GetPointer()
|
||||||
|
|
||||||
// All these functions must be defined in the subclasses
|
// All these functions must be defined in the subclasses
|
||||||
// derived from class CBotVar
|
// derived from class CBotVar
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
signed char CBotVar::GetValByte()
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
short CBotVar::GetValShort()
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CBotVar::GetValChar()
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int CBotVar::GetValInt()
|
int CBotVar::GetValInt()
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
long CBotVar::GetValLong()
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
float CBotVar::GetValFloat()
|
float CBotVar::GetValFloat()
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
double CBotVar::GetValDouble()
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBotVar::SetValByte(signed char val)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBotVar::SetValShort(short val)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBotVar::SetValChar(uint32_t val)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
void CBotVar::SetValInt(int c, const std::string& s)
|
void CBotVar::SetValInt(int c, const std::string& s)
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
void CBotVar::SetValLong(long val)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
void CBotVar::SetValFloat(float c)
|
void CBotVar::SetValFloat(float c)
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
void CBotVar::SetValDouble(double val)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
void CBotVar::Mul(CBotVar* left, CBotVar* right)
|
void CBotVar::Mul(CBotVar* left, CBotVar* right)
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -752,16 +841,46 @@ CBotClass* CBotVar::GetClass()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CBotVar::operator bool()
|
||||||
|
{
|
||||||
|
return static_cast<bool>(GetValInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
CBotVar::operator signed char()
|
||||||
|
{
|
||||||
|
return GetValByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
CBotVar::operator short()
|
||||||
|
{
|
||||||
|
return GetValShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
CBotVar::operator uint32_t()
|
||||||
|
{
|
||||||
|
return GetValChar();
|
||||||
|
}
|
||||||
|
|
||||||
CBotVar::operator int()
|
CBotVar::operator int()
|
||||||
{
|
{
|
||||||
return GetValInt();
|
return GetValInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CBotVar::operator long()
|
||||||
|
{
|
||||||
|
return GetValLong();
|
||||||
|
}
|
||||||
|
|
||||||
CBotVar::operator float()
|
CBotVar::operator float()
|
||||||
{
|
{
|
||||||
return GetValFloat();
|
return GetValFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CBotVar::operator double()
|
||||||
|
{
|
||||||
|
return GetValDouble();
|
||||||
|
}
|
||||||
|
|
||||||
CBotVar::operator std::string()
|
CBotVar::operator std::string()
|
||||||
{
|
{
|
||||||
return GetValString();
|
return GetValString();
|
||||||
|
@ -772,16 +891,41 @@ void CBotVar::operator=(const CBotVar &var)
|
||||||
SetVal(const_cast<CBotVar*>(&var));
|
SetVal(const_cast<CBotVar*>(&var));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CBotVar::operator=(signed char x)
|
||||||
|
{
|
||||||
|
SetValByte(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBotVar::operator=(short x)
|
||||||
|
{
|
||||||
|
SetValShort(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBotVar::operator=(uint32_t x)
|
||||||
|
{
|
||||||
|
SetValChar(x);
|
||||||
|
}
|
||||||
|
|
||||||
void CBotVar::operator=(int x)
|
void CBotVar::operator=(int x)
|
||||||
{
|
{
|
||||||
SetValInt(x);
|
SetValInt(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CBotVar::operator=(long x)
|
||||||
|
{
|
||||||
|
SetValLong(x);
|
||||||
|
}
|
||||||
|
|
||||||
void CBotVar::operator=(float x)
|
void CBotVar::operator=(float x)
|
||||||
{
|
{
|
||||||
SetValFloat(x);
|
SetValFloat(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CBotVar::operator=(double x)
|
||||||
|
{
|
||||||
|
SetValDouble(x);
|
||||||
|
}
|
||||||
|
|
||||||
void CBotVar::operator=(const std::string &x)
|
void CBotVar::operator=(const std::string &x)
|
||||||
{
|
{
|
||||||
SetValString(x);
|
SetValString(x);
|
||||||
|
|
|
@ -444,12 +444,23 @@ public:
|
||||||
*/
|
*/
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
operator bool();
|
||||||
|
operator signed char();
|
||||||
|
operator short();
|
||||||
|
operator uint32_t();
|
||||||
operator int();
|
operator int();
|
||||||
|
operator long();
|
||||||
operator float();
|
operator float();
|
||||||
|
operator double();
|
||||||
operator std::string();
|
operator std::string();
|
||||||
void operator=(const CBotVar& var);
|
void operator=(const CBotVar& var);
|
||||||
|
void operator=(signed char x);
|
||||||
|
void operator=(short x);
|
||||||
|
void operator=(uint32_t x);
|
||||||
void operator=(int x);
|
void operator=(int x);
|
||||||
|
void operator=(long x);
|
||||||
void operator=(float x);
|
void operator=(float x);
|
||||||
|
void operator=(double x);
|
||||||
void operator=(const std::string &x);
|
void operator=(const std::string &x);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -465,6 +476,12 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void Copy(CBotVar* pSrc, bool bName = true);
|
virtual void Copy(CBotVar* pSrc, bool bName = true);
|
||||||
|
|
||||||
|
virtual void SetValByte(signed char val);
|
||||||
|
|
||||||
|
virtual void SetValShort(short val);
|
||||||
|
|
||||||
|
virtual void SetValChar(uint32_t val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set value as an integer
|
* \brief Set value as an integer
|
||||||
*
|
*
|
||||||
|
@ -475,30 +492,44 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void SetValInt(int val, const std::string& name = "");
|
virtual void SetValInt(int val, const std::string& name = "");
|
||||||
|
|
||||||
|
virtual void SetValLong(long val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set value as float
|
* \brief Set value as float
|
||||||
* \param val New value
|
* \param val New value
|
||||||
*/
|
*/
|
||||||
virtual void SetValFloat(float val);
|
virtual void SetValFloat(float val);
|
||||||
|
|
||||||
|
virtual void SetValDouble(double val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set value as string
|
* \brief Set value as string
|
||||||
* \param val New value
|
* \param val New value
|
||||||
*/
|
*/
|
||||||
virtual void SetValString(const std::string& val);
|
virtual void SetValString(const std::string& val);
|
||||||
|
|
||||||
|
virtual signed char GetValByte();
|
||||||
|
|
||||||
|
virtual short GetValShort();
|
||||||
|
|
||||||
|
virtual uint32_t GetValChar();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get value as integer
|
* \brief Get value as integer
|
||||||
* \return Current value
|
* \return Current value
|
||||||
*/
|
*/
|
||||||
virtual int GetValInt();
|
virtual int GetValInt();
|
||||||
|
|
||||||
|
virtual long GetValLong();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get value as float
|
* \brief Get value as float
|
||||||
* \return Current value
|
* \return Current value
|
||||||
*/
|
*/
|
||||||
virtual float GetValFloat();
|
virtual float GetValFloat();
|
||||||
|
|
||||||
|
virtual double GetValDouble();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get value as string
|
* \brief Get value as string
|
||||||
*
|
*
|
||||||
|
@ -623,28 +654,28 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Save common variable header (name, type, etc.)
|
* \brief Save common variable header (name, type, etc.)
|
||||||
* \param pf file pointer
|
* \param ostr Output stream
|
||||||
* \return false on write error
|
* \return false on write error
|
||||||
*/
|
*/
|
||||||
virtual bool Save0State(FILE* pf);
|
virtual bool Save0State(std::ostream &ostr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Save variable data
|
* \brief Save variable data
|
||||||
*
|
*
|
||||||
* Overriden in child classes
|
* Overriden in child classes
|
||||||
*
|
*
|
||||||
* \param pf file pointer
|
* \param ostr Output stream
|
||||||
* \return false on write error
|
* \return false on write error
|
||||||
*/
|
*/
|
||||||
virtual bool Save1State(FILE* pf);
|
virtual bool Save1State(std::ostream &ostr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Restore variable
|
* \brief Restore variable
|
||||||
* \param pf file pointer
|
* \param istr Input stream
|
||||||
* \param[out] pVar Pointer to recieve the variable
|
* \param[out] pVar Pointer to recieve the variable
|
||||||
* \return false on read error
|
* \return false on read error
|
||||||
*/
|
*/
|
||||||
static bool RestoreState(FILE* pf, CBotVar* &pVar);
|
static bool RestoreState(std::istream &istr, CBotVar* &pVar);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "CBot/CBotVar/CBotVarArray.h"
|
#include "CBot/CBotVar/CBotVarArray.h"
|
||||||
#include "CBot/CBotVar/CBotVarClass.h"
|
#include "CBot/CBotVar/CBotVarClass.h"
|
||||||
#include "CBot/CBotToken.h"
|
#include "CBot/CBotToken.h"
|
||||||
#include "CBot/CBotFileUtils.h"
|
|
||||||
|
|
||||||
#include "CBot/CBotEnums.h"
|
#include "CBot/CBotEnums.h"
|
||||||
|
|
||||||
|
@ -137,10 +136,10 @@ std::string CBotVarArray::GetValString()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotVarArray::Save1State(FILE* pf)
|
bool CBotVarArray::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if ( !WriteType(pf, m_type) ) return false;
|
if (!WriteType(ostr, m_type)) return false;
|
||||||
return SaveVars(pf, m_pInstance); // saves the instance that manages the table
|
return SaveVars(ostr, m_pInstance); // saves the instance that manages the table
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
|
|
||||||
std::string GetValString() override;
|
std::string GetValString() override;
|
||||||
|
|
||||||
bool Save1State(FILE* pf) override;
|
bool Save1State(std::ostream &ostr) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Array data
|
//! Array data
|
||||||
|
|
|
@ -40,9 +40,9 @@ void CBotVarBoolean::Not()
|
||||||
SetValInt(!GetValInt());
|
SetValInt(!GetValInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBotVarBoolean::Save1State(FILE* pf)
|
bool CBotVarBoolean::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
return WriteWord(pf, m_val); // the value of the variable
|
return WriteByte(ostr, m_val); // the value of the variable
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
void XOr(CBotVar* left, CBotVar* right) override;
|
void XOr(CBotVar* left, CBotVar* right) override;
|
||||||
void Not() override;
|
void Not() override;
|
||||||
|
|
||||||
bool Save1State(FILE* pf) override;
|
bool Save1State(std::ostream &ostr) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CBot/CBotVar/CBotVarValue.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief CBotVar subclass for managing 1-byte integer values (::CBotTypByte)
|
||||||
|
*/
|
||||||
|
class CBotVarByte : public CBotVarInteger<signed char, CBotTypByte>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotVarByte(const CBotToken &name) : CBotVarInteger(name) {}
|
||||||
|
|
||||||
|
void SR(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
SetValByte(static_cast<unsigned char>(left->GetValByte()) >> right->GetValInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Save1State(std::ostream &ostr) override
|
||||||
|
{
|
||||||
|
return WriteByte(ostr, m_val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CBot/CBotVar/CBotVarValue.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief CBotVar subclass for managing 32-bit Unicode values (::CBotTypChar)
|
||||||
|
*/
|
||||||
|
class CBotVarChar : public CBotVarInteger<uint32_t, CBotTypChar>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotVarChar(const CBotToken &name) : CBotVarInteger(name) {}
|
||||||
|
|
||||||
|
std::string GetValString() override
|
||||||
|
{
|
||||||
|
if (m_binit == CBotVar::InitType::UNDEF)
|
||||||
|
return LoadString(TX_UNDEF);
|
||||||
|
if (m_binit == CBotVar::InitType::IS_NAN)
|
||||||
|
return LoadString(TX_NAN);
|
||||||
|
|
||||||
|
if (0x10FFFF < m_val || (0xD7FF < m_val && m_val < 0xE000))
|
||||||
|
return "\xEF\xBF\xBD"; // replacement character U+FFFD
|
||||||
|
|
||||||
|
return CodePointToUTF8(m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SR(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
SetValChar(left->GetValChar() >> right->GetValInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Save1State(std::ostream &ostr) override
|
||||||
|
{
|
||||||
|
return WriteUInt32(ostr, m_val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -23,8 +23,6 @@
|
||||||
#include "CBot/CBotStack.h"
|
#include "CBot/CBotStack.h"
|
||||||
#include "CBot/CBotDefines.h"
|
#include "CBot/CBotDefines.h"
|
||||||
|
|
||||||
#include "CBot/CBotFileUtils.h"
|
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotInstr.h"
|
#include "CBot/CBotInstr/CBotInstr.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -464,12 +462,12 @@ bool CBotVarClass::Ne(CBotVar* left, CBotVar* right)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotVarClass::Save1State(FILE* pf)
|
bool CBotVarClass::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if ( !WriteType(pf, m_type) ) return false;
|
if (!WriteType(ostr, m_type)) return false;
|
||||||
if ( !WriteLong(pf, m_ItemIdent) ) return false;
|
if (!WriteLong(ostr, m_ItemIdent)) return false;
|
||||||
|
|
||||||
return SaveVars(pf, m_pVar); // content of the object
|
return SaveVars(ostr, m_pVar); // content of the object
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
CBotVar* GetItemList() override;
|
CBotVar* GetItemList() override;
|
||||||
std::string GetValString() override;
|
std::string GetValString() override;
|
||||||
|
|
||||||
bool Save1State(FILE* pf) override;
|
bool Save1State(std::ostream &ostr) override;
|
||||||
|
|
||||||
void Update(void* pUser) override;
|
void Update(void* pUser) override;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CBot/CBotVar/CBotVarValue.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief CBotVar subclass for managing double values (::CBotTypDouble)
|
||||||
|
*/
|
||||||
|
class CBotVarDouble : public CBotVarNumber<double, CBotTypDouble>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotVarDouble(const CBotToken &name) : CBotVarNumber(name) {}
|
||||||
|
|
||||||
|
bool Save1State(std::ostream &ostr) override
|
||||||
|
{
|
||||||
|
return WriteDouble(ostr, m_val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -22,9 +22,9 @@
|
||||||
namespace CBot
|
namespace CBot
|
||||||
{
|
{
|
||||||
|
|
||||||
bool CBotVarFloat::Save1State(FILE* pf)
|
bool CBotVarFloat::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
return WriteFloat(pf, m_val); // the value of the variable
|
return WriteFloat(ostr, m_val); // the value of the variable
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -32,7 +32,7 @@ class CBotVarFloat : public CBotVarNumber<float, CBotTypFloat>
|
||||||
public:
|
public:
|
||||||
CBotVarFloat(const CBotToken &name) : CBotVarNumber(name) {}
|
CBotVarFloat(const CBotToken &name) : CBotVarNumber(name) {}
|
||||||
|
|
||||||
bool Save1State(FILE* pf) override;
|
bool Save1State(std::ostream &ostr) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -45,67 +45,44 @@ std::string CBotVarInt::GetValString()
|
||||||
void CBotVarInt::Neg()
|
void CBotVarInt::Neg()
|
||||||
{
|
{
|
||||||
CBotVarNumber::Neg();
|
CBotVarNumber::Neg();
|
||||||
m_defnum.empty();
|
m_defnum.clear();
|
||||||
}
|
}
|
||||||
void CBotVarInt::Inc()
|
void CBotVarInt::Inc()
|
||||||
{
|
{
|
||||||
CBotVarNumber::Inc();
|
CBotVarNumber::Inc();
|
||||||
m_defnum.empty();
|
m_defnum.clear();
|
||||||
}
|
}
|
||||||
void CBotVarInt::Dec()
|
void CBotVarInt::Dec()
|
||||||
{
|
{
|
||||||
CBotVarNumber::Dec();
|
CBotVarNumber::Dec();
|
||||||
m_defnum.empty();
|
m_defnum.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBotVarInt::XOr(CBotVar* left, CBotVar* right)
|
|
||||||
{
|
|
||||||
SetValInt(left->GetValInt() ^ right->GetValInt());
|
|
||||||
}
|
|
||||||
void CBotVarInt::And(CBotVar* left, CBotVar* right)
|
|
||||||
{
|
|
||||||
SetValInt(left->GetValInt() & right->GetValInt());
|
|
||||||
}
|
|
||||||
void CBotVarInt::Or(CBotVar* left, CBotVar* right)
|
|
||||||
{
|
|
||||||
SetValInt(left->GetValInt() | right->GetValInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBotVarInt::SL(CBotVar* left, CBotVar* right)
|
|
||||||
{
|
|
||||||
SetValInt(left->GetValInt() << right->GetValInt());
|
|
||||||
}
|
|
||||||
void CBotVarInt::ASR(CBotVar* left, CBotVar* right)
|
|
||||||
{
|
|
||||||
SetValInt(left->GetValInt() >> right->GetValInt());
|
|
||||||
}
|
|
||||||
void CBotVarInt::SR(CBotVar* left, CBotVar* right)
|
void CBotVarInt::SR(CBotVar* left, CBotVar* right)
|
||||||
{
|
{
|
||||||
int source = left->GetValInt();
|
SetValInt(static_cast<unsigned>(left->GetValInt()) >> right->GetValInt());
|
||||||
int shift = right->GetValInt();
|
|
||||||
if (shift >= 1) source &= 0x7fffffff;
|
|
||||||
SetValInt(source >> shift);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBotVarInt::Not()
|
void CBotVarInt::Not()
|
||||||
{
|
{
|
||||||
m_val = ~m_val;
|
m_val = ~m_val;
|
||||||
|
m_defnum.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBotVarInt::Save0State(FILE* pf)
|
bool CBotVarInt::Save0State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if (!m_defnum.empty())
|
if (!m_defnum.empty())
|
||||||
{
|
{
|
||||||
if(!WriteWord(pf, 200)) return false; // special marker
|
if(!WriteWord(ostr, 200)) return false; // special marker
|
||||||
if(!WriteString(pf, m_defnum)) return false;
|
if(!WriteString(ostr, m_defnum)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CBotVar::Save0State(pf);
|
return CBotVar::Save0State(ostr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBotVarInt::Save1State(FILE* pf)
|
bool CBotVarInt::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
return WriteWord(pf, m_val);
|
return WriteInt(ostr, m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -27,10 +27,10 @@ namespace CBot
|
||||||
/**
|
/**
|
||||||
* \brief CBotVar subclass for managing integer values (::CBotTypInt)
|
* \brief CBotVar subclass for managing integer values (::CBotTypInt)
|
||||||
*/
|
*/
|
||||||
class CBotVarInt : public CBotVarNumber<int, CBotTypInt>
|
class CBotVarInt : public CBotVarInteger<int, CBotTypInt>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CBotVarInt(const CBotToken &name) : CBotVarNumber(name) {}
|
CBotVarInt(const CBotToken &name) : CBotVarInteger(name) {}
|
||||||
|
|
||||||
void SetValInt(int val, const std::string& s = "") override;
|
void SetValInt(int val, const std::string& s = "") override;
|
||||||
std::string GetValString() override;
|
std::string GetValString() override;
|
||||||
|
@ -40,18 +40,20 @@ public:
|
||||||
void Neg() override;
|
void Neg() override;
|
||||||
void Inc() override;
|
void Inc() override;
|
||||||
void Dec() override;
|
void Dec() override;
|
||||||
|
|
||||||
void XOr(CBotVar* left, CBotVar* right) override;
|
|
||||||
void Or(CBotVar* left, CBotVar* right) override;
|
|
||||||
void And(CBotVar* left, CBotVar* right) override;
|
|
||||||
void Not() override;
|
void Not() override;
|
||||||
|
|
||||||
void SL(CBotVar* left, CBotVar* right) override;
|
|
||||||
void SR(CBotVar* left, CBotVar* right) override;
|
void SR(CBotVar* left, CBotVar* right) override;
|
||||||
void ASR(CBotVar* left, CBotVar* right) override;
|
|
||||||
|
|
||||||
bool Save0State(FILE* pf) override;
|
bool Save0State(std::ostream &ostr) override;
|
||||||
bool Save1State(FILE* pf) override;
|
bool Save1State(std::ostream &ostr) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void SetValue(int val) override
|
||||||
|
{
|
||||||
|
CBotVarNumberBase::SetValue(val);
|
||||||
|
m_defnum.clear();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! The name if given by DefineNum.
|
//! The name if given by DefineNum.
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CBot/CBotVar/CBotVarValue.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief CBotVar subclass for managing long integer values (::CBotTypLong)
|
||||||
|
*/
|
||||||
|
class CBotVarLong : public CBotVarInteger<long, CBotTypLong>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotVarLong(const CBotToken &name) : CBotVarInteger(name) {}
|
||||||
|
|
||||||
|
void SR(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
SetValLong(static_cast<unsigned long>(left->GetValLong()) >> right->GetValInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Save1State(std::ostream &ostr) override
|
||||||
|
{
|
||||||
|
return WriteLong(ostr, m_val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
#include "CBot/CBotEnums.h"
|
#include "CBot/CBotEnums.h"
|
||||||
#include "CBot/CBotUtils.h"
|
#include "CBot/CBotUtils.h"
|
||||||
#include "CBot/CBotFileUtils.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
@ -171,21 +170,21 @@ CBotClass* CBotVarPointer::GetClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotVarPointer::Save1State(FILE* pf)
|
bool CBotVarPointer::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if ( m_type.GetClass() != nullptr )
|
if ( m_type.GetClass() != nullptr )
|
||||||
{
|
{
|
||||||
if (!WriteString(pf, m_type.GetClass()->GetName())) return false; // name of the class
|
if (!WriteString(ostr, m_type.GetClass()->GetName())) return false; // name of the class
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!WriteString(pf, "")) return false;
|
if (!WriteString(ostr, "")) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteLong(pf, GetIdent())) return false; // the unique reference
|
if (!WriteLong(ostr, GetIdent())) return false; // the unique reference
|
||||||
|
|
||||||
// also saves the proceedings copies
|
// also saves the proceedings copies
|
||||||
return SaveVars(pf, GetPointer());
|
return SaveVars(ostr, GetPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -61,7 +61,7 @@ public:
|
||||||
|
|
||||||
void ConstructorSet() override;
|
void ConstructorSet() override;
|
||||||
|
|
||||||
bool Save1State(FILE* pf) override;
|
bool Save1State(std::ostream &ostr) override;
|
||||||
|
|
||||||
void Update(void* pUser) override;
|
void Update(void* pUser) override;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CBot/CBotVar/CBotVarValue.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief CBotVar subclass for managing short integer values (::CBotTypShort)
|
||||||
|
*/
|
||||||
|
class CBotVarShort : public CBotVarInteger<short, CBotTypShort>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotVarShort(const CBotToken &name) : CBotVarInteger(name) {}
|
||||||
|
|
||||||
|
void SR(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
SetValShort(static_cast<unsigned short>(left->GetValShort()) >> right->GetValInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Save1State(std::ostream &ostr) override
|
||||||
|
{
|
||||||
|
return WriteShort(ostr, m_val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -37,9 +37,9 @@ bool CBotVarString::Ne(CBotVar* left, CBotVar* right)
|
||||||
return left->GetValString() != right->GetValString();
|
return left->GetValString() != right->GetValString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBotVarString::Save1State(FILE* pf)
|
bool CBotVarString::Save1State(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
return WriteString(pf, m_val);
|
return WriteString(ostr, m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
bool Eq(CBotVar* left, CBotVar* right) override;
|
bool Eq(CBotVar* left, CBotVar* right) override;
|
||||||
bool Ne(CBotVar* left, CBotVar* right) override;
|
bool Ne(CBotVar* left, CBotVar* right) override;
|
||||||
|
|
||||||
bool Save1State(FILE* pf) override;
|
bool Save1State(std::ostream &ostr) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -74,6 +74,13 @@ public:
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void SetValue(T val)
|
||||||
|
{
|
||||||
|
this->m_val = val;
|
||||||
|
this->m_binit = CBotVar::InitType::DEF;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! The value
|
//! The value
|
||||||
T m_val;
|
T m_val;
|
||||||
|
@ -86,18 +93,59 @@ template <typename T, CBotType type>
|
||||||
class CBotVarNumberBase : public CBotVarValue<T, type>
|
class CBotVarNumberBase : public CBotVarValue<T, type>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CBotVarNumberBase(const CBotToken &name) : CBotVarValue<T, type>(name) {}
|
CBotVarNumberBase(const CBotToken &name) : CBotVarValue<T, type>(name)
|
||||||
|
{
|
||||||
|
this->m_val = static_cast<T>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValByte(signed char val) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValShort(short val) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValChar(uint32_t val) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(val));
|
||||||
|
}
|
||||||
|
|
||||||
void SetValInt(int val, const std::string &s = "") override
|
void SetValInt(int val, const std::string &s = "") override
|
||||||
{
|
{
|
||||||
this->m_val = static_cast<T>(val);
|
this->SetValue(static_cast<T>(val));
|
||||||
this->m_binit = CBotVar::InitType::DEF;
|
}
|
||||||
|
|
||||||
|
void SetValLong(long val) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetValFloat(float val) override
|
void SetValFloat(float val) override
|
||||||
{
|
{
|
||||||
this->m_val = static_cast<T>(val);
|
this->SetValue(static_cast<T>(val));
|
||||||
this->m_binit = CBotVar::InitType::DEF;
|
}
|
||||||
|
|
||||||
|
void SetValDouble(double val) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
signed char GetValByte() override
|
||||||
|
{
|
||||||
|
return static_cast<signed char>(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
short GetValShort() override
|
||||||
|
{
|
||||||
|
return static_cast<short>(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetValChar() override
|
||||||
|
{
|
||||||
|
return static_cast<uint32_t>(this->m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetValInt() override
|
int GetValInt() override
|
||||||
|
@ -105,19 +153,28 @@ public:
|
||||||
return static_cast<int>(this->m_val);
|
return static_cast<int>(this->m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long GetValLong() override
|
||||||
|
{
|
||||||
|
return static_cast<long>(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
float GetValFloat() override
|
float GetValFloat() override
|
||||||
{
|
{
|
||||||
return static_cast<float>(this->m_val);
|
return static_cast<float>(this->m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double GetValDouble() override
|
||||||
|
{
|
||||||
|
return static_cast<double>(this->m_val);
|
||||||
|
}
|
||||||
|
|
||||||
bool Eq(CBotVar* left, CBotVar* right) override
|
bool Eq(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
return left->GetValFloat() == right->GetValFloat();
|
return static_cast<T>(*left) == static_cast<T>(*right);
|
||||||
}
|
}
|
||||||
bool Ne(CBotVar* left, CBotVar* right) override
|
bool Ne(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
return left->GetValFloat() != right->GetValFloat();
|
return static_cast<T>(*left) != static_cast<T>(*right);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -132,33 +189,33 @@ public:
|
||||||
|
|
||||||
void Mul(CBotVar* left, CBotVar* right) override
|
void Mul(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
this->SetValFloat(left->GetValFloat() * right->GetValFloat());
|
this->SetValue(static_cast<T>(*left) * static_cast<T>(*right));
|
||||||
}
|
}
|
||||||
void Power(CBotVar* left, CBotVar* right) override
|
void Power(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
this->SetValFloat(pow(left->GetValFloat(), right->GetValFloat()));
|
this->SetValue(pow(static_cast<T>(*left), static_cast<T>(*right)));
|
||||||
}
|
}
|
||||||
CBotError Div(CBotVar* left, CBotVar* right) override
|
CBotError Div(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
float r = right->GetValFloat();
|
T r = static_cast<T>(*right);
|
||||||
if (r == 0) return CBotErrZeroDiv;
|
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
|
||||||
this->SetValFloat(left->GetValFloat() / r);
|
this->SetValue(static_cast<T>(*left) / r);
|
||||||
return CBotNoErr;
|
return CBotNoErr;
|
||||||
}
|
}
|
||||||
CBotError Modulo(CBotVar* left, CBotVar* right) override
|
CBotError Modulo(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
float r = right->GetValFloat();
|
T r = static_cast<T>(*right);
|
||||||
if (r == 0) return CBotErrZeroDiv;
|
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
|
||||||
this->SetValFloat(fmod(left->GetValFloat(), r));
|
this->SetValue(fmod(static_cast<T>(*left), r));
|
||||||
return CBotNoErr;
|
return CBotNoErr;
|
||||||
}
|
}
|
||||||
void Add(CBotVar* left, CBotVar* right) override
|
void Add(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
this->SetValFloat(left->GetValFloat() + right->GetValFloat());
|
this->SetValue(static_cast<T>(*left) + static_cast<T>(*right));
|
||||||
}
|
}
|
||||||
void Sub(CBotVar* left, CBotVar* right) override
|
void Sub(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
this->SetValFloat(left->GetValFloat() - right->GetValFloat());
|
this->SetValue(static_cast<T>(*left) - static_cast<T>(*right));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Neg() override
|
void Neg() override
|
||||||
|
@ -176,21 +233,65 @@ public:
|
||||||
|
|
||||||
bool Lo(CBotVar* left, CBotVar* right) override
|
bool Lo(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
return left->GetValFloat() < right->GetValFloat();
|
return static_cast<T>(*left) < static_cast<T>(*right);
|
||||||
}
|
}
|
||||||
bool Hi(CBotVar* left, CBotVar* right) override
|
bool Hi(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
return left->GetValFloat() > right->GetValFloat();
|
return static_cast<T>(*left) > static_cast<T>(*right);
|
||||||
}
|
}
|
||||||
bool Ls(CBotVar* left, CBotVar* right) override
|
bool Ls(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
return left->GetValFloat() <= right->GetValFloat();
|
return static_cast<T>(*left) <= static_cast<T>(*right);
|
||||||
}
|
}
|
||||||
bool Hs(CBotVar* left, CBotVar* right) override
|
bool Hs(CBotVar* left, CBotVar* right) override
|
||||||
{
|
{
|
||||||
return left->GetValFloat() >= right->GetValFloat();
|
return static_cast<T>(*left) >= static_cast<T>(*right);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* \brief An integer variable (byte, short, char, int, long)
|
||||||
|
*/
|
||||||
|
template <typename T, CBotType type>
|
||||||
|
class CBotVarInteger : public CBotVarNumber<T, type>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotVarInteger(const CBotToken &name) : CBotVarNumber<T, type>(name) {}
|
||||||
|
|
||||||
|
CBotError Modulo(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
T r = static_cast<T>(*right);
|
||||||
|
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
|
||||||
|
this->SetValue(static_cast<T>(*left) % r);
|
||||||
|
return CBotNoErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XOr(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(*left) ^ static_cast<T>(*right));
|
||||||
|
}
|
||||||
|
void And(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(*left) & static_cast<T>(*right));
|
||||||
|
}
|
||||||
|
void Or(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(*left) | static_cast<T>(*right));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SL(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(*left) << right->GetValInt());
|
||||||
|
}
|
||||||
|
void ASR(CBotVar* left, CBotVar* right) override
|
||||||
|
{
|
||||||
|
this->SetValue(static_cast<T>(*left) >> right->GetValInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Not() override
|
||||||
|
{
|
||||||
|
this->m_val = ~(this->m_val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
||||||
|
|
|
@ -44,6 +44,8 @@ set(SOURCES
|
||||||
CBotInstr/CBotEmpty.h
|
CBotInstr/CBotEmpty.h
|
||||||
CBotInstr/CBotExprLitBool.cpp
|
CBotInstr/CBotExprLitBool.cpp
|
||||||
CBotInstr/CBotExprLitBool.h
|
CBotInstr/CBotExprLitBool.h
|
||||||
|
CBotInstr/CBotExprLitChar.cpp
|
||||||
|
CBotInstr/CBotExprLitChar.h
|
||||||
CBotInstr/CBotExprLitNan.cpp
|
CBotInstr/CBotExprLitNan.cpp
|
||||||
CBotInstr/CBotExprLitNan.h
|
CBotInstr/CBotExprLitNan.h
|
||||||
CBotInstr/CBotExprLitNull.cpp
|
CBotInstr/CBotExprLitNull.cpp
|
||||||
|
@ -127,14 +129,19 @@ set(SOURCES
|
||||||
CBotVar/CBotVarArray.h
|
CBotVar/CBotVarArray.h
|
||||||
CBotVar/CBotVarBoolean.cpp
|
CBotVar/CBotVarBoolean.cpp
|
||||||
CBotVar/CBotVarBoolean.h
|
CBotVar/CBotVarBoolean.h
|
||||||
|
CBotVar/CBotVarByte.h
|
||||||
|
CBotVar/CBotVarChar.h
|
||||||
CBotVar/CBotVarClass.cpp
|
CBotVar/CBotVarClass.cpp
|
||||||
CBotVar/CBotVarClass.h
|
CBotVar/CBotVarClass.h
|
||||||
|
CBotVar/CBotVarDouble.h
|
||||||
CBotVar/CBotVarFloat.cpp
|
CBotVar/CBotVarFloat.cpp
|
||||||
CBotVar/CBotVarFloat.h
|
CBotVar/CBotVarFloat.h
|
||||||
CBotVar/CBotVarInt.cpp
|
CBotVar/CBotVarInt.cpp
|
||||||
CBotVar/CBotVarInt.h
|
CBotVar/CBotVarInt.h
|
||||||
|
CBotVar/CBotVarLong.h
|
||||||
CBotVar/CBotVarPointer.cpp
|
CBotVar/CBotVarPointer.cpp
|
||||||
CBotVar/CBotVarPointer.h
|
CBotVar/CBotVarPointer.h
|
||||||
|
CBotVar/CBotVarShort.h
|
||||||
CBotVar/CBotVarString.cpp
|
CBotVar/CBotVarString.cpp
|
||||||
CBotVar/CBotVarString.h
|
CBotVar/CBotVarString.h
|
||||||
stdlib/Compilation.cpp
|
stdlib/Compilation.cpp
|
||||||
|
|
|
@ -742,6 +742,8 @@ void InitializeRestext()
|
||||||
stringsCbot[CBot::CBotErrHexDigits] = TR("Missing hex digits after escape sequence");
|
stringsCbot[CBot::CBotErrHexDigits] = TR("Missing hex digits after escape sequence");
|
||||||
stringsCbot[CBot::CBotErrHexRange] = TR("Hex value out of range");
|
stringsCbot[CBot::CBotErrHexRange] = TR("Hex value out of range");
|
||||||
stringsCbot[CBot::CBotErrUnicodeName] = TR("Invalid universal character name");
|
stringsCbot[CBot::CBotErrUnicodeName] = TR("Invalid universal character name");
|
||||||
|
stringsCbot[CBot::CBotErrCharEmpty] = TR("Empty character constant");
|
||||||
|
stringsCbot[CBot::CBotErrRedefCase] = TR("Duplicate label in switch");
|
||||||
|
|
||||||
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
|
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
|
||||||
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");
|
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");
|
||||||
|
|
|
@ -4449,10 +4449,8 @@ void CRobotMain::SaveOneScript(CObject *obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Saves the stack of the program in execution of a robot
|
//! Saves the stack of the program in execution of a robot
|
||||||
bool CRobotMain::SaveFileStack(CObject *obj, FILE *file, int objRank)
|
bool CRobotMain::SaveFileStack(CObject *obj, std::ostream &ostr)
|
||||||
{
|
{
|
||||||
if (objRank == -1) return true;
|
|
||||||
|
|
||||||
if (! obj->Implements(ObjectInterfaceType::Programmable)) return true;
|
if (! obj->Implements(ObjectInterfaceType::Programmable)) return true;
|
||||||
|
|
||||||
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
|
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
|
||||||
|
@ -4460,14 +4458,24 @@ bool CRobotMain::SaveFileStack(CObject *obj, FILE *file, int objRank)
|
||||||
ObjectType type = obj->GetType();
|
ObjectType type = obj->GetType();
|
||||||
if (type == OBJECT_HUMAN) return true;
|
if (type == OBJECT_HUMAN) return true;
|
||||||
|
|
||||||
return programmable->WriteStack(file);
|
long status = 1;
|
||||||
|
std::stringstream sstr("");
|
||||||
|
|
||||||
|
if (!programmable->WriteStack(sstr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("WriteStack failed at object id = %i\n", obj->GetID());
|
||||||
|
status = 100; // marked bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CBot::WriteLong(ostr, status)) return false;
|
||||||
|
if (!CBot::WriteStream(ostr, sstr)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Resumes the execution stack of the program in a robot
|
//! Resumes the execution stack of the program in a robot
|
||||||
bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank)
|
bool CRobotMain::ReadFileStack(CObject *obj, std::istream &istr)
|
||||||
{
|
{
|
||||||
if (objRank == -1) return true;
|
|
||||||
|
|
||||||
if (! obj->Implements(ObjectInterfaceType::Programmable)) return true;
|
if (! obj->Implements(ObjectInterfaceType::Programmable)) return true;
|
||||||
|
|
||||||
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
|
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
|
||||||
|
@ -4475,7 +4483,29 @@ bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank)
|
||||||
ObjectType type = obj->GetType();
|
ObjectType type = obj->GetType();
|
||||||
if (type == OBJECT_HUMAN) return true;
|
if (type == OBJECT_HUMAN) return true;
|
||||||
|
|
||||||
return programmable->ReadStack(file);
|
long status;
|
||||||
|
if (!CBot::ReadLong(istr, status)) return false;
|
||||||
|
|
||||||
|
if (status == 100) // was marked bad ?
|
||||||
|
{
|
||||||
|
if (!CBot::ReadLong(istr, status)) return false;
|
||||||
|
if (!istr.seekg(status, istr.cur)) return false;
|
||||||
|
return true; // next program
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 1)
|
||||||
|
{
|
||||||
|
std::stringstream sstr("");
|
||||||
|
if (!CBot::ReadStream(istr, sstr)) return false;
|
||||||
|
|
||||||
|
if (!programmable->ReadStack(sstr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("ReadStack failed at object id = %i\n", obj->GetID());
|
||||||
|
}
|
||||||
|
return true; // next program
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // error: status == ??
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> CRobotMain::GetNewScriptNames(ObjectType type)
|
std::vector<std::string> CRobotMain::GetNewScriptNames(ObjectType type)
|
||||||
|
@ -4670,25 +4700,36 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes the file of stacks of execution.
|
// Writes the file of stacks of execution.
|
||||||
FILE* file = CBot::fOpen((CResourceManager::GetSaveLocation() + "/" + filecbot).c_str(), "wb");
|
COutputStream ostr(filecbot);
|
||||||
if (file == nullptr) return false;
|
if (!ostr.is_open()) return false;
|
||||||
|
|
||||||
|
bool bError = false;
|
||||||
long version = 1;
|
long version = 1;
|
||||||
CBot::fWrite(&version, sizeof(long), 1, file); // version of COLOBOT
|
CBot::WriteLong(ostr, version); // version of COLOBOT
|
||||||
version = CBot::CBotProgram::GetVersion();
|
version = CBot::CBotProgram::GetVersion();
|
||||||
CBot::fWrite(&version, sizeof(long), 1, file); // version of CBOT
|
CBot::WriteLong(ostr, version); // version of CBOT
|
||||||
|
CBot::WriteWord(ostr, 0); // TODO
|
||||||
|
|
||||||
objRank = 0;
|
|
||||||
for (CObject* obj : m_objMan->GetAllObjects())
|
for (CObject* obj : m_objMan->GetAllObjects())
|
||||||
{
|
{
|
||||||
if (obj->GetType() == OBJECT_TOTO) continue;
|
if (obj->GetType() == OBJECT_TOTO) continue;
|
||||||
if (IsObjectBeingTransported(obj)) continue;
|
if (IsObjectBeingTransported(obj)) continue;
|
||||||
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue;
|
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue;
|
||||||
|
|
||||||
if (!SaveFileStack(obj, file, objRank++)) break;
|
if (!SaveFileStack(obj, ostr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("SaveFileStack failed at object id = %i\n", obj->GetID());
|
||||||
|
bError = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CBot::CBotClass::SaveStaticState(file);
|
|
||||||
CBot::fClose(file);
|
if (!bError && !CBot::CBotClass::SaveStaticState(ostr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("CBotClass save static state failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ostr.close();
|
||||||
|
|
||||||
if (!emergencySave)
|
if (!emergencySave)
|
||||||
{
|
{
|
||||||
|
@ -4846,29 +4887,48 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
|
||||||
m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE);
|
m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE);
|
||||||
|
|
||||||
// Reads the file of stacks of execution.
|
// Reads the file of stacks of execution.
|
||||||
FILE* file = CBot::fOpen((CResourceManager::GetSaveLocation() + "/" + filecbot).c_str(), "rb");
|
CInputStream istr(filecbot);
|
||||||
if (file != nullptr)
|
|
||||||
|
if (istr.is_open())
|
||||||
{
|
{
|
||||||
long version;
|
bool bError = false;
|
||||||
CBot::fRead(&version, sizeof(long), 1, file); // version of COLOBOT
|
long version = 0;
|
||||||
|
CBot::ReadLong(istr, version); // version of COLOBOT
|
||||||
if (version == 1)
|
if (version == 1)
|
||||||
{
|
{
|
||||||
CBot::fRead(&version, sizeof(long), 1, file); // version of CBOT
|
CBot::ReadLong(istr, version); // version of CBOT
|
||||||
if (version == CBot::CBotProgram::GetVersion())
|
if (version == CBot::CBotProgram::GetVersion())
|
||||||
{
|
{
|
||||||
objRank = 0;
|
unsigned short flag;
|
||||||
for (CObject* obj : m_objMan->GetAllObjects())
|
CBot::ReadWord(istr, flag); // TODO
|
||||||
|
bError = (flag != 0);
|
||||||
|
|
||||||
|
if (!bError) for (CObject* obj : m_objMan->GetAllObjects())
|
||||||
{
|
{
|
||||||
if (obj->GetType() == OBJECT_TOTO) continue;
|
if (obj->GetType() == OBJECT_TOTO) continue;
|
||||||
if (IsObjectBeingTransported(obj)) continue;
|
if (IsObjectBeingTransported(obj)) continue;
|
||||||
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue;
|
if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast<CDestroyableObject*>(obj)->IsDying()) continue;
|
||||||
|
|
||||||
if (!ReadFileStack(obj, file, objRank++)) break;
|
if (!ReadFileStack(obj, istr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("ReadFileStack failed at object id = %i\n", obj->GetID());
|
||||||
|
bError = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bError && !CBot::CBotClass::RestoreStaticState(istr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("CBotClass restore static state failed\n");
|
||||||
|
bError = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
GetLogger()->Error("cbot.run file is wrong version: %i\n", version);
|
||||||
}
|
}
|
||||||
CBot::CBotClass::RestoreStaticState(file);
|
|
||||||
CBot::fClose(file);
|
if (bError) GetLogger()->Error("Restoring CBOT state failed at stream position: %li\n", istr.tellg());
|
||||||
|
istr.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED);
|
m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED);
|
||||||
|
|
|
@ -308,8 +308,8 @@ public:
|
||||||
|
|
||||||
void SaveAllScript();
|
void SaveAllScript();
|
||||||
void SaveOneScript(CObject *obj);
|
void SaveOneScript(CObject *obj);
|
||||||
bool SaveFileStack(CObject *obj, FILE *file, int objRank);
|
bool SaveFileStack(CObject *obj, std::ostream &ostr);
|
||||||
bool ReadFileStack(CObject *obj, FILE *file, int objRank);
|
bool ReadFileStack(CObject *obj, std::istream &istr);
|
||||||
|
|
||||||
//! Return list of scripts to load to robot created in BotFactory
|
//! Return list of scripts to load to robot created in BotFactory
|
||||||
std::vector<std::string> GetNewScriptNames(ObjectType type);
|
std::vector<std::string> GetNewScriptNames(ObjectType type);
|
||||||
|
|
|
@ -143,24 +143,43 @@ bool CProgrammableObjectImpl::IsProgram()
|
||||||
|
|
||||||
// Load a stack of script implementation from a file.
|
// Load a stack of script implementation from a file.
|
||||||
|
|
||||||
bool CProgrammableObjectImpl::ReadStack(FILE *file)
|
bool CProgrammableObjectImpl::ReadStack(std::istream &istr)
|
||||||
{
|
{
|
||||||
short op;
|
short op;
|
||||||
|
|
||||||
CBot::fRead(&op, sizeof(short), 1, file);
|
if (!CBot::ReadShort(istr, op)) return false;
|
||||||
if ( op == 1 ) // run ?
|
if ( op == 1 ) // run ?
|
||||||
{
|
{
|
||||||
CBot::fRead(&op, sizeof(short), 1, file); // program rank
|
if (!CBot::ReadShort(istr, op)) return false; // program rank
|
||||||
if ( op >= 0 )
|
if ( op >= 0 )
|
||||||
{
|
{
|
||||||
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
|
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
|
||||||
{
|
{
|
||||||
assert(op < static_cast<int>(dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramCount()));
|
int count = static_cast<int>(dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramCount());
|
||||||
|
if (!(op < count))
|
||||||
|
{
|
||||||
|
GetLogger()->Info("Object program count: %i\n", count);
|
||||||
|
GetLogger()->Error("Error in file: program index out of range: %i\n", op);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_currentProgram = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgram(op);
|
m_currentProgram = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgram(op);
|
||||||
if ( !m_currentProgram->script->ReadStack(file) ) return false;
|
if (!m_currentProgram->script->ReadStack(istr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("Restore state failed at program index: %i\n", op);
|
||||||
|
int errNum = m_currentProgram->script->GetError();
|
||||||
|
if (errNum != 0)
|
||||||
|
{
|
||||||
|
std::string errStr;
|
||||||
|
m_currentProgram->script->GetError(errStr);
|
||||||
|
GetLogger()->Error("Program reports error: %i:(%s)\n", errNum, errStr.c_str());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
GetLogger()->Error("Object is not a program storage object\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +190,7 @@ bool CProgrammableObjectImpl::ReadStack(FILE *file)
|
||||||
|
|
||||||
// Save the script implementation stack of a file.
|
// Save the script implementation stack of a file.
|
||||||
|
|
||||||
bool CProgrammableObjectImpl::WriteStack(FILE *file)
|
bool CProgrammableObjectImpl::WriteStack(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
short op;
|
short op;
|
||||||
|
|
||||||
|
@ -179,21 +198,25 @@ bool CProgrammableObjectImpl::WriteStack(FILE *file)
|
||||||
m_currentProgram->script->IsRunning() )
|
m_currentProgram->script->IsRunning() )
|
||||||
{
|
{
|
||||||
op = 1; // run
|
op = 1; // run
|
||||||
CBot::fWrite(&op, sizeof(short), 1, file);
|
if (!CBot::WriteShort(ostr, op)) return false;
|
||||||
|
|
||||||
op = -1;
|
op = -1;
|
||||||
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
|
if (m_object->Implements(ObjectInterfaceType::ProgramStorage))
|
||||||
{
|
{
|
||||||
op = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramIndex(m_currentProgram);
|
op = dynamic_cast<CProgramStorageObject*>(m_object)->GetProgramIndex(m_currentProgram);
|
||||||
}
|
}
|
||||||
CBot::fWrite(&op, sizeof(short), 1, file);
|
if (!CBot::WriteShort(ostr, op)) return false;
|
||||||
|
|
||||||
return m_currentProgram->script->WriteStack(file);
|
if (!m_currentProgram->script->WriteStack(ostr))
|
||||||
|
{
|
||||||
|
GetLogger()->Error("Save state failed at program index: %i\n", op);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
op = 0; // stop
|
op = 0; // stop
|
||||||
CBot::fWrite(&op, sizeof(short), 1, file);
|
return CBot::WriteShort(ostr, op);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ public:
|
||||||
Program* GetCurrentProgram() override;
|
Program* GetCurrentProgram() override;
|
||||||
void StopProgram() override;
|
void StopProgram() override;
|
||||||
|
|
||||||
bool ReadStack(FILE *file) override;
|
bool ReadStack(std::istream &istr) override;
|
||||||
bool WriteStack(FILE *file) override;
|
bool WriteStack(std::ostream &ostr) override;
|
||||||
|
|
||||||
void TraceRecordStart() override;
|
void TraceRecordStart() override;
|
||||||
void TraceRecordStop() override;
|
void TraceRecordStop() override;
|
||||||
|
|
|
@ -53,9 +53,9 @@ public:
|
||||||
virtual bool IsProgram() = 0;
|
virtual bool IsProgram() = 0;
|
||||||
|
|
||||||
//! Save current execution status to file
|
//! Save current execution status to file
|
||||||
virtual bool WriteStack(FILE *file) = 0;
|
virtual bool WriteStack(std::ostream &ostr) = 0;
|
||||||
//! Read current execution status from file
|
//! Read current execution status from file
|
||||||
virtual bool ReadStack(FILE *file) = 0;
|
virtual bool ReadStack(std::istream &istr) = 0;
|
||||||
|
|
||||||
//! Start recording trace
|
//! Start recording trace
|
||||||
virtual void TraceRecordStart() = 0;
|
virtual void TraceRecordStart() = 0;
|
||||||
|
|
|
@ -236,8 +236,13 @@ std::string GetHelpFilename(const char *token)
|
||||||
if ( strcmp(token, "continue" ) == 0 ) helpfile = "cbot/continue";
|
if ( strcmp(token, "continue" ) == 0 ) helpfile = "cbot/continue";
|
||||||
if ( strcmp(token, "return" ) == 0 ) helpfile = "cbot/return";
|
if ( strcmp(token, "return" ) == 0 ) helpfile = "cbot/return";
|
||||||
if ( strcmp(token, "sizeof" ) == 0 ) helpfile = "cbot/sizeof";
|
if ( strcmp(token, "sizeof" ) == 0 ) helpfile = "cbot/sizeof";
|
||||||
|
if ( strcmp(token, "byte" ) == 0 ) helpfile = "cbot/byte";
|
||||||
|
if ( strcmp(token, "short" ) == 0 ) helpfile = "cbot/short";
|
||||||
|
if ( strcmp(token, "char" ) == 0 ) helpfile = "cbot/char";
|
||||||
if ( strcmp(token, "int" ) == 0 ) helpfile = "cbot/int";
|
if ( strcmp(token, "int" ) == 0 ) helpfile = "cbot/int";
|
||||||
|
if ( strcmp(token, "long" ) == 0 ) helpfile = "cbot/long";
|
||||||
if ( strcmp(token, "float" ) == 0 ) helpfile = "cbot/float";
|
if ( strcmp(token, "float" ) == 0 ) helpfile = "cbot/float";
|
||||||
|
if ( strcmp(token, "double" ) == 0 ) helpfile = "cbot/double";
|
||||||
if ( strcmp(token, "bool" ) == 0 ) helpfile = "cbot/bool";
|
if ( strcmp(token, "bool" ) == 0 ) helpfile = "cbot/bool";
|
||||||
if ( strcmp(token, "string" ) == 0 ) helpfile = "cbot/string";
|
if ( strcmp(token, "string" ) == 0 ) helpfile = "cbot/string";
|
||||||
if ( strcmp(token, "point" ) == 0 ) helpfile = "cbot/point";
|
if ( strcmp(token, "point" ) == 0 ) helpfile = "cbot/point";
|
||||||
|
@ -388,8 +393,13 @@ std::string GetHelpFilename(const char *token)
|
||||||
bool IsType(const char *token)
|
bool IsType(const char *token)
|
||||||
{
|
{
|
||||||
if ( strcmp(token, "void" ) == 0 ) return true;
|
if ( strcmp(token, "void" ) == 0 ) return true;
|
||||||
|
if ( strcmp(token, "byte" ) == 0 ) return true;
|
||||||
|
if ( strcmp(token, "short" ) == 0 ) return true;
|
||||||
|
if ( strcmp(token, "char" ) == 0 ) return true;
|
||||||
if ( strcmp(token, "int" ) == 0 ) return true;
|
if ( strcmp(token, "int" ) == 0 ) return true;
|
||||||
|
if ( strcmp(token, "long" ) == 0 ) return true;
|
||||||
if ( strcmp(token, "float" ) == 0 ) return true;
|
if ( strcmp(token, "float" ) == 0 ) return true;
|
||||||
|
if ( strcmp(token, "double" ) == 0 ) return true;
|
||||||
if ( strcmp(token, "bool" ) == 0 ) return true;
|
if ( strcmp(token, "bool" ) == 0 ) return true;
|
||||||
if ( strcmp(token, "string" ) == 0 ) return true;
|
if ( strcmp(token, "string" ) == 0 ) return true;
|
||||||
if ( strcmp(token, "point" ) == 0 ) return true;
|
if ( strcmp(token, "point" ) == 0 ) return true;
|
||||||
|
|
|
@ -589,16 +589,17 @@ void CScript::UpdateList(Ui::CList* list)
|
||||||
list->SetState(Ui::STATE_ENABLE);
|
list->SetState(Ui::STATE_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colorize a string literal with escape sequences also colored
|
// Colorize a string or character literal with escape sequences also colored
|
||||||
|
|
||||||
static void HighlightString(Ui::CEdit* edit, const std::string& s, int start)
|
static void HighlightString(Ui::CEdit* edit, const std::string& s, int start)
|
||||||
{
|
{
|
||||||
edit->SetFormat(start, start + 1, Gfx::FONT_HIGHLIGHT_STRING);
|
edit->SetFormat(start, start + 1, Gfx::FONT_HIGHLIGHT_STRING);
|
||||||
|
|
||||||
auto it = s.cbegin() + 1;
|
auto it = s.cbegin();
|
||||||
|
char endQuote = *(it++);
|
||||||
|
|
||||||
++start;
|
++start;
|
||||||
while (it != s.cend() && *it != '\"')
|
while (it != s.cend() && *it != endQuote)
|
||||||
{
|
{
|
||||||
if (*(it++) != '\\') // not escape sequence
|
if (*(it++) != '\\') // not escape sequence
|
||||||
{
|
{
|
||||||
|
@ -697,7 +698,7 @@ void CScript::ColorizeScript(Ui::CEdit* edit, int rangeStart, int rangeEnd)
|
||||||
{
|
{
|
||||||
color = Gfx::FONT_HIGHLIGHT_STRING;
|
color = Gfx::FONT_HIGHLIGHT_STRING;
|
||||||
}
|
}
|
||||||
else if (type == CBot::TokenTypString) // string literals
|
else if (type == CBot::TokenTypString || type == CBot::TokenTypChar) // string literals and character literals
|
||||||
{
|
{
|
||||||
HighlightString(edit, token, cursor1);
|
HighlightString(edit, token, cursor1);
|
||||||
bt = bt->GetNext();
|
bt = bt->GetNext();
|
||||||
|
@ -1032,16 +1033,16 @@ bool CScript::WriteScript(const char* filename)
|
||||||
|
|
||||||
// Reads a stack of script by execution as a file.
|
// Reads a stack of script by execution as a file.
|
||||||
|
|
||||||
bool CScript::ReadStack(FILE *file)
|
bool CScript::ReadStack(std::istream &istr)
|
||||||
{
|
{
|
||||||
int nb;
|
int nb;
|
||||||
|
|
||||||
CBot::fRead(&nb, sizeof(int), 1, file);
|
if (!CBot::ReadInt(istr, nb)) return false;
|
||||||
CBot::fRead(&m_ipf, sizeof(int), 1, file);
|
if (!CBot::ReadInt(istr, m_ipf)) return false;
|
||||||
CBot::fRead(&m_errMode, sizeof(int), 1, file);
|
if (!CBot::ReadInt(istr, m_errMode)) return false;
|
||||||
|
|
||||||
if (m_botProg == nullptr) return false;
|
if (m_botProg == nullptr) return false;
|
||||||
if ( !m_botProg->RestoreState(file) ) return false;
|
if (!m_botProg->RestoreState(istr)) return false;
|
||||||
|
|
||||||
m_bRun = true;
|
m_bRun = true;
|
||||||
m_bContinue = false;
|
m_bContinue = false;
|
||||||
|
@ -1050,16 +1051,16 @@ bool CScript::ReadStack(FILE *file)
|
||||||
|
|
||||||
// Writes a stack of script by execution as a file.
|
// Writes a stack of script by execution as a file.
|
||||||
|
|
||||||
bool CScript::WriteStack(FILE *file)
|
bool CScript::WriteStack(std::ostream &ostr)
|
||||||
{
|
{
|
||||||
int nb;
|
int nb;
|
||||||
|
|
||||||
nb = 2;
|
nb = 2;
|
||||||
CBot::fWrite(&nb, sizeof(int), 1, file);
|
if (!CBot::WriteInt(ostr, nb)) return false;
|
||||||
CBot::fWrite(&m_ipf, sizeof(int), 1, file);
|
if (!CBot::WriteInt(ostr, m_ipf)) return false;
|
||||||
CBot::fWrite(&m_errMode, sizeof(int), 1, file);
|
if (!CBot::WriteInt(ostr, m_errMode)) return false;
|
||||||
|
|
||||||
return m_botProg->SaveState(file);
|
return m_botProg->SaveState(ostr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -88,8 +88,8 @@ public:
|
||||||
bool SendScript(const char* text);
|
bool SendScript(const char* text);
|
||||||
bool ReadScript(const char* filename);
|
bool ReadScript(const char* filename);
|
||||||
bool WriteScript(const char* filename);
|
bool WriteScript(const char* filename);
|
||||||
bool ReadStack(FILE *file);
|
bool ReadStack(std::istream &istr);
|
||||||
bool WriteStack(FILE *file);
|
bool WriteStack(std::ostream &ostr);
|
||||||
bool Compare(CScript* other);
|
bool Compare(CScript* other);
|
||||||
|
|
||||||
void SetFilename(const std::string &filename);
|
void SetFilename(const std::string &filename);
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
extern bool g_cbotTestSaveState;
|
||||||
|
bool g_cbotTestSaveState = false;
|
||||||
|
|
||||||
using namespace CBot;
|
using namespace CBot;
|
||||||
|
|
||||||
class CBotUT : public testing::Test
|
class CBotUT : public testing::Test
|
||||||
|
@ -197,6 +200,23 @@ private:
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TestSaveAndRestore(CBotProgram* program)
|
||||||
|
{
|
||||||
|
std::stringstream sstr("");
|
||||||
|
// save
|
||||||
|
if (!program->SaveState(sstr))
|
||||||
|
throw CBotTestFail("CBotProgram::SaveState Failed");
|
||||||
|
|
||||||
|
if (!CBotClass::SaveStaticState(sstr))
|
||||||
|
throw CBotTestFail("CBotClass::SaveStaticState Failed");
|
||||||
|
// restore
|
||||||
|
if (!program->RestoreState(sstr))
|
||||||
|
throw CBotTestFail("CBotProgram::RestoreState Failed");
|
||||||
|
|
||||||
|
if (!CBotClass::RestoreStaticState(sstr))
|
||||||
|
throw CBotTestFail("CBotClass::RestoreStaticState Failed");
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<CBotProgram> ExecuteTest(const std::string& code, CBotError expectedError = CBotNoErr)
|
std::unique_ptr<CBotProgram> ExecuteTest(const std::string& code, CBotError expectedError = CBotNoErr)
|
||||||
{
|
{
|
||||||
|
@ -231,7 +251,17 @@ protected:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
program->Start(test);
|
program->Start(test);
|
||||||
while (!program->Run());
|
if (g_cbotTestSaveState)
|
||||||
|
{
|
||||||
|
while (!program->Run(nullptr, 0)) // save/restore at each step
|
||||||
|
{
|
||||||
|
TestSaveAndRestore(program.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (!program->Run(nullptr, 0)); // execute in step mode
|
||||||
|
}
|
||||||
program->GetError(error, cursor1, cursor2);
|
program->GetError(error, cursor1, cursor2);
|
||||||
if (error != expectedRuntimeError)
|
if (error != expectedRuntimeError)
|
||||||
{
|
{
|
||||||
|
@ -575,6 +605,127 @@ TEST_F(CBotUT, VarImplicitCast)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, IntegerMathNearLimits_Issue993)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void Test_Issue993() {\n"
|
||||||
|
" ASSERT(-2147483600 * 1 == -2147483600);\n"
|
||||||
|
" ASSERT( 2147483600 * 1 == 2147483600);\n"
|
||||||
|
" ASSERT( 2147483646 * 1 == 2147483646);\n"
|
||||||
|
" ASSERT( 2147483646 * -1 == -2147483646);\n"
|
||||||
|
" ASSERT( 2147483000 * -1 == -2147483000);\n"
|
||||||
|
" ASSERT( 2147483000 * 1 == 2147483000);\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, BinaryLiterals)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void TestBinaryLiterals() {\n"
|
||||||
|
" ASSERT( 8 == 0b00001000);\n"
|
||||||
|
" ASSERT( 12 == 0b00001100);\n"
|
||||||
|
" ASSERT( 16 == 0b00010000);\n"
|
||||||
|
" ASSERT( 24 == 0b00011000);\n"
|
||||||
|
" ASSERT( 32 == 0b00100000);\n"
|
||||||
|
" ASSERT( 48 == 0b00110000);\n"
|
||||||
|
" ASSERT( 64 == 0b01000000);\n"
|
||||||
|
" ASSERT( 96 == 0b01100000);\n"
|
||||||
|
" ASSERT(128 == 0b10000000);\n"
|
||||||
|
" ASSERT(192 == 0b11000000);\n"
|
||||||
|
" ASSERT(256 == 0b100000000);\n"
|
||||||
|
" ASSERT(384 == 0b110000000);\n"
|
||||||
|
" ASSERT(512 == 0b1000000000);\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, TestSwitchCase)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void Test_Switch_Case() {\n"
|
||||||
|
" int n = 0, c = 0;\n"
|
||||||
|
" for (int i = -9; i < 11; ++i) {\n"
|
||||||
|
" switch (i) {\n"
|
||||||
|
" case -9: n = -9; ++c; break;\n"
|
||||||
|
" case -8: n = -8; ++c; break;\n"
|
||||||
|
" case -7: n = -7; ++c; break;\n"
|
||||||
|
" case -6: n = -6; ++c; break;\n"
|
||||||
|
" case -5: n = -5; ++c; break;\n"
|
||||||
|
" case -4: n = -4; ++c; break;\n"
|
||||||
|
" case -3: n = -3; ++c; break;\n"
|
||||||
|
" case -2: n = -2; ++c; break;\n"
|
||||||
|
" case -1: n = -1; ++c; break;\n"
|
||||||
|
" case 0: n = 0; ++c; break;\n"
|
||||||
|
" case 1: n = 1; ++c; break;\n"
|
||||||
|
" case 2: n = 2; ++c; break;\n"
|
||||||
|
" case 3: n = 3; ++c; break;\n"
|
||||||
|
" case 4: n = 4; ++c; break;\n"
|
||||||
|
" case 5: n = 5; ++c; break;\n"
|
||||||
|
" case 6: n = 6; ++c; break;\n"
|
||||||
|
" case 7: n = 7; ++c; break;\n"
|
||||||
|
" case 8: n = 8; ++c; break;\n"
|
||||||
|
" case 9: n = 9; ++c; break;\n"
|
||||||
|
" default: n = 10; ++c; break;\n"
|
||||||
|
" }\n"
|
||||||
|
" ASSERT(n == i);\n"
|
||||||
|
" }\n"
|
||||||
|
" ASSERT(n == 10);\n"
|
||||||
|
" ASSERT(c == 20);\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void Test_Case_With_Math() {\n"
|
||||||
|
" int n = 0, c = 0;\n"
|
||||||
|
" for (int i = -9; i < 11; ++i) {\n"
|
||||||
|
" switch (i * 10) {\n"
|
||||||
|
" case -9*10: n = -90; ++c; break;\n"
|
||||||
|
" case -8*10: n = -80; ++c; break;\n"
|
||||||
|
" case -7*10: n = -70; ++c; break;\n"
|
||||||
|
" case -6*10: n = -60; ++c; break;\n"
|
||||||
|
" case -5*10: n = -50; ++c; break;\n"
|
||||||
|
" case -4*10: n = -40; ++c; break;\n"
|
||||||
|
" case -3*10: n = -30; ++c; break;\n"
|
||||||
|
" case -2*10: n = -20; ++c; break;\n"
|
||||||
|
" case -1*10: n = -10; ++c; break;\n"
|
||||||
|
" case 0*10: n = 0; ++c; break;\n"
|
||||||
|
" case 1*10: n = 10; ++c; break;\n"
|
||||||
|
" case 2*10: n = 20; ++c; break;\n"
|
||||||
|
" case 3*10: n = 30; ++c; break;\n"
|
||||||
|
" case 4*10: n = 40; ++c; break;\n"
|
||||||
|
" case 5*10: n = 50; ++c; break;\n"
|
||||||
|
" case 6*10: n = 60; ++c; break;\n"
|
||||||
|
" case 7*10: n = 70; ++c; break;\n"
|
||||||
|
" case 8*10: n = 80; ++c; break;\n"
|
||||||
|
" case 9*10: n = 90; ++c; break;\n"
|
||||||
|
" default: n = 100; ++c; break;\n"
|
||||||
|
" }\n"
|
||||||
|
" ASSERT(n == i * 10);\n"
|
||||||
|
" }\n"
|
||||||
|
" ASSERT(n == 100);\n"
|
||||||
|
" ASSERT(c == 20);\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void Duplicate_Case() {\n"
|
||||||
|
" switch(0) {\n"
|
||||||
|
" case 1000:\n"
|
||||||
|
" case 10*100:\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrRedefCase
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void Duplicate_Default() {\n"
|
||||||
|
" switch(0) {\n"
|
||||||
|
" default:\n"
|
||||||
|
" default:\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrRedefCase
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(CBotUT, ToString)
|
TEST_F(CBotUT, ToString)
|
||||||
{
|
{
|
||||||
ExecuteTest(
|
ExecuteTest(
|
||||||
|
@ -1708,6 +1859,107 @@ TEST_F(CBotUT, StringFunctions)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, LiteralCharacters)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void TestCharValue()\n"
|
||||||
|
"{\n"
|
||||||
|
" ASSERT('A' == 65);\n"
|
||||||
|
" ASSERT('B' == 66);\n"
|
||||||
|
" ASSERT('C' == 67);\n"
|
||||||
|
" ASSERT('\\a' == 0x07);\n"
|
||||||
|
" ASSERT('\\b' == 0x08);\n"
|
||||||
|
" ASSERT('\\t' == 0x09);\n"
|
||||||
|
" ASSERT('\\n' == 0x0A);\n"
|
||||||
|
" ASSERT('\\v' == 0x0B);\n"
|
||||||
|
" ASSERT('\\f' == 0x0C);\n"
|
||||||
|
" ASSERT('\\r' == 0x0D);\n"
|
||||||
|
" ASSERT('\\\"' == 0x22);\n"
|
||||||
|
" ASSERT('\\\'' == 0x27);\n"
|
||||||
|
" ASSERT('\\\\' == 0x5C);\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestCharUnicodeEscape()\n"
|
||||||
|
"{\n"
|
||||||
|
" ASSERT('\\u0007' == '\\a');\n"
|
||||||
|
" ASSERT('\\u0008' == '\\b');\n"
|
||||||
|
" ASSERT('\\u0009' == '\\t');\n"
|
||||||
|
" ASSERT('\\u000A' == '\\n');\n"
|
||||||
|
" ASSERT('\\u000B' == '\\v');\n"
|
||||||
|
" ASSERT('\\u000C' == '\\f');\n"
|
||||||
|
" ASSERT('\\u000D' == '\\r');\n"
|
||||||
|
" ASSERT('\\u0022' == '\\\"');\n"
|
||||||
|
" ASSERT('\\u0027' == '\\\'');\n"
|
||||||
|
" ASSERT('\\u005C' == '\\\\');\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void AssignCharToString_ToUTF_8()\n"
|
||||||
|
"{\n"
|
||||||
|
" string test = '\\u00A9';\n"
|
||||||
|
" test += '\\u00AE';\n"
|
||||||
|
" ASSERT(test == \"\\xC2\\xA9\\xC2\\xAE\");\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void AddCharToString_ToUTF_8()\n"
|
||||||
|
"{\n"
|
||||||
|
" ASSERT(\"\" + 'A' + 'B' + 'C' == \"ABC\");\n"
|
||||||
|
" ASSERT(\"\" + '\\u00A9' == \"\\xC2\\xA9\");\n"
|
||||||
|
" ASSERT(\"\" + '\\u00AE' == \"\\xC2\\xAE\");\n"
|
||||||
|
" ASSERT(\"\" + '\\u262E' == \"\\xE2\\x98\\xAE\");\n"
|
||||||
|
" ASSERT(\"\" + '\\u262F' == \"\\xE2\\x98\\xAF\");\n"
|
||||||
|
" ASSERT(\"\" + '\\U0001F60E' == \"\\xF0\\x9F\\x98\\x8E\");\n"
|
||||||
|
" ASSERT(\"\" + '\\U0001F61C' == \"\\xF0\\x9F\\x98\\x9C\");\n"
|
||||||
|
" ASSERT(\"\" + '\\U0001F6E0' == \"\\xF0\\x9F\\x9B\\xA0\");\n"
|
||||||
|
" ASSERT(\"\" + '\\U0010FFFF' == \"\\xF4\\x8F\\xBF\\xBF\");\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void MissingEndQuote()\n"
|
||||||
|
"{\n"
|
||||||
|
" '\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrEndQuote
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void MissingEndQuote()\n"
|
||||||
|
"{\n"
|
||||||
|
" 'a\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrEndQuote
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void EmptyQuotes()\n"
|
||||||
|
"{\n"
|
||||||
|
" '';\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrCharEmpty
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void UnknownEscapeSequence()\n"
|
||||||
|
"{\n"
|
||||||
|
" '\\p';\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrBadEscape
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void MissingHexDigits()\n"
|
||||||
|
"{\n"
|
||||||
|
" '\\u';\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrHexDigits
|
||||||
|
);
|
||||||
|
|
||||||
|
ExecuteTest(
|
||||||
|
"extern void BadUnicodeCharacterName()\n"
|
||||||
|
"{\n"
|
||||||
|
" '\\U00110000';\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrUnicodeName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(CBotUT, TestNANParam_Issue642)
|
TEST_F(CBotUT, TestNANParam_Issue642)
|
||||||
{
|
{
|
||||||
ExecuteTest(
|
ExecuteTest(
|
||||||
|
|
|
@ -21,11 +21,21 @@
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
extern bool g_cbotTestSaveState;
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
CLogger logger;
|
CLogger logger;
|
||||||
|
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
// parse arguments not removed by InitGoogleTest
|
||||||
|
for (int i = 1; i < argc; ++i)
|
||||||
|
{
|
||||||
|
std::string arg(argv[i]);
|
||||||
|
if (arg == "--CBotUT_TestSaveState")
|
||||||
|
g_cbotTestSaveState = true;
|
||||||
|
}
|
||||||
|
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue