From 0919796df7ab9025bb53ef2dc56d0888de8c7e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Konopacki?= Date: Wed, 8 Aug 2012 02:01:06 +0200 Subject: Transation of comments complete --- src/CBot/CBotStack.cpp | 2942 ++++++++++++++++++++++++------------------------ 1 file changed, 1471 insertions(+), 1471 deletions(-) (limited to 'src/CBot/CBotStack.cpp') diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 419798f..ddb26c6 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -1,1471 +1,1471 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * 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://www.gnu.org/licenses/.////////////////////////////////////////////////////////////////////// - -//Management of the stack - - -#include "CBot.h" -#include -#include - - -#define ITIMER 100 - -//////////////////////////////////////////////////////////////////////////// -// gestion de la pile d'exécution -//////////////////////////////////////////////////////////////////////////// - -int CBotStack::m_initimer = ITIMER; -int CBotStack::m_timer = 0; -CBotVar* CBotStack::m_retvar = NULL; -int CBotStack::m_error = 0; -int CBotStack::m_start = 0; -int CBotStack::m_end = 0; -CBotString CBotStack::m_labelBreak=""; -void* CBotStack::m_pUser = NULL; - -#if STACKMEM - -CBotStack* CBotStack::FirstStack() -{ - CBotStack* p; - - long size = sizeof(CBotStack); - size *= (MAXSTACK+10); - - // demande une tranche mémoire pour la pile - p = (CBotStack*)malloc(size); - - // la vide totalement - memset(p, 0, size); - - p-> m_bBlock = true; - m_timer = m_initimer; // met le timer au début - - CBotStack* pp = p; - pp += MAXSTACK; - int i; - for ( i = 0 ; i< 10 ; i++ ) - { - pp->m_bOver = true; - pp ++; - } -#ifdef _DEBUG - int n = 1; - pp = p; - for ( i = 0 ; i< MAXSTACK+10 ; i++ ) - { - pp->m_index = n++; - pp ++; - } -#endif - - m_error = 0; // évite des blocages car m_error est static - return p; -} - -CBotStack::CBotStack(CBotStack* ppapa) -{ - // constructor must exist or the destructor is never called! - ASM_TRAP(); -} - -CBotStack::~CBotStack() -{ - ASM_TRAP(); // utiliser Delete() à la place -} - -void CBotStack::Delete() -{ - if ( this == NULL || this == EOX ) return; - - m_next->Delete(); - m_next2->Delete(); - - if (m_prev != NULL) - { - if ( m_prev->m_next == this ) - m_prev->m_next = NULL; // enlève de la chaîne - - if ( m_prev->m_next2 == this ) - m_prev->m_next2 = NULL; // enlève de la chaîne - } - - delete m_var; - delete m_listVar; - - CBotStack* p = m_prev; - bool bOver = m_bOver; -#ifdef _DEBUG - int n = m_index; -#endif - - // efface le bloc libéré - memset(this, 0, sizeof(CBotStack)); - m_bOver = bOver; -#ifdef _DEBUG - m_index = n; -#endif - - if ( p == NULL ) - free( this ); -} - - -// routine optimisée -CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock) -{ - if (m_next != NULL) - { - return m_next; // reprise dans une pile existante - } - -#ifdef _DEBUG - int n = 0; -#endif - CBotStack* p = this; - do - { - p ++; -#ifdef _DEBUG - n ++; -#endif - } - while ( p->m_prev != NULL ); - - m_next = p; // chaîne l'élément - p->m_bBlock = bBlock; - p->m_instr = instr; - p->m_prog = m_prog; - p->m_step = 0; - p->m_prev = this; - p->m_state = 0; - p->m_call = NULL; - p->m_bFunc = false; - return p; -} - -CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock) -{ - if (m_next != NULL) - { - if ( m_next == EOX ) - { - m_next = NULL; - return EOX; - } - return m_next; // reprise dans une pile existante - } - CBotStack* p = AddStack(NULL, bBlock); - p->m_call = instr; - p->m_bFunc = 2; // spécial - return p; -} - -CBotStack* CBotStack::AddStack2(bool bBlock) -{ - if (m_next2 != NULL) - { - m_next2->m_prog = m_prog; // spécial évite un RestoreStack2 - return m_next2; // reprise dans une pile existante - } - - CBotStack* p = this; - do - { - p ++; - } - while ( p->m_prev != NULL ); - - m_next2 = p; // chaîne l'élément - p->m_prev = this; - p->m_bBlock = bBlock; - p->m_prog = m_prog; - p->m_step = 0; - return p; -} - -bool CBotStack::GivBlock() -{ - return m_bBlock; -} - -bool CBotStack::Return(CBotStack* pfils) -{ - if ( pfils == this ) return true; // spécial - - if (m_var != NULL) delete m_var; // valeur remplacée ? - m_var = pfils->m_var; // résultat transmis - pfils->m_var = NULL; // ne pas détruire la variable - - m_next->Delete();m_next = NULL; // libère la pile au dessus - m_next2->Delete();m_next2 = NULL; // aussi la seconde pile (catch) - - return (m_error == 0); // interrompu si erreur -} - -bool CBotStack::ReturnKeep(CBotStack* pfils) -{ - if ( pfils == this ) return true; // spécial - - if (m_var != NULL) delete m_var; // valeur remplacée ? - m_var = pfils->m_var; // résultat transmis - pfils->m_var = NULL; // ne pas détruire la variable - - return (m_error == 0); // interrompu si erreur -} - -bool CBotStack::StackOver() -{ - if (!m_bOver) return false; - m_error = TX_STACKOVER; - return true; -} - -#else - -CBotStack::CBotStack(CBotStack* ppapa) -{ - m_next = NULL; - m_next2 = NULL; - m_prev = ppapa; - - m_bBlock = (ppapa == NULL) ? true : false; - - m_state = 0; - m_step = 1; - - if (ppapa == NULL) m_timer = m_initimer; // met le timer au début - - m_listVar = NULL; - m_bDontDelete = false; - - m_var = NULL; - m_prog = NULL; - m_instr = NULL; - m_call = NULL; - m_bFunc = false; -} - -// destructeur -CBotStack::~CBotStack() -{ - if ( m_next != EOX) delete m_next; - delete m_next2; - if (m_prev != NULL && m_prev->m_next == this ) - m_prev->m_next = NULL; // enlève de la chaîne - - delete m_var; - if ( !m_bDontDelete ) delete m_listVar; -} - -// routine à optimiser -CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock) -{ - if (m_next != NULL) - { - return m_next; // reprise dans une pile existante - } - CBotStack* p = new CBotStack(this); - m_next = p; // chaîne l'élément - p->m_bBlock = bBlock; - p->m_instr = instr; - p->m_prog = m_prog; - p->m_step = 0; - return p; -} - -CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock) -{ - if (m_next != NULL) - { - if ( m_next == EOX ) - { - m_next = NULL; - return EOX; - } - return m_next; // reprise dans une pile existante - } - CBotStack* p = new CBotStack(this); - m_next = p; // chaîne l'élément - p->m_bBlock = bBlock; - p->m_call = instr; - p->m_prog = m_prog; - p->m_step = 0; - p->m_bFunc = 2; // spécial - return p; -} - -CBotStack* CBotStack::AddStack2(bool bBlock) -{ - if (m_next2 != NULL) - { - m_next2->m_prog = m_prog; // spécial évite un RestoreStack2 - return m_next2; // reprise dans une pile existante - } - - CBotStack* p = new CBotStack(this); - m_next2 = p; // chaîne l'élément - p->m_bBlock = bBlock; - p->m_prog = m_prog; - p->m_step = 0; - - return p; -} - -bool CBotStack::Return(CBotStack* pfils) -{ - if ( pfils == this ) return true; // spécial - - if (m_var != NULL) delete m_var; // valeur remplacée ? - m_var = pfils->m_var; // résultat transmis - pfils->m_var = NULL; // ne pas détruite la variable - - if ( m_next != EOX ) delete m_next; // libère la pile au dessus - delete m_next2;m_next2 = NULL; // aussi la seconde pile (catch) - - return (m_error == 0); // interrompu si erreur -} - -bool CBotStack::StackOver() -{ - return false; // pas de test de débordement dans cette version -} - -#endif - -void CBotStack::Reset(void* pUser) -{ - m_timer = m_initimer; // remet le timer - m_error = 0; -// m_start = 0; -// m_end = 0; - m_labelBreak.Empty(); - m_pUser = pUser; -} - - - - -CBotStack* CBotStack::RestoreStack(CBotInstr* instr) -{ - if (m_next != NULL) - { - m_next->m_instr = instr; // réinit (si reprise après restitution) - m_next->m_prog = m_prog; - return m_next; // reprise dans une pile existante - } - return NULL; -} - -CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr) -{ - CBotStack* p = RestoreStack(); - p->m_call = instr; - return p; -} - - - -// routine pour l'exécution pas à pas -bool CBotStack::IfStep() -{ - if ( m_initimer > 0 || m_step++ > 0 ) return false; - return true; -} - - -bool CBotStack::BreakReturn(CBotStack* pfils, const char* name) -{ - if ( m_error>=0 ) return false; // sortie normale - if ( m_error==-3 ) return false; // sortie normale (return en cours) - - if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name)) - return false; // c'est pas pour moi - - m_error = 0; - m_labelBreak.Empty(); - return Return(pfils); -} - -bool CBotStack::IfContinue(int state, const char* name) -{ - if ( m_error != -2 ) return false; - - if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name)) - return false; // c'est pas pour moi - - m_state = state; // où reprendre ? - m_error = 0; - m_labelBreak.Empty(); - if ( m_next != EOX ) m_next->Delete(); // purge la pile au dessus - return true; -} - -void CBotStack::SetBreak(int val, const char* name) -{ - m_error = -val; // réagit comme une Exception - m_labelBreak = name; - if (val == 3) // pour un return - { - m_retvar = m_var; - m_var = NULL; - } -} - -// remet sur la pile la valeur calculée par le dernier CBotReturn - -bool CBotStack::GivRetVar(bool bRet) -{ - if (m_error == -3) - { - if ( m_var ) delete m_var; - m_var = m_retvar; - m_retvar = NULL; - m_error = 0; - return true; - } - return bRet; // interrompu par autre chose que return -} - -int CBotStack::GivError(int& start, int& end) -{ - start = m_start; - end = m_end; - return m_error; -} - - -int CBotStack::GivType(int mode) -{ - if (m_var == NULL) return -1; - return m_var->GivType(mode); -} - -CBotTypResult CBotStack::GivTypResult(int mode) -{ - if (m_var == NULL) return -1; - return m_var->GivTypResult(mode); -} - -void CBotStack::SetType(CBotTypResult& type) -{ - if (m_var == NULL) return; - m_var->SetType( type ); -} - - -CBotVar* CBotStack::FindVar(CBotToken* &pToken, bool bUpdate, bool bModif) -{ - CBotStack* p = this; - CBotString name = pToken->GivString(); - - while (p != NULL) - { - CBotVar* pp = p->m_listVar; - while ( pp != NULL) - { - if (pp->GivName() == name) - { - if ( bUpdate ) - pp->Maj(m_pUser, false); - - return pp; - } - pp = pp->m_next; - } - p = p->m_prev; - } - return NULL; -} - -CBotVar* CBotStack::FindVar(const char* name) -{ - CBotStack* p = this; - while (p != NULL) - { - CBotVar* pp = p->m_listVar; - while ( pp != NULL) - { - if (pp->GivName() == name) - { - return pp; - } - pp = pp->m_next; - } - p = p->m_prev; - } - return NULL; -} - -CBotVar* CBotStack::FindVar(long ident, bool bUpdate, bool bModif) -{ - CBotStack* p = this; - while (p != NULL) - { - CBotVar* pp = p->m_listVar; - while ( pp != NULL) - { - if (pp->GivUniqNum() == ident) - { - if ( bUpdate ) - pp->Maj(m_pUser, false); - - return pp; - } - pp = pp->m_next; - } - p = p->m_prev; - } - return NULL; -} - - -CBotVar* CBotStack::FindVar(CBotToken& Token, bool bUpdate, bool bModif) -{ - CBotToken* pt = &Token; - return FindVar(pt, bUpdate, bModif); -} - - -CBotVar* CBotStack::CopyVar(CBotToken& Token, bool bUpdate) -{ - CBotVar* pVar = FindVar( Token, bUpdate ); - - if ( pVar == NULL) return NULL; - - CBotVar* pCopy = CBotVar::Create(pVar); - pCopy->Copy(pVar); - return pCopy; -} - - -bool CBotStack::SetState(int n, int limite) -{ - m_state = n; - - m_timer--; // décompte les opérations - return ( m_timer > limite ); // interrompu si timer passé -} - -bool CBotStack::IncState(int limite) -{ - m_state++; - - m_timer--; // décompte les opérations - return ( m_timer > limite ); // interrompu si timer passé -} - - -void CBotStack::SetError(int n, CBotToken* token) -{ - if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante - m_error = n; - if (token != NULL) - { - m_start = token->GivStart(); - m_end = token->GivEnd(); - } -} - -void CBotStack::ResetError(int n, int start, int end) -{ - m_error = n; - m_start = start; - m_end = end; -} - -void CBotStack::SetPosError(CBotToken* token) -{ - m_start = token->GivStart(); - m_end = token->GivEnd(); -} - -void CBotStack::SetTimer(int n) -{ - m_initimer = n; -} - -bool CBotStack::Execute() -{ - CBotCall* instr = NULL; // instruction la plus élevée - CBotStack* pile; - - CBotStack* p = this; - - while (p != NULL) - { - if ( p->m_next2 != NULL ) break; - if ( p->m_call != NULL ) - { - instr = p->m_call; - pile = p->m_prev ; - } - p = p->m_next; - } - - if ( instr == NULL ) return true; // exécution normale demandée - - if (!instr->Run(pile)) return false; // exécution à partir de là - -#if STACKMEM - pile->m_next->Delete(); -#else - delete pile->m_next; -#endif - - pile->m_next = EOX; // spécial pour reprise - return true; -} - -// met sur le stack le pointeur à une variable -void CBotStack::SetVar( CBotVar* var ) -{ - if (m_var) delete m_var; // remplacement d'une variable - m_var = var; -} - -// met sur le stack une copie d'une variable -void CBotStack::SetCopyVar( CBotVar* var ) -{ - if (m_var) delete m_var; // remplacement d'une variable - - m_var = CBotVar::Create("", var->GivTypResult(2)); - m_var->Copy( var ); -} - -CBotVar* CBotStack::GivVar() -{ - return m_var; -} - -CBotVar* CBotStack::GivPtVar() -{ - CBotVar* p = m_var; - m_var = NULL; // ne sera pas détruit donc - return p; -} - -CBotVar* CBotStack::GivCopyVar() -{ - if (m_var == NULL) return NULL; - CBotVar* v = CBotVar::Create("", m_var->GivType()); - v->Copy( m_var ); - return v; -} - -long CBotStack::GivVal() -{ - if (m_var == NULL) return 0; - return m_var->GivValInt(); -} - - - - -void CBotStack::AddVar(CBotVar* pVar) -{ - CBotStack* p = this; - - // revient sur l'élement père - while (p != NULL && p->m_bBlock == 0) p = p->m_prev; - - if ( p == NULL ) return; - -/// p->m_bDontDelete = bDontDelete; - - CBotVar** pp = &p->m_listVar; - while ( *pp != NULL ) pp = &(*pp)->m_next; - - *pp = pVar; // ajoute à la suite - -#ifdef _DEBUG - if ( pVar->GivUniqNum() == 0 ) ASM_TRAP(); -#endif -} - -/*void CBotStack::RestoreVar(CBotVar* pVar) -{ - if ( !m_bDontDelete ) __asm int 3; - delete m_listVar; - m_listVar = pVar; // remplace directement -}*/ - -void CBotStack::SetBotCall(CBotProgram* p) -{ - m_prog = p; - m_bFunc = true; -} - -CBotProgram* CBotStack::GivBotCall(bool bFirst) -{ - if ( ! bFirst ) return m_prog; - CBotStack* p = this; - while ( p->m_prev != NULL ) p = p->m_prev; - return p->m_prog; -} - -void* CBotStack::GivPUser() -{ - return m_pUser; -} - - -bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype) -{ - CBotTypResult res; - - // cherche d'abord selon l'identificateur - - res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype ); - if (res.GivType() >= 0) return res.GivType(); - - res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token ); - if (res.GivType() >= 0) return res.GivType(); - - // si pas trouvé (recompilé ?) cherche selon le nom - - nIdent = 0; - res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype ); - if (res.GivType() >= 0) return res.GivType(); - - res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token ); - if (res.GivType() >= 0) return res.GivType(); - - SetError(TX_NOCALL, token); - return true; -} - -void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar) -{ - if ( m_next == NULL ) return; - - if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) ) - m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this ); -} - - -bool SaveVar(FILE* pf, CBotVar* pVar) -{ - while ( true ) - { - if ( pVar == NULL ) - { - return WriteWord(pf, 0); // met un terminateur - } - - if ( !pVar->Save0State(pf)) return false; // entête commune - if ( !pVar->Save1State(pf) ) return false; // sauve selon la classe fille - - pVar = pVar->GivNext(); - } -} - -void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end) -{ - CBotProgram* prog = m_prog; // programme courrant - - CBotInstr* funct = NULL; // fonction trouvée - CBotInstr* instr = NULL; // instruction la plus élevée - - CBotStack* p = this; - - while (p->m_next != NULL) - { - if ( p->m_instr != NULL ) instr = p->m_instr; - if ( p->m_bFunc == 1 ) funct = p->m_instr; - if ( p->m_next->m_prog != prog ) break ; - - if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; - else p = p->m_next; - } - - if ( p->m_instr != NULL ) instr = p->m_instr; - if ( p->m_bFunc == 1 ) funct = p->m_instr; - - if ( funct == NULL ) return; - - CBotToken* t = funct->GivToken(); - FunctionName = t->GivString(); - -// if ( p->m_instr != NULL ) instr = p->m_instr; - - t = instr->GivToken(); - start = t->GivStart(); - end = t->GivEnd(); -} - -CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level) -{ - CBotProgram* prog = m_prog; // programme courrant - FunctionName = NULL; - - // remonte la pile dans le module courant - CBotStack* p = this; - - while (p->m_next != NULL) - { - if ( p->m_next->m_prog != prog ) break ; - - if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; - else p = p->m_next; - } - - - // descend sur les éléments de block - while ( p != NULL && !p->m_bBlock ) p = p->m_prev; - - while ( p != NULL && level++ < 0 ) - { - p = p->m_prev; - while ( p != NULL && !p->m_bBlock ) p = p->m_prev; - } - - if ( p == NULL ) return NULL; - - // recherche le nom de la fonction courante - CBotStack* pp = p; - while ( pp != NULL ) - { - if ( pp->m_bFunc == 1 ) break; - pp = pp->m_prev; - } - - if ( pp == NULL || pp->m_instr == NULL ) return NULL; - - CBotToken* t = pp->m_instr->GivToken(); - FunctionName = t->GivString(); - - return p->m_listVar; -} - -bool CBotStack::SaveState(FILE* pf) -{ - if ( this == NULL ) // fin de l'arbre ? - { - return WriteWord(pf, 0); // met un terminateur - } - - if ( m_next2 != NULL ) - { - if (!WriteWord(pf, 2)) return false; // une marque de poursuite - if (!m_next2->SaveState(pf)) return false; - } - else - { - if (!WriteWord(pf, 1)) return false; // une marque de poursuite - } - if (!WriteWord(pf, m_bBlock)) return false; // est-ce un bloc local - if (!WriteWord(pf, m_state)) return false; // dans quel état - if (!WriteWord(pf, 0)) return false; // par compatibilité m_bDontDelete - if (!WriteWord(pf, m_step)) return false; // dans quel état - - - if (!SaveVar(pf, m_var)) return false; // le résultat courant - if (!SaveVar(pf, m_listVar)) return false; // les variables locales - - return m_next->SaveState(pf); // enregistre la suite -} - - -bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack) -{ - unsigned short w; - - pStack = NULL; - if (!ReadWord(pf, w)) return false; - if ( w == 0 ) return true; - -#if STACKMEM - if ( this == NULL ) pStack = FirstStack(); - else pStack = AddStack(); -#else - pStack = new CBotStack(this); -#endif - - if ( w == 2 ) - { - if (!pStack->RestoreState(pf, pStack->m_next2)) return false; - } - - if (!ReadWord(pf, w)) return false; // est-ce un bloc local - pStack->m_bBlock = w; - - if (!ReadWord(pf, w)) return false; // dans quel état j'ère ? - pStack->SetState((short)w); // dans le bon état - - if (!ReadWord(pf, w)) return false; // dont delete ? - // plus utilisé - - if (!ReadWord(pf, w)) return false; // pas à pas - pStack->m_step = w; - - if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // la variable temp - if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// les variables locales - - return pStack->RestoreState(pf, pStack->m_next); -} - - -bool CBotVar::Save0State(FILE* pf) -{ - if (!WriteWord(pf, 100+m_mPrivate))return false; // variable privée ? - if (!WriteWord(pf, m_bStatic))return false; // variable static ? - if (!WriteWord(pf, m_type.GivType()))return false; // enregiste le type (toujours non nul) - if (!WriteWord(pf, m_binit))return false; // variable définie ? - return WriteString(pf, m_token->GivString()); // et le nom de la variable -} - -bool CBotVarInt::Save0State(FILE* pf) -{ - if ( !m_defnum.IsEmpty() ) - { - if(!WriteWord(pf, 200 )) return false; // marqueur spécial - if(!WriteString(pf, m_defnum)) return false; // nom de la valeur - } - - return CBotVar::Save0State(pf); -} - -bool CBotVarInt::Save1State(FILE* pf) -{ - return WriteWord(pf, m_val); // la valeur de la variable -} - -bool CBotVarBoolean::Save1State(FILE* pf) -{ - return WriteWord(pf, m_val); // la valeur de la variable -} - -bool CBotVarFloat::Save1State(FILE* pf) -{ - return WriteFloat(pf, m_val); // la valeur de la variable -} - -bool CBotVarString::Save1State(FILE* pf) -{ - return WriteString(pf, m_val); // la valeur de la variable -} - - - -bool CBotVarClass::Save1State(FILE* pf) -{ - if ( !WriteType(pf, m_type) ) return false; - if ( !WriteLong(pf, m_ItemIdent) ) return false; - - return SaveVar(pf, m_pVar); // contenu de l'objet -} - -bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) -{ - unsigned short w, wi, prv, st; - float ww; - CBotString name, s; - - delete pVar; - - pVar = NULL; - CBotVar* pNew = NULL; - CBotVar* pPrev = NULL; - - while ( true ) // recupère toute une liste - { - if (!ReadWord(pf, w)) return false; // privé ou type ? - if ( w == 0 ) return true; - - CBotString defnum; - if ( w == 200 ) - { - if (!ReadString(pf, defnum)) return false; // nombre avec un identifiant - if (!ReadWord(pf, w)) return false; // type - } - - prv = 100; st = 0; - if ( w >= 100 ) - { - prv = w; - if (!ReadWord(pf, st)) return false; // statique - if (!ReadWord(pf, w)) return false; // type - } - - if ( w == CBotTypClass ) w = CBotTypIntrinsic; // forcément intrinsèque - - if (!ReadWord(pf, wi)) return false; // init ? - - if (!ReadString(pf, name)) return false; // nom de la variable - - CBotToken token(name, CBotString()); - - switch (w) - { - case CBotTypInt: - case CBotTypBoolean: - pNew = CBotVar::Create(&token, w); // crée une variable - if (!ReadWord(pf, w)) return false; - pNew->SetValInt((short)w, defnum); - break; - case CBotTypFloat: - pNew = CBotVar::Create(&token, w); // crée une variable - if (!ReadFloat(pf, ww)) return false; - pNew->SetValFloat(ww); - break; - case CBotTypString: - pNew = CBotVar::Create(&token, w); // crée une variable - if (!ReadString(pf, s)) return false; - pNew->SetValString(s); - break; - - // restitue un objet intrinsic ou un élément d'un array - case CBotTypIntrinsic: - case CBotTypArrayBody: - { - CBotTypResult r; - long id; - if (!ReadType(pf, r)) return false; // type complet - if (!ReadLong(pf, id) ) return false; - -// if (!ReadString(pf, s)) return false; - { - CBotVar* p = NULL; - if ( id ) p = CBotVarClass::Find(id) ; - - pNew = new CBotVarClass(&token, r); // crée directement une instance - // attention cptuse = 0 - if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return false; - pNew->SetIdent(id); - - if ( p != NULL ) - { - delete pNew; - pNew = p; // reprend l'élément connu - } - } - } - break; - - case CBotTypPointer: - case CBotTypNullPointer: - if (!ReadString(pf, s)) return false; - { - pNew = CBotVar::Create(&token, CBotTypResult(w, s));// crée une variable - CBotVarClass* p = NULL; - long id; - ReadLong(pf, id); -// if ( id ) p = CBotVarClass::Find(id); // retrouve l'instance ( fait par RestoreInstance ) - - // restitue une copie de l'instance d'origine - CBotVar* pInstance = NULL; - if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; - ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus - -// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // plutôt celui-ci ! - - } - break; - - case CBotTypArrayPointer: - { - CBotTypResult r; - if (!ReadType(pf, r)) return false; - - pNew = CBotVar::Create(&token, r); // crée une variable - - // restitue une copie de l'instance d'origine - CBotVar* pInstance = NULL; - if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; - ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus - } - break; - default: - ASM_TRAP(); - } - - if ( pPrev != NULL ) pPrev->m_next = pNew; - if ( pVar == NULL ) pVar = pNew; - - pNew->m_binit = wi; // pNew->SetInit(wi); - pNew->SetStatic(st); - pNew->SetPrivate(prv-100); - pPrev = pNew; - } - return true; -} - - - - -//////////////////////////////////////////////////////////////////////////// -// gestion de la pile à la compilation -//////////////////////////////////////////////////////////////////////////// - -CBotProgram* CBotCStack::m_prog = NULL; // init la variable statique -int CBotCStack::m_error = 0; -int CBotCStack::m_end = 0; -CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0); -//CBotToken* CBotCStack::m_retClass= NULL; - - -CBotCStack::CBotCStack(CBotCStack* ppapa) -{ - m_next = NULL; - m_prev = ppapa; - - if (ppapa == NULL) - { - m_error = 0; - m_start = 0; - m_end = 0; - m_bBlock = true; - } - else - { - m_start = ppapa->m_start; - m_bBlock = false; - } - - m_listVar = NULL; - m_var = NULL; -} - -// destructeur -CBotCStack::~CBotCStack() -{ - if (m_next != NULL) delete m_next; - if (m_prev != NULL) m_prev->m_next = NULL; // enlève de la chaîne - - delete m_var; - delete m_listVar; -} - -// utilisé uniquement à la compilation -CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock) -{ - if (m_next != NULL) return m_next; // reprise dans une pile existante - - CBotCStack* p = new CBotCStack(this); - m_next = p; // chaîne l'élément - p->m_bBlock = bBlock; - - if (pToken != NULL) p->SetStartError(pToken->GivStart()); - - return p; -} - - -CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils) -{ - if ( pfils == this ) return inst; - - if (m_var != NULL) delete m_var; // valeur remplacée ? - m_var = pfils->m_var; // résultat transmis - pfils->m_var = NULL; // ne pas détruire la variable - - if (m_error) - { - m_start = pfils->m_start; // récupère la position de l'erreur - m_end = pfils->m_end; - } - - delete pfils; - return inst; -} - -CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils) -{ - if (m_var != NULL) delete m_var; // valeur remplacée ? - m_var = pfils->m_var; // résultat transmis - pfils->m_var = NULL; // ne pas détruire la variable - - if (m_error) - { - m_start = pfils->m_start; // récupère la position de l'erreur - m_end = pfils->m_end; - } - - delete pfils; - return inst; -} - -int CBotCStack::GivError(int& start, int& end) -{ - start = m_start; - end = m_end; - return m_error; -} - -int CBotCStack::GivError() -{ - return m_error; -} - -// type d'instruction sur la pile -CBotTypResult CBotCStack::GivTypResult(int mode) -{ - if (m_var == NULL) - return CBotTypResult(99); - return m_var->GivTypResult(mode); -} - -// type d'instruction sur la pile -int CBotCStack::GivType(int mode) -{ - if (m_var == NULL) - return 99; - return m_var->GivType(mode); -} - -// pointeur sur la pile est de quelle classe ? -CBotClass* CBotCStack::GivClass() -{ - if ( m_var == NULL ) - return NULL; - if ( m_var->GivType(1) != CBotTypPointer ) return NULL; - - return m_var->GivClass(); -} - -// type d'instruction sur la pile -void CBotCStack::SetType(CBotTypResult& type) -{ - if (m_var == NULL) return; - m_var->SetType( type ); -} - -// cherche une variable sur la pile -// le token peut être une suite de TokenTypVar (objet d'une classe) -// ou un pointeur dans le source - -CBotVar* CBotCStack::FindVar(CBotToken* &pToken) -{ - CBotCStack* p = this; - CBotString name = pToken->GivString(); - - while (p != NULL) - { - CBotVar* pp = p->m_listVar; - while ( pp != NULL) - { - if (name == pp->GivName()) - { - return pp; - } - pp = pp->m_next; - } - p = p->m_prev; - } - return NULL; -} - -CBotVar* CBotCStack::FindVar(CBotToken& Token) -{ - CBotToken* pt = &Token; - return FindVar(pt); -} - -CBotVar* CBotCStack::CopyVar(CBotToken& Token) -{ - CBotVar* pVar = FindVar( Token ); - - if ( pVar == NULL) return NULL; - - CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() ); - pCopy->Copy(pVar); - return pCopy; -} - -bool CBotCStack::IsOk() -{ - return (m_error == 0); -} - - -void CBotCStack::SetStartError( int pos ) -{ - if ( m_error != 0) return; // ne change pas une erreur déjà existante - m_start = pos; -} - -void CBotCStack::SetError(int n, int pos) -{ - if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante - m_error = n; - m_end = pos; -} - -void CBotCStack::SetError(int n, CBotToken* p) -{ - if (m_error) return; // ne change pas une erreur déjà existante - m_error = n; - m_start = p->GivStart(); - m_end = p->GivEnd(); -} - -void CBotCStack::ResetError(int n, int start, int end) -{ - m_error = n; - m_start = start; - m_end = end; -} - -bool CBotCStack::NextToken(CBotToken* &p) -{ - CBotToken* pp = p; - - p = p->GivNext(); - if (p!=NULL) return true; - - SetError(TX_ENDOF, pp->GivEnd()); - return false; -} - -void CBotCStack::SetBotCall(CBotProgram* p) -{ - m_prog = p; -} - -CBotProgram* CBotCStack::GivBotCall() -{ - return m_prog; -} - -void CBotCStack::SetRetType(CBotTypResult& type) -{ - m_retTyp = type; -} - -CBotTypResult CBotCStack::GivRetType() -{ - return m_retTyp; -} - -void CBotCStack::SetVar( CBotVar* var ) -{ - if (m_var) delete m_var; // remplacement d'une variable - m_var = var; -} - -// met sur le stack une copie d'une variable -void CBotCStack::SetCopyVar( CBotVar* var ) -{ - if (m_var) delete m_var; // remplacement d'une variable - - if ( var == NULL ) return; - m_var = CBotVar::Create("", var->GivTypResult(2)); - m_var->Copy( var ); -} - -CBotVar* CBotCStack::GivVar() -{ - return m_var; -} - -void CBotCStack::AddVar(CBotVar* pVar) -{ - CBotCStack* p = this; - - // revient sur l'élement père - while (p != NULL && p->m_bBlock == 0) p = p->m_prev; - - if ( p == NULL ) return; - - CBotVar** pp = &p->m_listVar; - while ( *pp != NULL ) pp = &(*pp)->m_next; - - *pp = pVar; // ajoute à la suite - -#ifdef _DEBUG - if ( pVar->GivUniqNum() == 0 ) ASM_TRAP(); -#endif -} - -// test si une variable est déjà définie localement - -bool CBotCStack::CheckVarLocal(CBotToken* &pToken) -{ - CBotCStack* p = this; - CBotString name = pToken->GivString(); - - while (p != NULL) - { - CBotVar* pp = p->m_listVar; - while ( pp != NULL) - { - if (name == pp->GivName()) - return true; - pp = pp->m_next; - } - if ( p->m_bBlock ) return false; - p = p->m_prev; - } - return false; -} - -CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent) -{ - nIdent = 0; - CBotTypResult val(-1); - - val = CBotCall::CompileCall(p, ppVars, this, nIdent); - if (val.GivType() < 0) - { - val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent); - if ( val.GivType() < 0 ) - { - // pVar = NULL; // l'erreur n'est pas sur un paramètre en particulier - SetError( -val.GivType(), p ); - val.SetType(-val.GivType()); - return val; - } - } - return val; -} - -// test si un nom de procédure est déjà défini quelque part - -bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) -{ - CBotString name = pToken->GivString(); - - if ( CBotCall::CheckCall(name) ) return true; - - CBotFunction* pp = m_prog->GivFunctions(); - while ( pp != NULL ) - { - if ( pToken->GivString() == pp->GivName() ) - { - // les paramètres sont-ils exactement les mêmes ? - if ( pp->CheckParam( pParam ) ) - return true; - } - pp = pp->Next(); - } - - pp = CBotFunction::m_listPublic; - while ( pp != NULL ) - { - if ( pToken->GivString() == pp->GivName() ) - { - // les paramètres sont-ils exactement les mêmes ? - if ( pp->CheckParam( pParam ) ) - return true; - } - pp = pp->m_nextpublic; - } - - return false; -} - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * 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://www.gnu.org/licenses/. + +//Management of the stack + + +#include "CBot.h" +#include +#include + + +#define ITIMER 100 + +//////////////////////////////////////////////////////////////////////////// +// management of a execution of a stack +//////////////////////////////////////////////////////////////////////////// + +int CBotStack::m_initimer = ITIMER; +int CBotStack::m_timer = 0; +CBotVar* CBotStack::m_retvar = NULL; +int CBotStack::m_error = 0; +int CBotStack::m_start = 0; +int CBotStack::m_end = 0; +CBotString CBotStack::m_labelBreak=""; +void* CBotStack::m_pUser = NULL; + +#if STACKMEM + +CBotStack* CBotStack::FirstStack() +{ + CBotStack* p; + + long size = sizeof(CBotStack); + size *= (MAXSTACK+10); + + // request a slice of memory for the stack + p = (CBotStack*)malloc(size); + + // completely empty + memset(p, 0, size); + + p-> m_bBlock = true; + m_timer = m_initimer; // sets the timer at the beginning + + CBotStack* pp = p; + pp += MAXSTACK; + int i; + for ( i = 0 ; i< 10 ; i++ ) + { + pp->m_bOver = true; + pp ++; + } +#ifdef _DEBUG + int n = 1; + pp = p; + for ( i = 0 ; i< MAXSTACK+10 ; i++ ) + { + pp->m_index = n++; + pp ++; + } +#endif + + m_error = 0; // avoids deadlocks because m_error is static + return p; +} + +CBotStack::CBotStack(CBotStack* ppapa) +{ + // constructor must exist or the destructor is never called! + ASM_TRAP(); +} + +CBotStack::~CBotStack() +{ + ASM_TRAP(); // use Delete () instead +} + +void CBotStack::Delete() +{ + if ( this == NULL || this == EOX ) return; + + m_next->Delete(); + m_next2->Delete(); + + if (m_prev != NULL) + { + if ( m_prev->m_next == this ) + m_prev->m_next = NULL; // removes chain + + if ( m_prev->m_next2 == this ) + m_prev->m_next2 = NULL; // removes chain + } + + delete m_var; + delete m_listVar; + + CBotStack* p = m_prev; + bool bOver = m_bOver; +#ifdef _DEBUG + int n = m_index; +#endif + + // clears the freed block + memset(this, 0, sizeof(CBotStack)); + m_bOver = bOver; +#ifdef _DEBUG + m_index = n; +#endif + + if ( p == NULL ) + free( this ); +} + + +// routine improved +CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock) +{ + if (m_next != NULL) + { + return m_next; // included in an existing stack + } + +#ifdef _DEBUG + int n = 0; +#endif + CBotStack* p = this; + do + { + p ++; +#ifdef _DEBUG + n ++; +#endif + } + while ( p->m_prev != NULL ); + + m_next = p; // chain an element + p->m_bBlock = bBlock; + p->m_instr = instr; + p->m_prog = m_prog; + p->m_step = 0; + p->m_prev = this; + p->m_state = 0; + p->m_call = NULL; + p->m_bFunc = false; + return p; +} + +CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock) +{ + if (m_next != NULL) + { + if ( m_next == EOX ) + { + m_next = NULL; + return EOX; + } + return m_next; // included in an existing stack + } + CBotStack* p = AddStack(NULL, bBlock); + p->m_call = instr; + p->m_bFunc = 2; // special + return p; +} + +CBotStack* CBotStack::AddStack2(bool bBlock) +{ + if (m_next2 != NULL) + { + m_next2->m_prog = m_prog; // special avoids RestoreStack2 + return m_next2; // included in an existing stack + } + + CBotStack* p = this; + do + { + p ++; + } + while ( p->m_prev != NULL ); + + m_next2 = p; // chain an element + p->m_prev = this; + p->m_bBlock = bBlock; + p->m_prog = m_prog; + p->m_step = 0; + return p; +} + +bool CBotStack::GivBlock() +{ + return m_bBlock; +} + +bool CBotStack::Return(CBotStack* pfils) +{ + if ( pfils == this ) return true; // special + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + m_next->Delete();m_next = NULL; // releases the stack above + m_next2->Delete();m_next2 = NULL; // also the second stack (catch) + + return (m_error == 0); // interrupted if error +} + +bool CBotStack::ReturnKeep(CBotStack* pfils) +{ + if ( pfils == this ) return true; // special + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + return (m_error == 0); // interrupted if error +} + +bool CBotStack::StackOver() +{ + if (!m_bOver) return false; + m_error = TX_STACKOVER; + return true; +} + +#else + +CBotStack::CBotStack(CBotStack* ppapa) +{ + m_next = NULL; + m_next2 = NULL; + m_prev = ppapa; + + m_bBlock = (ppapa == NULL) ? true : false; + + m_state = 0; + m_step = 1; + + if (ppapa == NULL) m_timer = m_initimer; // sets the timer at the beginning + + m_listVar = NULL; + m_bDontDelete = false; + + m_var = NULL; + m_prog = NULL; + m_instr = NULL; + m_call = NULL; + m_bFunc = false; +} + +// destructor +CBotStack::~CBotStack() +{ + if ( m_next != EOX) delete m_next; + delete m_next2; + if (m_prev != NULL && m_prev->m_next == this ) + m_prev->m_next = NULL; // removes chain + + delete m_var; + if ( !m_bDontDelete ) delete m_listVar; +} + +// \TODO routine has/to optimize +CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock) +{ + if (m_next != NULL) + { + return m_next; // included in an existing stack + } + CBotStack* p = new CBotStack(this); + m_next = p; // chain an element + p->m_bBlock = bBlock; + p->m_instr = instr; + p->m_prog = m_prog; + p->m_step = 0; + return p; +} + +CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock) +{ + if (m_next != NULL) + { + if ( m_next == EOX ) + { + m_next = NULL; + return EOX; + } + return m_next; // included in an existing stack + } + CBotStack* p = new CBotStack(this); + m_next = p; // chain an element + p->m_bBlock = bBlock; + p->m_call = instr; + p->m_prog = m_prog; + p->m_step = 0; + p->m_bFunc = 2; // special + return p; +} + +CBotStack* CBotStack::AddStack2(bool bBlock) +{ + if (m_next2 != NULL) + { + m_next2->m_prog = m_prog; // special avoids RestoreStack2 + return m_next2; // included in an existing stack + } + + CBotStack* p = new CBotStack(this); + m_next2 = p; // chain an element + p->m_bBlock = bBlock; + p->m_prog = m_prog; + p->m_step = 0; + + return p; +} + +bool CBotStack::Return(CBotStack* pfils) +{ + if ( pfils == this ) return true; // special + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // do not destroy the variable + + if ( m_next != EOX ) delete m_next; // releases the stack above + delete m_next2;m_next2 = NULL; // also the second stack (catch) + + return (m_error == 0); // interrupted if error +} + +bool CBotStack::StackOver() +{ + return false; // no overflow check in this version +} + +#endif + +void CBotStack::Reset(void* pUser) +{ + m_timer = m_initimer; // resets the timer + m_error = 0; +// m_start = 0; +// m_end = 0; + m_labelBreak.Empty(); + m_pUser = pUser; +} + + + + +CBotStack* CBotStack::RestoreStack(CBotInstr* instr) +{ + if (m_next != NULL) + { + m_next->m_instr = instr; // reset (if recovery after ) + m_next->m_prog = m_prog; + return m_next; // included in an existing stack + } + return NULL; +} + +CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr) +{ + CBotStack* p = RestoreStack(); + p->m_call = instr; + return p; +} + + + +// routine for execution step by step +bool CBotStack::IfStep() +{ + if ( m_initimer > 0 || m_step++ > 0 ) return false; + return true; +} + + +bool CBotStack::BreakReturn(CBotStack* pfils, const char* name) +{ + if ( m_error>=0 ) return false; // normal output + if ( m_error==-3 ) return false; // normal output (return current) + + if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name)) + return false; // it's not for me + + m_error = 0; + m_labelBreak.Empty(); + return Return(pfils); +} + +bool CBotStack::IfContinue(int state, const char* name) +{ + if ( m_error != -2 ) return false; + + if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name)) + return false; // it's not for me + + m_state = state; // where again? + m_error = 0; + m_labelBreak.Empty(); + if ( m_next != EOX ) m_next->Delete(); // purge above stack + return true; +} + +void CBotStack::SetBreak(int val, const char* name) +{ + m_error = -val; // reacts as an Exception + m_labelBreak = name; + if (val == 3) // for a return + { + m_retvar = m_var; + m_var = NULL; + } +} + +// gives on the stack value calculated by the last CBotReturn + +bool CBotStack::GivRetVar(bool bRet) +{ + if (m_error == -3) + { + if ( m_var ) delete m_var; + m_var = m_retvar; + m_retvar = NULL; + m_error = 0; + return true; + } + return bRet; // interrupted by something other than return +} + +int CBotStack::GivError(int& start, int& end) +{ + start = m_start; + end = m_end; + return m_error; +} + + +int CBotStack::GivType(int mode) +{ + if (m_var == NULL) return -1; + return m_var->GivType(mode); +} + +CBotTypResult CBotStack::GivTypResult(int mode) +{ + if (m_var == NULL) return -1; + return m_var->GivTypResult(mode); +} + +void CBotStack::SetType(CBotTypResult& type) +{ + if (m_var == NULL) return; + m_var->SetType( type ); +} + + +CBotVar* CBotStack::FindVar(CBotToken* &pToken, bool bUpdate, bool bModif) +{ + CBotStack* p = this; + CBotString name = pToken->GivString(); + + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (pp->GivName() == name) + { + if ( bUpdate ) + pp->Maj(m_pUser, false); + + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + +CBotVar* CBotStack::FindVar(const char* name) +{ + CBotStack* p = this; + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (pp->GivName() == name) + { + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + +CBotVar* CBotStack::FindVar(long ident, bool bUpdate, bool bModif) +{ + CBotStack* p = this; + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (pp->GivUniqNum() == ident) + { + if ( bUpdate ) + pp->Maj(m_pUser, false); + + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + + +CBotVar* CBotStack::FindVar(CBotToken& Token, bool bUpdate, bool bModif) +{ + CBotToken* pt = &Token; + return FindVar(pt, bUpdate, bModif); +} + + +CBotVar* CBotStack::CopyVar(CBotToken& Token, bool bUpdate) +{ + CBotVar* pVar = FindVar( Token, bUpdate ); + + if ( pVar == NULL) return NULL; + + CBotVar* pCopy = CBotVar::Create(pVar); + pCopy->Copy(pVar); + return pCopy; +} + + +bool CBotStack::SetState(int n, int limite) +{ + m_state = n; + + m_timer--; // decrement the operations \TODO decrement the operations + return ( m_timer > limite ); // interrupted if timer pass +} + +bool CBotStack::IncState(int limite) +{ + m_state++; + + m_timer--; // decrement the operations \TODO decompte les operations + return ( m_timer > limite ); // interrupted if timer pass +} + + +void CBotStack::SetError(int n, CBotToken* token) +{ + if ( n!= 0 && m_error != 0) return; // does not change existing error + m_error = n; + if (token != NULL) + { + m_start = token->GivStart(); + m_end = token->GivEnd(); + } +} + +void CBotStack::ResetError(int n, int start, int end) +{ + m_error = n; + m_start = start; + m_end = end; +} + +void CBotStack::SetPosError(CBotToken* token) +{ + m_start = token->GivStart(); + m_end = token->GivEnd(); +} + +void CBotStack::SetTimer(int n) +{ + m_initimer = n; +} + +bool CBotStack::Execute() +{ + CBotCall* instr = NULL; // the most highest instruction + CBotStack* pile; + + CBotStack* p = this; + + while (p != NULL) + { + if ( p->m_next2 != NULL ) break; + if ( p->m_call != NULL ) + { + instr = p->m_call; + pile = p->m_prev ; + } + p = p->m_next; + } + + if ( instr == NULL ) return true; // normal execution request + + if (!instr->Run(pile)) return false; // \TODO exécution à partir de là + +#if STACKMEM + pile->m_next->Delete(); +#else + delete pile->m_next; +#endif + + pile->m_next = EOX; // special for recovery + return true; +} + +// puts on the stack pointer to a variable +void CBotStack::SetVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + m_var = var; +} + +// puts on the stack a copy of a variable +void CBotStack::SetCopyVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + + m_var = CBotVar::Create("", var->GivTypResult(2)); + m_var->Copy( var ); +} + +CBotVar* CBotStack::GivVar() +{ + return m_var; +} + +CBotVar* CBotStack::GivPtVar() +{ + CBotVar* p = m_var; + m_var = NULL; // therefore will not be destroyed + return p; +} + +CBotVar* CBotStack::GivCopyVar() +{ + if (m_var == NULL) return NULL; + CBotVar* v = CBotVar::Create("", m_var->GivType()); + v->Copy( m_var ); + return v; +} + +long CBotStack::GivVal() +{ + if (m_var == NULL) return 0; + return m_var->GivValInt(); +} + + + + +void CBotStack::AddVar(CBotVar* pVar) +{ + CBotStack* p = this; + + // returns to the father element + while (p != NULL && p->m_bBlock == 0) p = p->m_prev; + + if ( p == NULL ) return; + +/// p->m_bDontDelete = bDontDelete; + + CBotVar** pp = &p->m_listVar; + while ( *pp != NULL ) pp = &(*pp)->m_next; + + *pp = pVar; // added after + +#ifdef _DEBUG + if ( pVar->GivUniqNum() == 0 ) ASM_TRAP(); +#endif +} + +/*void CBotStack::RestoreVar(CBotVar* pVar) +{ + if ( !m_bDontDelete ) __asm int 3; + delete m_listVar; + m_listVar = pVar; // direct replacement +}*/ + +void CBotStack::SetBotCall(CBotProgram* p) +{ + m_prog = p; + m_bFunc = true; +} + +CBotProgram* CBotStack::GivBotCall(bool bFirst) +{ + if ( ! bFirst ) return m_prog; + CBotStack* p = this; + while ( p->m_prev != NULL ) p = p->m_prev; + return p->m_prog; +} + +void* CBotStack::GivPUser() +{ + return m_pUser; +} + + +bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype) +{ + CBotTypResult res; + + // first looks by the identifier + + res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype ); + if (res.GivType() >= 0) return res.GivType(); + + res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token ); + if (res.GivType() >= 0) return res.GivType(); + + // if not found (recompile?) seeks by name + + nIdent = 0; + res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype ); + if (res.GivType() >= 0) return res.GivType(); + + res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token ); + if (res.GivType() >= 0) return res.GivType(); + + SetError(TX_NOCALL, token); + return true; +} + +void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar) +{ + if ( m_next == NULL ) return; + + if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) ) + m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this ); +} + + +bool SaveVar(FILE* pf, CBotVar* pVar) +{ + while ( true ) + { + if ( pVar == NULL ) + { + return WriteWord(pf, 0); // is a terminator + } + + if ( !pVar->Save0State(pf)) return false; // common header + if ( !pVar->Save1State(pf) ) return false; // saves as the child class + + pVar = pVar->GivNext(); + } +} + +void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end) +{ + CBotProgram* prog = m_prog; // Current program + + CBotInstr* funct = NULL; // function found + CBotInstr* instr = NULL; // the highest intruction + + CBotStack* p = this; + + while (p->m_next != NULL) + { + if ( p->m_instr != NULL ) instr = p->m_instr; + if ( p->m_bFunc == 1 ) funct = p->m_instr; + if ( p->m_next->m_prog != prog ) break ; + + if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; + else p = p->m_next; + } + + if ( p->m_instr != NULL ) instr = p->m_instr; + if ( p->m_bFunc == 1 ) funct = p->m_instr; + + if ( funct == NULL ) return; + + CBotToken* t = funct->GivToken(); + FunctionName = t->GivString(); + +// if ( p->m_instr != NULL ) instr = p->m_instr; + + t = instr->GivToken(); + start = t->GivStart(); + end = t->GivEnd(); +} + +CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level) +{ + CBotProgram* prog = m_prog; // current program + FunctionName = NULL; + + // back the stack in the current module + CBotStack* p = this; + + while (p->m_next != NULL) + { + if ( p->m_next->m_prog != prog ) break ; + + if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; + else p = p->m_next; + } + + + // descends upon the elements of block + while ( p != NULL && !p->m_bBlock ) p = p->m_prev; + + while ( p != NULL && level++ < 0 ) + { + p = p->m_prev; + while ( p != NULL && !p->m_bBlock ) p = p->m_prev; + } + + if ( p == NULL ) return NULL; + + // search the name of the current function + CBotStack* pp = p; + while ( pp != NULL ) + { + if ( pp->m_bFunc == 1 ) break; + pp = pp->m_prev; + } + + if ( pp == NULL || pp->m_instr == NULL ) return NULL; + + CBotToken* t = pp->m_instr->GivToken(); + FunctionName = t->GivString(); + + return p->m_listVar; +} + +bool CBotStack::SaveState(FILE* pf) +{ + if ( this == NULL ) // end of the tree? + { + return WriteWord(pf, 0); // is a terminator + } + + if ( m_next2 != NULL ) + { + if (!WriteWord(pf, 2)) return false; // a mark of pursuit + if (!m_next2->SaveState(pf)) return false; + } + else + { + if (!WriteWord(pf, 1)) return false; // a mark of pursuit + } + if (!WriteWord(pf, m_bBlock)) return false; // is a local block + if (!WriteWord(pf, m_state)) return false; // in what state? + if (!WriteWord(pf, 0)) return false; // by compatibility m_bDontDelete + if (!WriteWord(pf, m_step)) return false; // in what state? + + + if (!SaveVar(pf, m_var)) return false; // current result + if (!SaveVar(pf, m_listVar)) return false; // local variables + + return m_next->SaveState(pf); // saves the following +} + + +bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack) +{ + unsigned short w; + + pStack = NULL; + if (!ReadWord(pf, w)) return false; + if ( w == 0 ) return true; + +#if STACKMEM + if ( this == NULL ) pStack = FirstStack(); + else pStack = AddStack(); +#else + pStack = new CBotStack(this); +#endif + + if ( w == 2 ) + { + if (!pStack->RestoreState(pf, pStack->m_next2)) return false; + } + + if (!ReadWord(pf, w)) return false; // is a local block + pStack->m_bBlock = w; + + if (!ReadWord(pf, w)) return false; // in what state ? + pStack->SetState((short)w); // in a good state + + if (!ReadWord(pf, w)) return false; // dont delete? + // uses more + + if (!ReadWord(pf, w)) return false; // step by step + pStack->m_step = w; + + if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // temp variable + if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// local variables + + return pStack->RestoreState(pf, pStack->m_next); +} + + +bool CBotVar::Save0State(FILE* pf) +{ + if (!WriteWord(pf, 100+m_mPrivate))return false; // private variable? + if (!WriteWord(pf, m_bStatic))return false; // static variable? + if (!WriteWord(pf, m_type.GivType()))return false; // saves the type (always non-zero) + if (!WriteWord(pf, m_binit))return false; // variable defined? + return WriteString(pf, m_token->GivString()); // and variable name +} + +bool CBotVarInt::Save0State(FILE* pf) +{ + if ( !m_defnum.IsEmpty() ) + { + if(!WriteWord(pf, 200 )) return false; // special marker + if(!WriteString(pf, m_defnum)) return false; // name of the value + } + + return CBotVar::Save0State(pf); +} + +bool CBotVarInt::Save1State(FILE* pf) +{ + return WriteWord(pf, m_val); // the value of the variable +} + +bool CBotVarBoolean::Save1State(FILE* pf) +{ + return WriteWord(pf, m_val); // the value of the variable +} + +bool CBotVarFloat::Save1State(FILE* pf) +{ + return WriteFloat(pf, m_val); // the value of the variable +} + +bool CBotVarString::Save1State(FILE* pf) +{ + return WriteString(pf, m_val); // the value of the variable +} + + + +bool CBotVarClass::Save1State(FILE* pf) +{ + if ( !WriteType(pf, m_type) ) return false; + if ( !WriteLong(pf, m_ItemIdent) ) return false; + + return SaveVar(pf, m_pVar); // content of the object +} + +bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) +{ + unsigned short w, wi, prv, st; + float ww; + CBotString name, s; + + delete pVar; + + pVar = NULL; + CBotVar* pNew = NULL; + CBotVar* pPrev = NULL; + + while ( true ) // retrieves a list + { + if (!ReadWord(pf, w)) return false; // private or type? + if ( w == 0 ) return true; + + CBotString defnum; + if ( w == 200 ) + { + if (!ReadString(pf, defnum)) return false; // number with identifier + if (!ReadWord(pf, w)) return false; // type + } + + prv = 100; st = 0; + if ( w >= 100 ) + { + prv = w; + if (!ReadWord(pf, st)) return false; // static + if (!ReadWord(pf, w)) return false; // type + } + + if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic + + if (!ReadWord(pf, wi)) return false; // init ? + + if (!ReadString(pf, name)) return false; // variable name + + CBotToken token(name, CBotString()); + + switch (w) + { + case CBotTypInt: + case CBotTypBoolean: + pNew = CBotVar::Create(&token, w); // creates a variable + if (!ReadWord(pf, w)) return false; + pNew->SetValInt((short)w, defnum); + break; + case CBotTypFloat: + pNew = CBotVar::Create(&token, w); // creates a variable + if (!ReadFloat(pf, ww)) return false; + pNew->SetValFloat(ww); + break; + case CBotTypString: + pNew = CBotVar::Create(&token, w); // creates a variable + if (!ReadString(pf, s)) return false; + pNew->SetValString(s); + break; + + // returns an intrinsic object or element of an array + case CBotTypIntrinsic: + case CBotTypArrayBody: + { + CBotTypResult r; + long id; + if (!ReadType(pf, r)) return false; // complete type + if (!ReadLong(pf, id) ) return false; + +// if (!ReadString(pf, s)) return false; + { + CBotVar* p = NULL; + if ( id ) p = CBotVarClass::Find(id) ; + + pNew = new CBotVarClass(&token, r); // directly creates an instance + // attention cptuse = 0 + if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return false; + pNew->SetIdent(id); + + if ( p != NULL ) + { + delete pNew; + pNew = p; // resume known element + } + } + } + break; + + case CBotTypPointer: + case CBotTypNullPointer: + if (!ReadString(pf, s)) return false; + { + pNew = CBotVar::Create(&token, CBotTypResult(w, s));// creates a variable + CBotVarClass* p = NULL; + long id; + ReadLong(pf, id); +// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance) + + // returns a copy of the original instance + CBotVar* pInstance = NULL; + if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; + ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over + +// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // rather this one + + } + break; + + case CBotTypArrayPointer: + { + CBotTypResult r; + if (!ReadType(pf, r)) return false; + + pNew = CBotVar::Create(&token, r); // creates a variable + + // returns a copy of the original instance + CBotVar* pInstance = NULL; + if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; + ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over + } + break; + default: + ASM_TRAP(); + } + + if ( pPrev != NULL ) pPrev->m_next = pNew; + if ( pVar == NULL ) pVar = pNew; + + pNew->m_binit = wi; // pNew->SetInit(wi); + pNew->SetStatic(st); + pNew->SetPrivate(prv-100); + pPrev = pNew; + } + return true; +} + + + + +//////////////////////////////////////////////////////////////////////////// +// management of the compile stack +//////////////////////////////////////////////////////////////////////////// + +CBotProgram* CBotCStack::m_prog = NULL; // init the static variable +int CBotCStack::m_error = 0; +int CBotCStack::m_end = 0; +CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0); +//CBotToken* CBotCStack::m_retClass= NULL; + + +CBotCStack::CBotCStack(CBotCStack* ppapa) +{ + m_next = NULL; + m_prev = ppapa; + + if (ppapa == NULL) + { + m_error = 0; + m_start = 0; + m_end = 0; + m_bBlock = true; + } + else + { + m_start = ppapa->m_start; + m_bBlock = false; + } + + m_listVar = NULL; + m_var = NULL; +} + +// destructor +CBotCStack::~CBotCStack() +{ + if (m_next != NULL) delete m_next; + if (m_prev != NULL) m_prev->m_next = NULL; // removes chain + + delete m_var; + delete m_listVar; +} + +// used only at compile +CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock) +{ + if (m_next != NULL) return m_next; // include on an existing stack + + CBotCStack* p = new CBotCStack(this); + m_next = p; // channel element + p->m_bBlock = bBlock; + + if (pToken != NULL) p->SetStartError(pToken->GivStart()); + + return p; +} + + +CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils) +{ + if ( pfils == this ) return inst; + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + if (m_error) + { + m_start = pfils->m_start; // retrieves the position of the error + m_end = pfils->m_end; + } + + delete pfils; + return inst; +} + +CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils) +{ + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + if (m_error) + { + m_start = pfils->m_start; // retrieves the position of the error + m_end = pfils->m_end; + } + + delete pfils; + return inst; +} + +int CBotCStack::GivError(int& start, int& end) +{ + start = m_start; + end = m_end; + return m_error; +} + +int CBotCStack::GivError() +{ + return m_error; +} + +// type of instruction on the stack +CBotTypResult CBotCStack::GivTypResult(int mode) +{ + if (m_var == NULL) + return CBotTypResult(99); + return m_var->GivTypResult(mode); +} + +// type of instruction on the stack +int CBotCStack::GivType(int mode) +{ + if (m_var == NULL) + return 99; + return m_var->GivType(mode); +} + +// pointer on the stack is in what class? +CBotClass* CBotCStack::GivClass() +{ + if ( m_var == NULL ) + return NULL; + if ( m_var->GivType(1) != CBotTypPointer ) return NULL; + + return m_var->GivClass(); +} + +// type of instruction on the stack +void CBotCStack::SetType(CBotTypResult& type) +{ + if (m_var == NULL) return; + m_var->SetType( type ); +} + +// seeks a variable on the stack +// the token may be a result of TokenTypVar (object of a class) +// or a pointer in the source + +CBotVar* CBotCStack::FindVar(CBotToken* &pToken) +{ + CBotCStack* p = this; + CBotString name = pToken->GivString(); + + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (name == pp->GivName()) + { + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + +CBotVar* CBotCStack::FindVar(CBotToken& Token) +{ + CBotToken* pt = &Token; + return FindVar(pt); +} + +CBotVar* CBotCStack::CopyVar(CBotToken& Token) +{ + CBotVar* pVar = FindVar( Token ); + + if ( pVar == NULL) return NULL; + + CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() ); + pCopy->Copy(pVar); + return pCopy; +} + +bool CBotCStack::IsOk() +{ + return (m_error == 0); +} + + +void CBotCStack::SetStartError( int pos ) +{ + if ( m_error != 0) return; // does not change existing error + m_start = pos; +} + +void CBotCStack::SetError(int n, int pos) +{ + if ( n!= 0 && m_error != 0) return; // does not change existing error + m_error = n; + m_end = pos; +} + +void CBotCStack::SetError(int n, CBotToken* p) +{ + if (m_error) return; // does not change existing error + m_error = n; + m_start = p->GivStart(); + m_end = p->GivEnd(); +} + +void CBotCStack::ResetError(int n, int start, int end) +{ + m_error = n; + m_start = start; + m_end = end; +} + +bool CBotCStack::NextToken(CBotToken* &p) +{ + CBotToken* pp = p; + + p = p->GivNext(); + if (p!=NULL) return true; + + SetError(TX_ENDOF, pp->GivEnd()); + return false; +} + +void CBotCStack::SetBotCall(CBotProgram* p) +{ + m_prog = p; +} + +CBotProgram* CBotCStack::GivBotCall() +{ + return m_prog; +} + +void CBotCStack::SetRetType(CBotTypResult& type) +{ + m_retTyp = type; +} + +CBotTypResult CBotCStack::GivRetType() +{ + return m_retTyp; +} + +void CBotCStack::SetVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + m_var = var; +} + +// puts on the stack a copy of a variable +void CBotCStack::SetCopyVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + + if ( var == NULL ) return; + m_var = CBotVar::Create("", var->GivTypResult(2)); + m_var->Copy( var ); +} + +CBotVar* CBotCStack::GivVar() +{ + return m_var; +} + +void CBotCStack::AddVar(CBotVar* pVar) +{ + CBotCStack* p = this; + + // returns to the father element + while (p != NULL && p->m_bBlock == 0) p = p->m_prev; + + if ( p == NULL ) return; + + CBotVar** pp = &p->m_listVar; + while ( *pp != NULL ) pp = &(*pp)->m_next; + + *pp = pVar; // added after + +#ifdef _DEBUG + if ( pVar->GivUniqNum() == 0 ) ASM_TRAP(); +#endif +} + +// test whether a variable is already defined locally + +bool CBotCStack::CheckVarLocal(CBotToken* &pToken) +{ + CBotCStack* p = this; + CBotString name = pToken->GivString(); + + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (name == pp->GivName()) + return true; + pp = pp->m_next; + } + if ( p->m_bBlock ) return false; + p = p->m_prev; + } + return false; +} + +CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent) +{ + nIdent = 0; + CBotTypResult val(-1); + + val = CBotCall::CompileCall(p, ppVars, this, nIdent); + if (val.GivType() < 0) + { + val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent); + if ( val.GivType() < 0 ) + { + // pVar = NULL; // the error is not on a particular parameter + SetError( -val.GivType(), p ); + val.SetType(-val.GivType()); + return val; + } + } + return val; +} + +// test if a procedure name is already defined somewhere + +bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) +{ + CBotString name = pToken->GivString(); + + if ( CBotCall::CheckCall(name) ) return true; + + CBotFunction* pp = m_prog->GivFunctions(); + while ( pp != NULL ) + { + if ( pToken->GivString() == pp->GivName() ) + { + // are parameters exactly the same? + if ( pp->CheckParam( pParam ) ) + return true; + } + pp = pp->Next(); + } + + pp = CBotFunction::m_listPublic; + while ( pp != NULL ) + { + if ( pToken->GivString() == pp->GivName() ) + { + // are parameters exactly the same? + if ( pp->CheckParam( pParam ) ) + return true; + } + pp = pp->m_nextpublic; + } + + return false; +} + -- cgit v1.2.3-1-g7c22