Merge pull request #1253 from melex750/dev-savegame

Add types byte, short, char, long, and double
blender-script
tomangelo 2020-01-02 15:01:16 +01:00 committed by GitHub
commit a67266553f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 2379 additions and 758 deletions

View File

@ -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 ""

View File

@ -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"

View File

@ -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)"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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 "Отсутствует конец блока"

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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;
} }

View File

@ -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

View File

@ -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());
} }
} }
if ( !IsOfType( p, ID_DOTS )) else
{ pStack->SetError(CBotErrBadNum, p->GetStart());
pStack->SetError( CBotErrNoDoubleDots, p->GetStart() ); delete i;
delete inst; }
return nullptr; else
pStack->SetError(CBotErrBadNum, p->GetStart());
} }
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;
} }

View File

@ -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

View File

@ -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);
} }

View File

@ -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.

View File

@ -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);
} }

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 else
{ {
inst->m_valint = GetNumInt(s); numtype = CBotTypFloat;
inst = new CBotExprLitNum<float>(static_cast<float>(val));
}
}
else
{
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();
} }

View File

@ -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;
}; };

View File

@ -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
{ {

View File

@ -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)
{ {

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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:
{
std::string valString;
if (!ReadString(istr, valString)) return false;
pNew = CBotVar::Create(token, w); // creates a variable pNew = CBotVar::Create(token, w); // creates a variable
if (!ReadString(pf, s)) return false; pNew->SetValString(valString);
pNew->SetValString(s);
break; 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
{ {
CBotTypResult ptrType(w, s); std::string className;
pNew = CBotVar::Create(token, ptrType);// creates a variable if (!ReadString(istr, className)) return false; // name of the class
{
// 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;

View File

@ -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);
//@} //@}

View File

@ -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);

View File

@ -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() + "[]";

View File

@ -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)

View File

@ -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.

View File

@ -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);

View File

@ -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);
//@} //@}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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());
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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;
} }
CBot::CBotClass::RestoreStaticState(file); }
CBot::fClose(file); else
GetLogger()->Error("cbot.run file is wrong version: %i\n", version);
}
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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);

View File

@ -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(

View File

@ -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();
} }