/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsiteс.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 */ //////////////////////////////////////////////////////////////////// // Definition for the class CBotVar // variables management of the language CBoT // it never creates an instance of the class mother CBotVar #include "CBot.h" #include #include #include long CBotVar::m_identcpt = 0; CBotVar::CBotVar( ) { m_next = NULL; m_pMyThis = NULL; m_pUserPtr = NULL; m_InitExpr = NULL; m_LimExpr = NULL; m_type = -1; m_binit = false; m_ident = 0; m_bStatic = false; m_mPrivate = 0; } CBotVarInt::CBotVarInt( const CBotToken* name ) { m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = NULL; m_InitExpr = NULL; m_LimExpr = NULL; m_type = CBotTypInt; m_binit = false; m_bStatic = false; m_mPrivate = 0; m_val = 0; } CBotVarFloat::CBotVarFloat( const CBotToken* name ) { m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = NULL; m_InitExpr = NULL; m_LimExpr = NULL; m_type = CBotTypFloat; m_binit = false; m_bStatic = false; m_mPrivate = 0; m_val = 0; } CBotVarString::CBotVarString( const CBotToken* name ) { m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = NULL; m_InitExpr = NULL; m_LimExpr = NULL; m_type = CBotTypString; m_binit = false; m_bStatic = false; m_mPrivate = 0; m_val.Empty(); } CBotVarBoolean::CBotVarBoolean( const CBotToken* name ) { m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = NULL; m_InitExpr = NULL; m_LimExpr = NULL; m_type = CBotTypBoolean; m_binit = false; m_bStatic = false; m_mPrivate = 0; m_val = 0; } CBotVarClass* CBotVarClass::m_ExClass = NULL; CBotVarClass::CBotVarClass( const CBotToken* name, const CBotTypResult& type) { /* // int nIdent = 0; InitCBotVarClass( name, type ) //, nIdent ); } CBotVarClass::CBotVarClass( const CBotToken* name, CBotTypResult& type) //, int &nIdent ) { InitCBotVarClass( name, type ); //, nIdent ); } void CBotVarClass::InitCBotVarClass( const CBotToken* name, CBotTypResult& type ) //, int &nIdent ) {*/ if ( !type.Eq(CBotTypClass) && !type.Eq(CBotTypIntrinsic) && // by convenience there accepts these types !type.Eq(CBotTypPointer) && !type.Eq(CBotTypArrayPointer) && !type.Eq(CBotTypArrayBody)) assert(0); m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = OBJECTCREATED;//NULL; m_InitExpr = NULL; m_LimExpr = NULL; m_pVar = NULL; m_type = type; if ( type.Eq(CBotTypArrayPointer) ) m_type.SetType( CBotTypArrayBody ); else if ( !type.Eq(CBotTypArrayBody) ) m_type.SetType( CBotTypClass ); // officel type for this object m_pClass = NULL; m_pParent = NULL; m_binit = false; m_bStatic = false; m_mPrivate = 0; m_bConstructor = false; m_CptUse = 0; m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum(); // se place tout seul dans la liste // TODO stands alone in the list (stands only in a list) if (m_ExClass) m_ExClass->m_ExPrev = this; m_ExNext = m_ExClass; m_ExPrev = NULL; m_ExClass = this; CBotClass* pClass = type.GetClass(); CBotClass* pClass2 = pClass->GetParent(); if ( pClass2 != NULL ) { // also creates an instance of the parent class m_pParent = new CBotVarClass(name, CBotTypResult(type.GetType(),pClass2) ); //, nIdent); } SetClass( pClass ); //, nIdent ); } CBotVarClass::~CBotVarClass( ) { if ( m_CptUse != 0 ) assert(0); if ( m_pParent ) delete m_pParent; m_pParent = NULL; // frees the indirect object if necessary // if ( m_Indirect != NULL ) // m_Indirect->DecrementUse(); // removes the class list if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext; else m_ExClass = m_ExNext; if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev; m_ExPrev = NULL; m_ExNext = NULL; delete m_pVar; } void CBotVarClass::ConstructorSet() { m_bConstructor = true; } CBotVar::~CBotVar( ) { delete m_token; delete m_next; } void CBotVar::debug() { // const char* p = static_cast( m_token->GetString()); CBotString s = static_cast( GetValString()); // const char* v = static_cast (s); if ( m_type.Eq(CBotTypClass) ) { CBotVar* pv = (static_cast(this))->m_pVar; while (pv != NULL) { pv->debug(); pv = pv->GetNext(); } } } void CBotVar::ConstructorSet() { // nop } void CBotVar::SetUserPtr(void* pUser) { m_pUserPtr = pUser; if (m_type.Eq(CBotTypPointer) && (static_cast(this))->m_pVarClass != NULL ) (static_cast(this))->m_pVarClass->SetUserPtr(pUser); } void CBotVar::SetIdent(long n) { if (m_type.Eq(CBotTypPointer) && (static_cast(this))->m_pVarClass != NULL ) (static_cast(this))->m_pVarClass->SetIdent(n); } void CBotVar::SetUniqNum(long n) { m_ident = n; if ( n == 0 ) assert(0); } long CBotVar::NextUniqNum() { if (++m_identcpt < 10000) m_identcpt = 10000; return m_identcpt; } long CBotVar::GetUniqNum() { return m_ident; } void* CBotVar::GetUserPtr() { return m_pUserPtr; } bool CBotVar::Save1State(FILE* pf) { // this routine "virtual" must never be called, // there must be a routine for each of the subclasses (CBotVarInt, CBotVarFloat, etc) // ( see the type in m_type ) assert(0); return false; } void CBotVar::Maj(void* pUser, bool bContinu) { /* if (!bContinu && m_pMyThis != NULL) m_pMyThis->Maj(pUser, true);*/ } // creates a variable depending on its type CBotVar* CBotVar::Create(const CBotToken* name, int type ) { CBotTypResult t(type); return Create(name, t); } CBotVar* CBotVar::Create(const CBotToken* name, CBotTypResult type) { switch (type.GetType()) { case CBotTypShort: case CBotTypInt: return new CBotVarInt(name); case CBotTypFloat: return new CBotVarFloat(name); case CBotTypBoolean: return new CBotVarBoolean(name); case CBotTypString: return new CBotVarString(name); case CBotTypPointer: case CBotTypNullPointer: return new CBotVarPointer(name, type); case CBotTypIntrinsic: return new CBotVarClass(name, type); case CBotTypClass: // creates a new instance of a class // and returns the POINTER on this instance { CBotVarClass* instance = new CBotVarClass(name, type); CBotVarPointer* pointer = new CBotVarPointer(name, type); pointer->SetPointer( instance ); return pointer; } case CBotTypArrayPointer: return new CBotVarArray(name, type); case CBotTypArrayBody: { CBotVarClass* instance = new CBotVarClass(name, type); CBotVarArray* array = new CBotVarArray(name, type); array->SetPointer( instance ); CBotVar* pv = array; while (type.Eq(CBotTypArrayBody)) { type = type.GetTypElem(); pv = (static_cast(pv))->GetItem(0, true); // creates at least the element [0] } return array; } } assert(0); return NULL; } CBotVar* CBotVar::Create( CBotVar* pVar ) { CBotVar* p = Create(pVar->m_token->GetString(), pVar->GetTypResult(2)); return p; } CBotVar* CBotVar::Create( const char* n, CBotTypResult type) { CBotToken name(n); switch (type.GetType()) { case CBotTypShort: case CBotTypInt: return new CBotVarInt(&name); case CBotTypFloat: return new CBotVarFloat(&name); case CBotTypBoolean: return new CBotVarBoolean(&name); case CBotTypString: return new CBotVarString(&name); case CBotTypPointer: case CBotTypNullPointer: { CBotVarPointer* p = new CBotVarPointer(&name, type); // p->SetClass(type.GetClass()); return p; } case CBotTypIntrinsic: { CBotVarClass* p = new CBotVarClass(&name, type); // p->SetClass(type.GetClass()); return p; } case CBotTypClass: // creates a new instance of a class // and returns the POINTER on this instance { CBotVarClass* instance = new CBotVarClass(&name, type); CBotVarPointer* pointer = new CBotVarPointer(&name, type); pointer->SetPointer( instance ); // pointer->SetClass( type.GetClass() ); return pointer; } case CBotTypArrayPointer: return new CBotVarArray(&name, type); case CBotTypArrayBody: { CBotVarClass* instance = new CBotVarClass(&name, type); CBotVarArray* array = new CBotVarArray(&name, type); array->SetPointer( instance ); CBotVar* pv = array; while (type.Eq(CBotTypArrayBody)) { type = type.GetTypElem(); pv = (static_cast(pv))->GetItem(0, true); // creates at least the element [0] } return array; } } assert(0); return NULL; } CBotVar* CBotVar::Create( const char* name, int type, CBotClass* pClass) { CBotToken token( name, "" ); CBotVar* pVar = Create( &token, type ); if ( type == CBotTypPointer && pClass == NULL ) // pointer "null" ? return pVar; if ( type == CBotTypClass || type == CBotTypPointer || type == CBotTypIntrinsic ) { if (pClass == NULL) { delete pVar; return NULL; } pVar->SetClass( pClass ); } return pVar; } CBotVar* CBotVar::Create( const char* name, CBotClass* pClass) { CBotToken token( name, "" ); CBotVar* pVar = Create( &token, CBotTypResult( CBotTypClass, pClass ) ); // pVar->SetClass( pClass ); return pVar; } CBotTypResult CBotVar::GetTypResult(int mode) { CBotTypResult r = m_type; if ( mode == 1 && m_type.Eq(CBotTypClass) ) r.SetType(CBotTypPointer); if ( mode == 2 && m_type.Eq(CBotTypClass) ) r.SetType(CBotTypIntrinsic); return r; } int CBotVar::GetType(int mode) { if ( mode == 1 && m_type.Eq(CBotTypClass) ) return CBotTypPointer; if ( mode == 2 && m_type.Eq(CBotTypClass) ) return CBotTypIntrinsic; return m_type.GetType(); } void CBotVar::SetType(CBotTypResult& type) { m_type = type; } int CBotVar::GetInit() { if ( m_type.Eq(CBotTypClass) ) return IS_DEF; // always set! return m_binit; } void CBotVar::SetInit(int bInit) { m_binit = bInit; if ( bInit == 2 ) m_binit = IS_DEF; // cas spécial if ( m_type.Eq(CBotTypPointer) && bInit == 2 ) { CBotVarClass* instance = GetPointer(); if ( instance == NULL ) { instance = new CBotVarClass(NULL, m_type); // instance->SetClass((static_cast(this))->m_pClass); SetPointer(instance); } instance->SetInit(1); } if ( m_type.Eq(CBotTypClass) || m_type.Eq(CBotTypIntrinsic) ) { CBotVar* p = (static_cast(this))->m_pVar; while( p != NULL ) { p->SetInit( bInit ); p->m_pMyThis = static_cast(this); p = p->GetNext(); } } } CBotString CBotVar::GetName() { return m_token->GetString(); } void CBotVar::SetName(const char* name) { m_token->SetString(name); } CBotToken* CBotVar::GetToken() { return m_token; } CBotVar* CBotVar::GetItem(const char* name) { assert(0); return NULL; } CBotVar* CBotVar::GetItemRef(int nIdent) { assert(0); return NULL; } CBotVar* CBotVar::GetItemList() { assert(0); return NULL; } CBotVar* CBotVar::GetItem(int row, bool bGrow) { assert(0); return NULL; } // check if a variable belongs to a given class bool CBotVar::IsElemOfClass(const char* name) { CBotClass* pc = NULL; if ( m_type.Eq(CBotTypPointer) ) { pc = (static_cast(this))->m_pClass; } if ( m_type.Eq(CBotTypClass) ) { pc = (static_cast(this))->m_pClass; } while ( pc != NULL ) { if ( pc->GetName() == name ) return true; pc = pc->GetParent(); } return false; } CBotVar* CBotVar::GetStaticVar() { // makes the pointer to the variable if it is static if ( m_bStatic == 0 || m_pMyThis == NULL ) return this; CBotClass* pClass = m_pMyThis->GetClass(); return pClass->GetItem( m_token->GetString() ); } CBotVar* CBotVar::GetNext() { return m_next; } void CBotVar::AddNext(CBotVar* pVar) { CBotVar* p = this; while (p->m_next != NULL) p = p->m_next; p->m_next = pVar; } void CBotVar::SetVal(CBotVar* var) { switch (var->GetType()) { case CBotTypBoolean: SetValInt(var->GetValInt()); break; case CBotTypInt: SetValInt(var->GetValInt(), (static_cast(var))->m_defnum); break; case CBotTypFloat: SetValFloat(var->GetValFloat()); break; case CBotTypString: SetValString(var->GetValString()); break; case CBotTypPointer: case CBotTypNullPointer: case CBotTypArrayPointer: SetPointer(var->GetPointer()); break; case CBotTypClass: { delete (static_cast(this))->m_pVar; (static_cast(this))->m_pVar = NULL; Copy(var, false); } break; default: assert(0); } m_binit = var->m_binit; // copie l'état nan s'il y a } void CBotVar::SetStatic(bool bStatic) { m_bStatic = bStatic; } void CBotVar::SetPrivate(int mPrivate) { m_mPrivate = mPrivate; } bool CBotVar::IsStatic() { return m_bStatic; } bool CBotVar::IsPrivate(int mode) { return m_mPrivate >= mode; } int CBotVar::GetPrivate() { return m_mPrivate; } void CBotVar::SetPointer(CBotVar* pVarClass) { assert(0); } CBotVarClass* CBotVar::GetPointer() { assert(0); return NULL; } // All these functions must be defined in the subclasses // derived from class CBotVar int CBotVar::GetValInt() { assert(0); return 0; } float CBotVar::GetValFloat() { assert(0); return 0; } void CBotVar::SetValInt(int c, const char* s) { assert(0); } void CBotVar::SetValFloat(float c) { assert(0); } void CBotVar::Mul(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::Power(CBotVar* left, CBotVar* right) { assert(0); } int CBotVar::Div(CBotVar* left, CBotVar* right) { assert(0); return 0; } int CBotVar::Modulo(CBotVar* left, CBotVar* right) { assert(0); return 0; } void CBotVar::Add(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::Sub(CBotVar* left, CBotVar* right) { assert(0); } bool CBotVar::Lo(CBotVar* left, CBotVar* right) { assert(0); return false; } bool CBotVar::Hi(CBotVar* left, CBotVar* right) { assert(0); return false; } bool CBotVar::Ls(CBotVar* left, CBotVar* right) { assert(0); return false; } bool CBotVar::Hs(CBotVar* left, CBotVar* right) { assert(0); return false; } bool CBotVar::Eq(CBotVar* left, CBotVar* right) { assert(0); return false; } bool CBotVar::Ne(CBotVar* left, CBotVar* right) { assert(0); return false; } void CBotVar::And(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::Or(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::XOr(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::ASR(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::SR(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::SL(CBotVar* left, CBotVar* right) { assert(0); } void CBotVar::Neg() { assert(0); } void CBotVar::Not() { assert(0); } void CBotVar::Inc() { assert(0); } void CBotVar::Dec() { assert(0); } void CBotVar::Copy(CBotVar* pSrc, bool bName) { assert(0); } void CBotVar::SetValString(const char* p) { assert(0); } CBotString CBotVar::GetValString() { assert(0); return CBotString(); } void CBotVar::SetClass(CBotClass* pClass) { assert(0); } CBotClass* CBotVar::GetClass() { assert(0); return NULL; } /* void CBotVar::SetIndirection(CBotVar* pVar) { // nop, only CBotVarPointer::SetIndirection } */ ////////////////////////////////////////////////////////////////////////////////////// // copy a variable in to another void CBotVarInt::Copy(CBotVar* pSrc, bool bName) { CBotVarInt* p = static_cast(pSrc); if ( bName) *m_token = *p->m_token; m_type = p->m_type; m_val = p->m_val; m_binit = p->m_binit; m_pMyThis = NULL; m_pUserPtr = p->m_pUserPtr; // identificator is the same (by défaut) if (m_ident == 0 ) m_ident = p->m_ident; m_defnum = p->m_defnum; } void CBotVarInt::SetValInt(int val, const char* defnum) { m_val = val; m_binit = true; m_defnum = defnum; } void CBotVarInt::SetValFloat(float val) { m_val = static_cast(val); m_binit = true; } int CBotVarInt::GetValInt() { return m_val; } float CBotVarInt::GetValFloat() { return static_cast(m_val); } CBotString CBotVarInt::GetValString() { if ( !m_defnum.IsEmpty() ) return m_defnum; CBotString res; if ( !m_binit ) { res.LoadString(TX_UNDEF); return res; } if ( m_binit == IS_NAN ) { res.LoadString(TX_NAN); return res; } char buffer[300]; sprintf(buffer, "%d", m_val); res = buffer; return res; } void CBotVarInt::Mul(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() * right->GetValInt(); m_binit = true; } void CBotVarInt::Power(CBotVar* left, CBotVar* right) { m_val = static_cast( pow( static_cast( left->GetValInt()) , static_cast( left->GetValInt()) )); m_binit = true; } int CBotVarInt::Div(CBotVar* left, CBotVar* right) { int r = right->GetValInt(); if ( r != 0 ) { m_val = left->GetValInt() / r; m_binit = true; } return ( r == 0 ? TX_DIVZERO : 0 ); } int CBotVarInt::Modulo(CBotVar* left, CBotVar* right) { int r = right->GetValInt(); if ( r != 0 ) { m_val = left->GetValInt() % r; m_binit = true; } return ( r == 0 ? TX_DIVZERO : 0 ); } void CBotVarInt::Add(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() + right->GetValInt(); m_binit = true; } void CBotVarInt::Sub(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() - right->GetValInt(); m_binit = true; } void CBotVarInt::XOr(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() ^ right->GetValInt(); m_binit = true; } void CBotVarInt::And(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() & right->GetValInt(); m_binit = true; } void CBotVarInt::Or(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() | right->GetValInt(); m_binit = true; } void CBotVarInt::SL(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() << right->GetValInt(); m_binit = true; } void CBotVarInt::ASR(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() >> right->GetValInt(); m_binit = true; } void CBotVarInt::SR(CBotVar* left, CBotVar* right) { int source = left->GetValInt(); int shift = right->GetValInt(); if (shift>=1) source &= 0x7fffffff; m_val = source >> shift; m_binit = true; } void CBotVarInt::Neg() { m_val = -m_val; } void CBotVarInt::Not() { m_val = ~m_val; } void CBotVarInt::Inc() { m_val++; m_defnum.Empty(); } void CBotVarInt::Dec() { m_val--; m_defnum.Empty(); } bool CBotVarInt::Lo(CBotVar* left, CBotVar* right) { return left->GetValInt() < right->GetValInt(); } bool CBotVarInt::Hi(CBotVar* left, CBotVar* right) { return left->GetValInt() > right->GetValInt(); } bool CBotVarInt::Ls(CBotVar* left, CBotVar* right) { return left->GetValInt() <= right->GetValInt(); } bool CBotVarInt::Hs(CBotVar* left, CBotVar* right) { return left->GetValInt() >= right->GetValInt(); } bool CBotVarInt::Eq(CBotVar* left, CBotVar* right) { return left->GetValInt() == right->GetValInt(); } bool CBotVarInt::Ne(CBotVar* left, CBotVar* right) { return left->GetValInt() != right->GetValInt(); } ////////////////////////////////////////////////////////////////////////////////////// // copy a variable into another void CBotVarFloat::Copy(CBotVar* pSrc, bool bName) { CBotVarFloat* p = static_cast(pSrc); if (bName) *m_token = *p->m_token; m_type = p->m_type; m_val = p->m_val; m_binit = p->m_binit; //- m_bStatic = p->m_bStatic; m_next = NULL; m_pMyThis = NULL;//p->m_pMyThis; m_pUserPtr = p->m_pUserPtr; // keeps indentificator the same (by default) if (m_ident == 0 ) m_ident = p->m_ident; } void CBotVarFloat::SetValInt(int val, const char* s) { m_val = static_cast(val); m_binit = true; } void CBotVarFloat::SetValFloat(float val) { m_val = val; m_binit = true; } int CBotVarFloat::GetValInt() { return static_cast(m_val); } float CBotVarFloat::GetValFloat() { return m_val; } CBotString CBotVarFloat::GetValString() { CBotString res; if ( !m_binit ) { res.LoadString(TX_UNDEF); return res; } if ( m_binit == IS_NAN ) { res.LoadString(TX_NAN); return res; } char buffer[300]; sprintf(buffer, "%.2f", m_val); res = buffer; return res; } void CBotVarFloat::Mul(CBotVar* left, CBotVar* right) { m_val = left->GetValFloat() * right->GetValFloat(); m_binit = true; } void CBotVarFloat::Power(CBotVar* left, CBotVar* right) { m_val = static_cast(pow( left->GetValFloat() , right->GetValFloat() )); m_binit = true; } int CBotVarFloat::Div(CBotVar* left, CBotVar* right) { float r = right->GetValFloat(); if ( r != 0 ) { m_val = left->GetValFloat() / r; m_binit = true; } return ( r == 0 ? TX_DIVZERO : 0 ); } int CBotVarFloat::Modulo(CBotVar* left, CBotVar* right) { float r = right->GetValFloat(); if ( r != 0 ) { m_val = static_cast(fmod( left->GetValFloat() , r )); m_binit = true; } return ( r == 0 ? TX_DIVZERO : 0 ); } void CBotVarFloat::Add(CBotVar* left, CBotVar* right) { m_val = left->GetValFloat() + right->GetValFloat(); m_binit = true; } void CBotVarFloat::Sub(CBotVar* left, CBotVar* right) { m_val = left->GetValFloat() - right->GetValFloat(); m_binit = true; } void CBotVarFloat::Neg() { m_val = -m_val; } void CBotVarFloat::Inc() { m_val++; } void CBotVarFloat::Dec() { m_val--; } bool CBotVarFloat::Lo(CBotVar* left, CBotVar* right) { return left->GetValFloat() < right->GetValFloat(); } bool CBotVarFloat::Hi(CBotVar* left, CBotVar* right) { return left->GetValFloat() > right->GetValFloat(); } bool CBotVarFloat::Ls(CBotVar* left, CBotVar* right) { return left->GetValFloat() <= right->GetValFloat(); } bool CBotVarFloat::Hs(CBotVar* left, CBotVar* right) { return left->GetValFloat() >= right->GetValFloat(); } bool CBotVarFloat::Eq(CBotVar* left, CBotVar* right) { return left->GetValFloat() == right->GetValFloat(); } bool CBotVarFloat::Ne(CBotVar* left, CBotVar* right) { return left->GetValFloat() != right->GetValFloat(); } ////////////////////////////////////////////////////////////////////////////////////// // copy a variable into another void CBotVarBoolean::Copy(CBotVar* pSrc, bool bName) { CBotVarBoolean* p = static_cast(pSrc); if (bName) *m_token = *p->m_token; m_type = p->m_type; m_val = p->m_val; m_binit = p->m_binit; //- m_bStatic = p->m_bStatic; m_next = NULL; m_pMyThis = NULL;//p->m_pMyThis; m_pUserPtr = p->m_pUserPtr; // keeps indentificator the same (by default) if (m_ident == 0 ) m_ident = p->m_ident; } void CBotVarBoolean::SetValInt(int val, const char* s) { m_val = static_cast(val); m_binit = true; } void CBotVarBoolean::SetValFloat(float val) { m_val = static_cast(val); m_binit = true; } int CBotVarBoolean::GetValInt() { return m_val; } float CBotVarBoolean::GetValFloat() { return static_cast(m_val); } CBotString CBotVarBoolean::GetValString() { CBotString ret; CBotString res; if ( !m_binit ) { res.LoadString(TX_UNDEF); return res; } if ( m_binit == IS_NAN ) { res.LoadString(TX_NAN); return res; } ret.LoadString( m_val > 0 ? ID_TRUE : ID_FALSE ); return ret; } void CBotVarBoolean::And(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() && right->GetValInt(); m_binit = true; } void CBotVarBoolean::Or(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() || right->GetValInt(); m_binit = true; } void CBotVarBoolean::XOr(CBotVar* left, CBotVar* right) { m_val = left->GetValInt() ^ right->GetValInt(); m_binit = true; } void CBotVarBoolean::Not() { m_val = m_val ? false : true ; } bool CBotVarBoolean::Eq(CBotVar* left, CBotVar* right) { return left->GetValInt() == right->GetValInt(); } bool CBotVarBoolean::Ne(CBotVar* left, CBotVar* right) { return left->GetValInt() != right->GetValInt(); } ////////////////////////////////////////////////////////////////////////////////////// // copy a variable into another void CBotVarString::Copy(CBotVar* pSrc, bool bName) { CBotVarString* p = static_cast(pSrc); if (bName) *m_token = *p->m_token; m_type = p->m_type; m_val = p->m_val; m_binit = p->m_binit; //- m_bStatic = p->m_bStatic; m_next = NULL; m_pMyThis = NULL;//p->m_pMyThis; m_pUserPtr = p->m_pUserPtr; // keeps indentificator the same (by default) if (m_ident == 0 ) m_ident = p->m_ident; } void CBotVarString::SetValString(const char* p) { m_val = p; m_binit = true; } CBotString CBotVarString::GetValString() { if ( !m_binit ) { CBotString res; res.LoadString(TX_UNDEF); return res; } if ( m_binit == IS_NAN ) { CBotString res; res.LoadString(TX_NAN); return res; } return m_val; } void CBotVarString::Add(CBotVar* left, CBotVar* right) { m_val = left->GetValString() + right->GetValString(); m_binit = true; } bool CBotVarString::Eq(CBotVar* left, CBotVar* right) { return (left->GetValString() == right->GetValString()); } bool CBotVarString::Ne(CBotVar* left, CBotVar* right) { return (left->GetValString() != right->GetValString()); } bool CBotVarString::Lo(CBotVar* left, CBotVar* right) { return (left->GetValString() == right->GetValString()); } bool CBotVarString::Hi(CBotVar* left, CBotVar* right) { return (left->GetValString() == right->GetValString()); } bool CBotVarString::Ls(CBotVar* left, CBotVar* right) { return (left->GetValString() == right->GetValString()); } bool CBotVarString::Hs(CBotVar* left, CBotVar* right) { return (left->GetValString() == right->GetValString()); } //////////////////////////////////////////////////////////////// // copy a variable into another void CBotVarClass::Copy(CBotVar* pSrc, bool bName) { pSrc = pSrc->GetPointer(); // if source given by a pointer if ( pSrc->GetType() != CBotTypClass ) assert(0); CBotVarClass* p = static_cast(pSrc); if (bName) *m_token = *p->m_token; m_type = p->m_type; m_binit = p->m_binit; //- m_bStatic = p->m_bStatic; m_pClass = p->m_pClass; if ( p->m_pParent ) { assert(0); // "que faire du pParent"; } // m_next = NULL; m_pUserPtr = p->m_pUserPtr; m_pMyThis = NULL;//p->m_pMyThis; m_ItemIdent = p->m_ItemIdent; // keeps indentificator the same (by default) if (m_ident == 0 ) m_ident = p->m_ident; delete m_pVar; m_pVar = NULL; CBotVar* pv = p->m_pVar; while( pv != NULL ) { CBotVar* pn = CBotVar::Create(pv); pn->Copy( pv ); if ( m_pVar == NULL ) m_pVar = pn; else m_pVar->AddNext(pn); pv = pv->GetNext(); } } void CBotVarClass::SetItemList(CBotVar* pVar) { delete m_pVar; m_pVar = pVar; // replaces the existing pointer } void CBotVarClass::SetIdent(long n) { m_ItemIdent = n; } void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent) { m_type.m_pClass = pClass; if ( m_pClass == pClass ) return; m_pClass = pClass; // initializes the variables associated with this class delete m_pVar; m_pVar = NULL; if (pClass == NULL) return; CBotVar* pv = pClass->GetVar(); // first on a list while ( pv != NULL ) { // seeks the maximum dimensions of the table CBotInstr* p = pv->m_LimExpr; // the different formulas if ( p != NULL ) { CBotStack* pile = CBotStack::FirstStack(); // an independent stack int n = 0; int max[100]; while (p != NULL) { while( pile->IsOk() && !p->Execute(pile) ) ; // calculate size without interruptions CBotVar* v = pile->GetVar(); // result max[n] = v->GetValInt(); // value n++; p = p->GetNext3(); } while (n<100) max[n++] = 0; pv->m_type.SetArray( max ); // stores the limitations pile->Delete(); } CBotVar* pn = CBotVar::Create( pv ); // a copy pn->SetStatic(pv->IsStatic()); pn->SetPrivate(pv->GetPrivate()); if ( pv->m_InitExpr != NULL ) // expression for initialization? { #if STACKMEM CBotStack* pile = CBotStack::FirstStack(); // an independent stack while(pile->IsOk() && !pv->m_InitExpr->Execute(pile, pn)); // evaluates the expression without timer pile->Delete(); #else CBotStack* pile = new CBotStack(NULL); // an independent stack while(!pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer pn->SetVal( pile->GetVar() ) ; delete pile; #endif } // pn->SetUniqNum(CBotVar::NextUniqNum()); // enumerate elements pn->SetUniqNum(pv->GetUniqNum()); //++nIdent pn->m_pMyThis = this; if ( m_pVar == NULL) m_pVar = pn; else m_pVar->AddNext( pn ); pv = pv->GetNext(); } } CBotClass* CBotVarClass::GetClass() { return m_pClass; } void CBotVarClass::Maj(void* pUser, bool bContinu) { /* if (!bContinu && m_pMyThis != NULL) m_pMyThis->Maj(pUser, true);*/ // an update routine exist? if ( m_pClass->m_rMaj == NULL ) return; // retrieves the user pointer according to the class // or according to the parameter passed to CBotProgram::Run() if ( m_pUserPtr != NULL) pUser = m_pUserPtr; if ( pUser == OBJECTDELETED || pUser == OBJECTCREATED ) return; m_pClass->m_rMaj( this, pUser ); } CBotVar* CBotVarClass::GetItem(const char* name) { CBotVar* p = m_pVar; while ( p != NULL ) { if ( p->GetName() == name ) return p; p = p->GetNext(); } if ( m_pParent != NULL ) return m_pParent->GetItem(name); return NULL; } CBotVar* CBotVarClass::GetItemRef(int nIdent) { CBotVar* p = m_pVar; while ( p != NULL ) { if ( p->GetUniqNum() == nIdent ) return p; p = p->GetNext(); } if ( m_pParent != NULL ) return m_pParent->GetItemRef(nIdent); return NULL; } // for the management of an array // bExtend can enlarge the table, but not beyond the threshold size of SetArray () CBotVar* CBotVarClass::GetItem(int n, bool bExtend) { CBotVar* p = m_pVar; if ( n < 0 ) return NULL; if ( n > MAXARRAYSIZE ) return NULL; if ( m_type.GetLimite() >= 0 && n >= m_type.GetLimite() ) return NULL; if ( p == NULL && bExtend ) { p = CBotVar::Create("", m_type.GetTypElem()); m_pVar = p; } if ( n == 0 ) return p; while ( n-- > 0 ) { if ( p->m_next == NULL ) { if ( bExtend ) p->m_next = CBotVar::Create("", m_type.GetTypElem()); if ( p->m_next == NULL ) return NULL; } p = p->m_next; } return p; } CBotVar* CBotVarClass::GetItemList() { return m_pVar; } CBotString CBotVarClass::GetValString() { // if ( m_Indirect != NULL) return m_Indirect->GetValString(); CBotString res; if ( m_pClass != NULL ) // not used for an array { res = m_pClass->GetName() + CBotString("( "); CBotVarClass* my = this; while ( my != NULL ) { CBotVar* pv = my->m_pVar; while ( pv != NULL ) { res += pv->GetName() + CBotString("="); if ( pv->IsStatic() ) { CBotVar* pvv = my->m_pClass->GetItem(pv->GetName()); res += pvv->GetValString(); } else { res += pv->GetValString(); } pv = pv->GetNext(); if ( pv != NULL ) res += ", "; } my = my->m_pParent; if ( my != NULL ) { res += ") extends "; res += my->m_pClass->GetName(); res += " ("; } } } else { res = "( "; CBotVar* pv = m_pVar; while ( pv != NULL ) { res += pv->GetValString(); if ( pv->GetNext() != NULL ) res += ", "; pv = pv->GetNext(); } } res += " )"; return res; } void CBotVarClass::IncrementUse() { m_CptUse++; } void CBotVarClass::DecrementUse() { m_CptUse--; if ( m_CptUse == 0 ) { // if there is one, call the destructor // but only if a constructor had been called. if ( m_bConstructor ) { m_CptUse++; // does not return to the destructor // m_error is static in the stack // saves the value for return int err, start, end; CBotStack* pile = NULL; err = pile->GetError(start,end); // stack == NULL it does not bother! pile = CBotStack::FirstStack(); // clears the error CBotVar* ppVars[1]; ppVars[0] = NULL; CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer); pThis->SetPointer(this); CBotVar* pResult = NULL; CBotString nom = "~" + m_pClass->GetName(); long ident = 0; while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, NULL)) ; // waits for the end pile->ResetError(err, start,end); pile->Delete(); delete pThis; m_CptUse--; } delete this; // self-destructs! } } CBotVarClass* CBotVarClass::GetPointer() { return this; } // makes an instance according to its unique number CBotVarClass* CBotVarClass::Find(long id) { CBotVarClass* p = m_ExClass; while ( p != NULL ) { if ( p->m_ItemIdent == id ) return p; p = p->m_ExNext; } return NULL; } bool CBotVarClass::Eq(CBotVar* left, CBotVar* right) { CBotVar* l = left->GetItemList(); CBotVar* r = right->GetItemList(); while ( l != NULL && r != NULL ) { if ( l->Ne(l, r) ) return false; l = l->GetNext(); r = r->GetNext(); } // should always arrived simultaneously at the end (same classes) return l == r; } bool CBotVarClass::Ne(CBotVar* left, CBotVar* right) { CBotVar* l = left->GetItemList(); CBotVar* r = right->GetItemList(); while ( l != NULL && r != NULL ) { if ( l->Ne(l, r) ) return true; l = l->GetNext(); r = r->GetNext(); } // should always arrived simultaneously at the end (same classes) return l != r; } ///////////////////////////////////////////////////////////////////////////// // management of arrays CBotVarArray::CBotVarArray(const CBotToken* name, CBotTypResult& type ) { if ( !type.Eq(CBotTypArrayPointer) && !type.Eq(CBotTypArrayBody)) assert(0); m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = NULL; m_type = type; m_type.SetType(CBotTypArrayPointer); m_binit = false; m_pInstance = NULL; // the list of the array elements } CBotVarArray::~CBotVarArray() { if ( m_pInstance != NULL ) m_pInstance->DecrementUse(); // the lowest reference } // copy a variable into another void CBotVarArray::Copy(CBotVar* pSrc, bool bName) { if ( pSrc->GetType() != CBotTypArrayPointer ) assert(0); CBotVarArray* p = static_cast(pSrc); if ( bName) *m_token = *p->m_token; m_type = p->m_type; m_pInstance = p->GetPointer(); if ( m_pInstance != NULL ) m_pInstance->IncrementUse(); // a reference increase m_binit = p->m_binit; //- m_bStatic = p->m_bStatic; m_pMyThis = NULL;//p->m_pMyThis; m_pUserPtr = p->m_pUserPtr; // keeps indentificator the same (by default) if (m_ident == 0 ) m_ident = p->m_ident; } void CBotVarArray::SetPointer(CBotVar* pVarClass) { m_binit = true; // init, even on a null pointer if ( m_pInstance == pVarClass) return; // Special, not decrement and reincrement // because the decrement can destroy the object if ( pVarClass != NULL ) { if ( pVarClass->GetType() == CBotTypArrayPointer ) pVarClass = pVarClass->GetPointer(); // the real pointer to the object if ( !pVarClass->m_type.Eq(CBotTypClass) && !pVarClass->m_type.Eq(CBotTypArrayBody)) assert(0); (static_cast(pVarClass))->IncrementUse(); // incement the reference } if ( m_pInstance != NULL ) m_pInstance->DecrementUse(); m_pInstance = static_cast(pVarClass); } CBotVarClass* CBotVarArray::GetPointer() { if ( m_pInstance == NULL ) return NULL; return m_pInstance->GetPointer(); } CBotVar* CBotVarArray::GetItem(int n, bool bExtend) { if ( m_pInstance == NULL ) { if ( !bExtend ) return NULL; // creates an instance of the table CBotVarClass* instance = new CBotVarClass(NULL, m_type); SetPointer( instance ); } return m_pInstance->GetItem(n, bExtend); } CBotVar* CBotVarArray::GetItemList() { if ( m_pInstance == NULL) return NULL; return m_pInstance->GetItemList(); } CBotString CBotVarArray::GetValString() { if ( m_pInstance == NULL ) return ( CBotString( "Null pointer" ) ) ; return m_pInstance->GetValString(); } bool CBotVarArray::Save1State(FILE* pf) { if ( !WriteType(pf, m_type) ) return false; return SaveVar(pf, m_pInstance); // saves the instance that manages the table } ///////////////////////////////////////////////////////////////////////////// // gestion des pointeurs à une instance donnée // TODO management of pointers to a given instance CBotVarPointer::CBotVarPointer(const CBotToken* name, CBotTypResult& type ) { if ( !type.Eq(CBotTypPointer) && !type.Eq(CBotTypNullPointer) && !type.Eq(CBotTypClass) && // for convenience accepts Class and Intrinsic !type.Eq(CBotTypIntrinsic) ) assert(0); m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = NULL; m_type = type; if ( !type.Eq(CBotTypNullPointer) ) m_type.SetType(CBotTypPointer); // anyway, this is a pointer m_binit = false; m_pClass = NULL; m_pVarClass = NULL; // will be defined by a SetPointer() SetClass(type.GetClass() ); } CBotVarPointer::~CBotVarPointer() { if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse(); // decrement reference } void CBotVarPointer::Maj(void* pUser, bool bContinu) { /* if ( !bContinu && m_pMyThis != NULL ) m_pMyThis->Maj(pUser, false);*/ if ( m_pVarClass != NULL) m_pVarClass->Maj(pUser, false); } CBotVar* CBotVarPointer::GetItem(const char* name) { if ( m_pVarClass == NULL) // no existing instance? return m_pClass->GetItem(name); // makes the pointer in the class itself return m_pVarClass->GetItem(name); } CBotVar* CBotVarPointer::GetItemRef(int nIdent) { if ( m_pVarClass == NULL) // no existing instance? return m_pClass->GetItemRef(nIdent);// makes the pointer to the class itself return m_pVarClass->GetItemRef(nIdent); } CBotVar* CBotVarPointer::GetItemList() { if ( m_pVarClass == NULL) return NULL; return m_pVarClass->GetItemList(); } CBotString CBotVarPointer::GetValString() { CBotString s = "Pointer to "; if ( m_pVarClass == NULL ) s = "Null pointer" ; else s += m_pVarClass->GetValString(); return s; } void CBotVarPointer::ConstructorSet() { if ( m_pVarClass != NULL) m_pVarClass->ConstructorSet(); } // initializes the pointer to the instance of a class void CBotVarPointer::SetPointer(CBotVar* pVarClass) { m_binit = true; // init, even on a null pointer if ( m_pVarClass == pVarClass) return; // special, not decrement and reincrement // because the decrement can destroy the object if ( pVarClass != NULL ) { if ( pVarClass->GetType() == CBotTypPointer ) pVarClass = pVarClass->GetPointer(); // the real pointer to the object // if ( pVarClass->GetType() != CBotTypClass ) if ( !pVarClass->m_type.Eq(CBotTypClass) ) assert(0); (static_cast(pVarClass))->IncrementUse(); // increment the reference m_pClass = (static_cast(pVarClass))->m_pClass; m_pUserPtr = pVarClass->m_pUserPtr; // not really necessary m_type = CBotTypResult(CBotTypPointer, m_pClass); // what kind of a pointer } if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse(); m_pVarClass = static_cast(pVarClass); } CBotVarClass* CBotVarPointer::GetPointer() { if ( m_pVarClass == NULL ) return NULL; return m_pVarClass->GetPointer(); } void CBotVarPointer::SetIdent(long n) { if ( m_pVarClass == NULL ) return; m_pVarClass->SetIdent( n ); } long CBotVarPointer::GetIdent() { if ( m_pVarClass == NULL ) return 0; return m_pVarClass->m_ItemIdent; } void CBotVarPointer::SetClass(CBotClass* pClass) { // int nIdent = 0; m_type.m_pClass = m_pClass = pClass; if ( m_pVarClass != NULL ) m_pVarClass->SetClass(pClass); //, nIdent); } CBotClass* CBotVarPointer::GetClass() { if ( m_pVarClass != NULL ) return m_pVarClass->GetClass(); return m_pClass; } bool CBotVarPointer::Save1State(FILE* pf) { if ( m_pClass ) { if (!WriteString(pf, m_pClass->GetName())) return false; // name of the class } else { if (!WriteString(pf, "")) return false; } if (!WriteLong(pf, GetIdent())) return false; // the unique reference // also saves the proceedings copies return SaveVar(pf, GetPointer()); } // copy a variable into another void CBotVarPointer::Copy(CBotVar* pSrc, bool bName) { if ( pSrc->GetType() != CBotTypPointer && pSrc->GetType() != CBotTypNullPointer) assert(0); CBotVarPointer* p = static_cast(pSrc); if ( bName) *m_token = *p->m_token; m_type = p->m_type; // m_pVarClass = p->m_pVarClass; m_pVarClass = p->GetPointer(); if ( m_pVarClass != NULL ) m_pVarClass->IncrementUse(); // incerement the reference m_pClass = p->m_pClass; m_binit = p->m_binit; //- m_bStatic = p->m_bStatic; m_next = NULL; m_pMyThis = NULL;//p->m_pMyThis; m_pUserPtr = p->m_pUserPtr; // keeps indentificator the same (by default) if (m_ident == 0 ) m_ident = p->m_ident; } bool CBotVarPointer::Eq(CBotVar* left, CBotVar* right) { CBotVarClass* l = left->GetPointer(); CBotVarClass* r = right->GetPointer(); if ( l == r ) return true; if ( l == NULL && r->GetUserPtr() == OBJECTDELETED ) return true; if ( r == NULL && l->GetUserPtr() == OBJECTDELETED ) return true; return false; } bool CBotVarPointer::Ne(CBotVar* left, CBotVar* right) { CBotVarClass* l = left->GetPointer(); CBotVarClass* r = right->GetPointer(); if ( l == r ) return false; if ( l == NULL && r->GetUserPtr() == OBJECTDELETED ) return false; if ( r == NULL && l->GetUserPtr() == OBJECTDELETED ) return false; return true; } /////////////////////////////////////////////////////// // management of results types CBotTypResult::CBotTypResult(int type) { m_type = type; m_pNext = NULL; m_pClass = NULL; m_limite = -1; } CBotTypResult::CBotTypResult(int type, const char* name) { m_type = type; m_pNext = NULL; m_pClass = NULL; m_limite = -1; if ( type == CBotTypPointer || type == CBotTypClass || type == CBotTypIntrinsic ) { m_pClass = CBotClass::Find(name); if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic; } } CBotTypResult::CBotTypResult(int type, CBotClass* pClass) { m_type = type; m_pNext = NULL; m_pClass = pClass; m_limite = -1; if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic; } CBotTypResult::CBotTypResult(int type, CBotTypResult elem) { m_type = type; m_pNext = NULL; m_pClass = NULL; m_limite = -1; if ( type == CBotTypArrayPointer || type == CBotTypArrayBody ) m_pNext = new CBotTypResult( elem ); } CBotTypResult::CBotTypResult(const CBotTypResult& typ) { m_type = typ.m_type; m_pClass = typ.m_pClass; m_pNext = NULL; m_limite = typ.m_limite; if ( typ.m_pNext ) m_pNext = new CBotTypResult( *typ.m_pNext ); } CBotTypResult::CBotTypResult() { m_type = 0; m_limite = -1; m_pNext = NULL; m_pClass = NULL; } CBotTypResult::~CBotTypResult() { delete m_pNext; } int CBotTypResult::GetType(int mode) const { #ifdef _DEBUG if ( m_type == CBotTypPointer || m_type == CBotTypClass || m_type == CBotTypIntrinsic ) if ( m_pClass == NULL ) assert(0); if ( m_type == CBotTypArrayPointer ) if ( m_pNext == NULL ) assert(0); #endif if ( mode == 3 && m_type == CBotTypNullPointer ) return CBotTypPointer; return m_type; } void CBotTypResult::SetType(int n) { m_type = n; } CBotClass* CBotTypResult::GetClass() const { return m_pClass; } CBotTypResult& CBotTypResult::GetTypElem() const { return *m_pNext; } int CBotTypResult::GetLimite() const { return m_limite; } void CBotTypResult::SetLimite(int n) { m_limite = n; } void CBotTypResult::SetArray( int* max ) { m_limite = *max; if (m_limite < 1) m_limite = -1; if ( m_pNext != NULL ) // last dimension? { m_pNext->SetArray( max+1 ); } } bool CBotTypResult::Compare(const CBotTypResult& typ) const { if ( m_type != typ.m_type ) return false; if ( m_type == CBotTypArrayPointer ) return m_pNext->Compare(*typ.m_pNext); if ( m_type == CBotTypPointer || m_type == CBotTypClass || m_type == CBotTypIntrinsic ) { return m_pClass == typ.m_pClass; } return true; } bool CBotTypResult::Eq(int type) const { return m_type == type; } CBotTypResult& CBotTypResult::operator=(const CBotTypResult& src) { m_type = src.m_type; m_limite = src.m_limite; m_pClass = src.m_pClass; m_pNext = NULL; if ( src.m_pNext != NULL ) { m_pNext = new CBotTypResult(*src.m_pNext); } return *this; }