summaryrefslogtreecommitdiffstats
path: root/src/CBot
diff options
context:
space:
mode:
authorMichał Konopacki <konopacki.m@gmail.com>2012-08-03 00:50:25 +0200
committerMichał Konopacki <konopacki.m@gmail.com>2012-08-03 00:50:25 +0200
commitbf3f9e1860a768b0e96a07fe4f138e332a9918ff (patch)
tree4544a1b54c82d76af0ab1586633005f65371b5a2 /src/CBot
parentd00a283519e2da0d4e0d1fb8a5d1bedd89ead45a (diff)
downloadcolobot-bf3f9e1860a768b0e96a07fe4f138e332a9918ff.tar.gz
colobot-bf3f9e1860a768b0e96a07fe4f138e332a9918ff.tar.bz2
colobot-bf3f9e1860a768b0e96a07fe4f138e332a9918ff.zip
Commentary translation
Diffstat (limited to 'src/CBot')
-rw-r--r--src/CBot/CBotProgram.cpp2230
-rw-r--r--src/CBot/CBotWhile.cpp2860
-rw-r--r--src/CBot/ClassFILE.cpp180
3 files changed, 2637 insertions, 2633 deletions
diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp
index bbdc350..5f1c021 100644
--- a/src/CBot/CBotProgram.cpp
+++ b/src/CBot/CBotProgram.cpp
@@ -1,1117 +1,1113 @@
-// * 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/.//////////////////////////////////////////////////////////////////////
-// gestion de base d'un programme CBot
-
-#include "CBot.h"
-#include <stdio.h>
-
-CBotProgram::CBotProgram()
-{
- m_Prog = NULL;
- m_pRun = NULL;
- m_pClass = NULL;
- m_pStack = NULL;
- m_pInstance = NULL;
-
- m_ErrorCode = 0;
- m_Ident = 0;
- m_bDebugDD = 0;
-}
-
-CBotProgram::CBotProgram(CBotVar* pInstance)
-{
- m_Prog = NULL;
- m_pRun = NULL;
- m_pClass = NULL;
- m_pStack = NULL;
- m_pInstance = pInstance;
-
- m_ErrorCode = 0;
- m_Ident = 0;
- m_bDebugDD = 0;
-}
-
-
-CBotProgram::~CBotProgram()
-{
-// delete m_pClass;
- m_pClass->Purge();
- m_pClass = NULL;
-
- CBotClass::FreeLock(this);
-
- delete m_Prog;
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
-}
-
-
-bool CBotProgram::Compile( const char* program, CBotStringArray& ListFonctions, void* pUser )
-{
- int error = 0;
- Stop();
-
-// delete m_pClass;
- m_pClass->Purge(); // purge les anciennes définitions des classes
- // mais sans détruire l'object
- m_pClass = NULL;
- delete m_Prog; m_Prog= NULL;
-
- ListFonctions.SetSize(0);
- m_ErrorCode = 0;
-
- if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
- pUser = m_pInstance->m_pUserPtr;
-
- // transforme le programme en Tokens
- CBotToken* pBaseToken = CBotToken::CompileTokens(program, error);
- if ( pBaseToken == NULL ) return false;
-
-
- CBotCStack* pStack = new CBotCStack(NULL);
- CBotToken* p = pBaseToken->GivNext(); // saute le 1er token (séparateur)
-
- pStack->SetBotCall(this); // défini les routines utilisables
- CBotCall::SetPUser(pUser);
-
- // fait une première passe rapide juste pour prendre les entêtes de routines et de classes
- while ( pStack->IsOk() && p != NULL && p->GivType() != 0)
- {
- if ( IsOfType(p, ID_SEP) ) continue; // des point-virgules qui trainent
-
- if ( p->GivType() == ID_CLASS ||
- ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
- {
- CBotClass* nxt = CBotClass::Compile1(p, pStack);
- if (m_pClass == NULL ) m_pClass = nxt;
- else m_pClass->AddNext(nxt);
- }
- else
- {
- CBotFunction* next = CBotFunction::Compile1(p, pStack, NULL);
- if (m_Prog == NULL ) m_Prog = next;
- else m_Prog->AddNext(next);
- }
- }
- if ( !pStack->IsOk() )
- {
- m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
- delete m_Prog;
- m_Prog = NULL;
- delete pBaseToken;
- return false;
- }
-
-// CBotFunction* temp = NULL;
- CBotFunction* next = m_Prog; // reprend la liste
-
- p = pBaseToken->GivNext(); // revient au début
-
- while ( pStack->IsOk() && p != NULL && p->GivType() != 0 )
- {
- if ( IsOfType(p, ID_SEP) ) continue; // des point-virgules qui trainent
-
- if ( p->GivType() == ID_CLASS ||
- ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
- {
- m_bCompileClass = true;
- CBotClass::Compile(p, pStack); // complète la définition de la classe
- }
- else
- {
- m_bCompileClass = false;
- CBotFunction::Compile(p, pStack, next);
- if (next->IsExtern()) ListFonctions.Add(next->GivName()/* + next->GivParams()*/);
- next->m_pProg = this; // garde le pointeur au module
- next = next->Next();
- }
- }
-
-// delete m_Prog; // la liste de la 1ère passe
-// m_Prog = temp; // la liste de la seconde passe
-
- if ( !pStack->IsOk() )
- {
- m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
- delete m_Prog;
- m_Prog = NULL;
- }
-
- delete pBaseToken;
- delete pStack;
-
- return (m_Prog != NULL);
-}
-
-
-bool CBotProgram::Start(const char* name)
-{
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
-
- m_pRun = m_Prog;
- while (m_pRun != NULL)
- {
- if ( m_pRun->GivName() == name ) break;
- m_pRun = m_pRun->m_next;
- }
-
- if ( m_pRun == NULL )
- {
- m_ErrorCode = TX_NORUN;
- return false;
- }
-
-#if STACKMEM
- m_pStack = CBotStack::FirstStack();
-#else
- m_pStack = new CBotStack(NULL); // crée une pile d'exécution
-#endif
-
- m_pStack->SetBotCall(this); // bases pour les routines
-
- return true; // on est prêt pour un Run()
-}
-
-bool CBotProgram::GetPosition(const char* name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
-{
- CBotFunction* p = m_Prog;
- while (p != NULL)
- {
- if ( p->GivName() == name ) break;
- p = p->m_next;
- }
-
- if ( p == NULL ) return false;
-
- p->GetPosition(start, stop, modestart, modestop);
- return true;
-}
-
-bool CBotProgram::Run(void* pUser, int timer)
-{
- bool ok;
-
- if (m_pStack == NULL || m_pRun == NULL) goto error;
-
- m_ErrorCode = 0;
- if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
- pUser = m_pInstance->m_pUserPtr;
-
- m_pStack->Reset(pUser); // vide l'éventuelle erreur précédente, et remet le timer
- if ( timer >= 0 ) m_pStack->SetTimer(timer);
-
- m_pStack->SetBotCall(this); // bases pour les routines
-
-#if STACKRUN
- // reprend l'exécution sur le haut de la pile
- ok = m_pStack->Execute();
- if ( ok )
- {
-#ifdef _DEBUG
- CBotVar* ppVar[3];
- ppVar[0] = CBotVar::Create("aa", CBotTypInt);
- ppVar[1] = CBotVar::Create("bb", CBotTypInt);
- ppVar[2] = NULL;
- ok = m_pRun->Execute(ppVar, m_pStack, m_pInstance);
-#else
- // revient sur l'exécution normale
- ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
-#endif
- }
-#else
- ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
-#endif
-
- // terminé sur une erreur ?
- if (!ok && !m_pStack->IsOk())
- {
- m_ErrorCode = m_pStack->GivError(m_ErrorStart, m_ErrorEnd);
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
- return true; // exécution terminée !!
- }
-
- if ( ok ) m_pRun = NULL; // plus de fonction en exécution
- return ok;
-
-error:
- m_ErrorCode = TX_NORUN;
- return true;
-}
-
-void CBotProgram::Stop()
-{
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
- m_pRun = NULL;
-}
-
-
-
-bool CBotProgram::GetRunPos(const char* &FunctionName, int &start, int &end)
-{
- FunctionName = NULL;
- start = end = 0;
- if (m_pStack == NULL) return false;
-
- m_pStack->GetRunPos(FunctionName, start, end);
- return true;
-}
-
-CBotVar* CBotProgram::GivStackVars(const char* &FunctionName, int level)
-{
- FunctionName = NULL;
- if (m_pStack == NULL) return NULL;
-
- return m_pStack->GivStackVars(FunctionName, level);
-}
-
-
-
-
-
-
-
-void CBotProgram::SetTimer(int n)
-{
- CBotStack::SetTimer( n );
-}
-
-int CBotProgram::GivError()
-{
- return m_ErrorCode;
-}
-
-void CBotProgram::SetIdent(long n)
-{
- m_Ident = n;
-}
-
-long CBotProgram::GivIdent()
-{
- return m_Ident;
-}
-
-bool CBotProgram::GetError(int& code, int& start, int& end)
-{
- code = m_ErrorCode;
- start = m_ErrorStart;
- end = m_ErrorEnd;
- return code > 0;
-}
-
-bool CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg)
-{
- code = m_ErrorCode;
- start = m_ErrorStart;
- end = m_ErrorEnd;
- pProg = this;
- return code > 0;
-}
-
-CBotString CBotProgram::GivErrorText(int code)
-{
- CBotString TextError;
-
- TextError.LoadString( code );
- if (TextError.IsEmpty())
- {
- char buf[100];
- sprintf(buf, "Exception numéro %d.", code);
- TextError = buf;
- }
- return TextError;
-}
-
-
-CBotFunction* CBotProgram::GivFunctions()
-{
- return m_Prog;
-}
-
-bool CBotProgram::AddFunction(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- // mémorise les pointeurs aux deux fonctions
- return CBotCall::AddFunction(name, rExec, rCompile);
-}
-
-
-bool WriteWord(FILE* pf, unsigned short w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( unsigned short ), 1, pf );
-
- return (lg == 1);
-}
-
-bool ReadWord(FILE* pf, unsigned short& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( unsigned short ), 1, pf );
-
- return (lg == 1);
-}
-
-bool WriteFloat(FILE* pf, float w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( float ), 1, pf );
-
- return (lg == 1);
-}
-
-bool ReadFloat(FILE* pf, float& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( float ), 1, pf );
-
- return (lg == 1);
-}
-
-bool WriteLong(FILE* pf, long w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( long ), 1, pf );
-
- return (lg == 1);
-}
-
-bool ReadLong(FILE* pf, long& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( long ), 1, pf );
-
- return (lg == 1);
-}
-
-bool WriteString(FILE* pf, CBotString s)
-{
- size_t lg1, lg2;
-
- lg1 = s.GivLength();
- if (!WriteWord(pf, lg1)) return false;
-
- lg2 = fwrite(s, 1, lg1, pf );
- return (lg1 == lg2);
-}
-
-bool ReadString(FILE* pf, CBotString& s)
-{
- unsigned short w;
- char buf[1000];
- size_t lg1, lg2;
-
- if (!ReadWord(pf, w)) return false;
- lg1 = w;
- lg2 = fread(buf, 1, lg1, pf );
- buf[lg2] = 0;
-
- s = buf;
- return (lg1 == lg2);
-}
-
-bool WriteType(FILE* pf, CBotTypResult type)
-{
- int typ = type.GivType();
- if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
- if ( !WriteWord(pf, typ) ) return false;
- if ( typ == CBotTypClass )
- {
- CBotClass* p = type.GivClass();
- if ( !WriteString(pf, p->GivName()) ) return false;
- }
- if ( type.Eq( CBotTypArrayBody ) ||
- type.Eq( CBotTypArrayPointer ) )
- {
- if ( !WriteWord(pf, type.GivLimite()) ) return false;
- if ( !WriteType(pf, type.GivTypElem()) ) return false;
- }
- return true;
-}
-
-bool ReadType(FILE* pf, CBotTypResult& type)
-{
- unsigned short w, ww;
- if ( !ReadWord(pf, w) ) return false;
- type.SetType(w);
-
- if ( type.Eq( CBotTypIntrinsic ) )
- {
- type = CBotTypResult( w, "point" );
- }
-
- if ( type.Eq( CBotTypClass ) )
- {
- CBotString s;
- if ( !ReadString(pf, s) ) return false;
- type = CBotTypResult( w, s );
- }
-
- if ( type.Eq( CBotTypArrayPointer ) ||
- type.Eq( CBotTypArrayBody ) )
- {
- CBotTypResult r;
- if ( !ReadWord(pf, ww) ) return false;
- if ( !ReadType(pf, r) ) return false;
- type = CBotTypResult( w, r );
- type.SetLimite((short)ww);
- }
- return true;
-}
-
-
-bool CBotProgram::DefineNum(const char* name, long val)
-{
- return CBotToken::DefineNum(name, val);
-}
-
-
-bool CBotProgram::SaveState(FILE* pf)
-{
- if (!WriteWord( pf, CBOTVERSION)) return false;
-
-
- if ( m_pStack != NULL )
- {
- if (!WriteWord( pf, 1)) return false;
- if (!WriteString( pf, m_pRun->GivName() )) return false;
- if (!m_pStack->SaveState(pf)) return false;
- }
- else
- {
- if (!WriteWord( pf, 0)) return false;
- }
- return true;
-}
-
-
-bool CBotProgram::RestoreState(FILE* pf)
-{
- unsigned short w;
- CBotString s;
-
- Stop();
-
- if (!ReadWord( pf, w )) return false;
- if ( w != CBOTVERSION ) return false;
-
- if (!ReadWord( pf, w )) return false;
- if ( w == 0 ) return true;
-
- if (!ReadString( pf, s )) return false;
- Start(s); // point de reprise
-
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
-
- // récupère la pile depuis l'enregistrement
- // utilise un pointeur NULL (m_pStack) mais c'est ok comme ça
- if (!m_pStack->RestoreState(pf, m_pStack)) return false;
- m_pStack->SetBotCall(this); // bases pour les routines
-
- // rétabli certains états dans la pile selon la structure
- m_pRun->RestoreState(NULL, m_pStack, m_pInstance);
- return true;
-}
-
-int CBotProgram::GivVersion()
-{
- return CBOTVERSION;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CBotCall* CBotCall::m_ListCalls = NULL;
-
-CBotCall::CBotCall(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- m_name = name;
- m_rExec = rExec;
- m_rComp = rCompile;
- m_next = NULL;
- m_nFuncIdent = CBotVar::NextUniqNum();
-}
-
-CBotCall::~CBotCall()
-{
- if (m_next) delete m_next;
- m_next = NULL;
-}
-
-void CBotCall::Free()
-{
- delete CBotCall::m_ListCalls;
-}
-
-bool CBotCall::AddFunction(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- CBotCall* p = m_ListCalls;
- CBotCall* pp = NULL;
-
- if ( p != NULL ) while ( p->m_next != NULL )
- {
- if ( p->GivName() == name )
- {
- // libère une fonction qu'on redéfini
- if ( pp ) pp->m_next = p->m_next;
- else m_ListCalls = p->m_next;
- pp = p;
- p = p->m_next;
- pp->m_next = NULL; // ne pas détruire la suite de la liste
- delete pp;
- continue;
- }
- pp = p; // pointeur précédent
- p = p->m_next;
- }
-
- pp = new CBotCall(name, rExec, rCompile);
-
- if (p) p->m_next = pp;
- else m_ListCalls = pp;
-
- return true;
-}
-
-
-// transforme le tableau de pointeurs aux variables
-// en une liste de variables chaînées
-CBotVar* MakeListVars(CBotVar** ppVars, bool bSetVal=false)
-{
- int i = 0;
- CBotVar* pVar = NULL;
-
- while( true )
- {
- ppVars[i];
- if ( ppVars[i] == NULL ) break;
-
- CBotVar* pp = CBotVar::Create(ppVars[i]);
- if (bSetVal) pp->Copy(ppVars[i]);
- else
- if ( ppVars[i]->GivType() == CBotTypPointer )
- pp->SetClass( ppVars[i]->GivClass());
-// copier le pointeur selon indirection
- if (pVar == NULL) pVar = pp;
- else pVar->AddNext(pp);
- i++;
- }
- return pVar;
-}
-
-// trouve un appel acceptable selon le nom de la procédure
-// et les paramètres donnés
-
-CBotTypResult CBotCall::CompileCall(CBotToken* &p, CBotVar** ppVar, CBotCStack* pStack, long& nIdent)
-{
- nIdent = 0;
- CBotCall* pt = m_ListCalls;
- CBotString name = p->GivString();
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- CBotVar* pVar = MakeListVars(ppVar);
- CBotVar* pVar2 = pVar;
- CBotTypResult r = pt->m_rComp(pVar2, m_pUser);
- int ret = r.GivType();
-
- // si une classe est retournée, c'est en fait un pointeur
- if ( ret == CBotTypClass ) r.SetType( ret = CBotTypPointer );
-
- if ( ret > 20 )
- {
- if (pVar2) pStack->SetError(ret, p /*pVar2->GivToken()*/ );
- }
- delete pVar;
- nIdent = pt->m_nFuncIdent;
- return r;
- }
- pt = pt->m_next;
- }
- return -1;
-}
-
-void* CBotCall::m_pUser = NULL;
-
-void CBotCall::SetPUser(void* pUser)
-{
- m_pUser = pUser;
-}
-
-bool CBotCall::CheckCall(const char* name)
-{
- CBotCall* p = m_ListCalls;
-
- while ( p != NULL )
- {
- if ( name == p->GivName() ) return true;
- p = p->m_next;
- }
- return false;
-}
-
-
-
-CBotString CBotCall::GivName()
-{
- return m_name;
-}
-
-CBotCall* CBotCall::Next()
-{
- return m_next;
-}
-
-
-int CBotCall::DoCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack, CBotTypResult& rettype)
-{
- CBotCall* pt = m_ListCalls;
-
- if ( nIdent ) while ( pt != NULL )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- goto fund;
- }
- pt = pt->m_next;
- }
-
- pt = m_ListCalls;
-
- if ( token != NULL )
- {
- CBotString name = token->GivString();
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- nIdent = pt->m_nFuncIdent;
- goto fund;
- }
- pt = pt->m_next;
- }
- }
-
- return -1;
-
-fund:
-#if !STACKRUN
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVar, true);
- CBotVar* pVarToDelete = pVar;
-
- // crée une variable pour le résultat
- CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
-
- CBotVar* pRes = pResult;
- int Exception = 0;
- int res = pt->m_rExec(pVar, pResult, Exception, pStack->GivPUser());
-
- if ( pResult != pRes ) delete pRes; // si résultat différent rendu
- delete pVarToDelete;
-
- if (res == false)
- {
- if (Exception!=0)
- {
- pStack->SetError(Exception, token);
- }
- delete pResult;
- return false;
- }
- pStack->SetVar(pResult);
-
- if ( rettype.GivType() > 0 && pResult == NULL )
- {
- pStack->SetError(TX_NORETVAL, token);
- }
- nIdent = pt->m_nFuncIdent;
- return true;
-
-#else
-
- CBotStack* pile = pStack->AddStackEOX(pt);
- if ( pile == EOX ) return true;
-
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVar, true);
- CBotVar* pVarToDelete = pVar;
-
- // crée une variable pour le résultat
- CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
-
- pile->SetVar( pVar );
-
- CBotStack* pile2 = pile->AddStack();
- pile2->SetVar( pResult );
-
- pile->SetError(0, token); // pour la position en cas d'erreur + loin
- return pt->Run( pStack );
-
-#endif
-
-}
-
-#if STACKRUN
-
-bool CBotCall::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack)
-{
- CBotCall* pt = m_ListCalls;
-
- {
- CBotString name = token->GivString();
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- nIdent = pt->m_nFuncIdent;
-
- CBotStack* pile = pStack->RestoreStackEOX(pt);
- if ( pile == NULL ) return true;
-
- CBotStack* pile2 = pile->RestoreStack();
- return true;
- }
- pt = pt->m_next;
- }
- }
-
- return false;
-}
-
-bool CBotCall::Run(CBotStack* pStack)
-{
- CBotStack* pile = pStack->AddStackEOX(this);
- if ( pile == EOX ) return true;
- CBotVar* pVar = pile->GivVar();
-
- CBotStack* pile2 = pile->AddStack();
- CBotVar* pResult = pile2->GivVar();
- CBotVar* pRes = pResult;
-
- int Exception = 0;
- int res = m_rExec(pVar, pResult, Exception, pStack->GivPUser());
-
- if (res == false)
- {
- if (Exception!=0)
- {
- pStack->SetError(Exception);
- }
- if ( pResult != pRes ) delete pResult; // si résultat différent rendu
- return false;
- }
-
- if ( pResult != NULL ) pStack->SetCopyVar( pResult );
- if ( pResult != pRes ) delete pResult; // si résultat différent rendu
-
- return true;
-}
-
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////
-
-CBotCallMethode::CBotCallMethode(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
-{
- m_name = name;
- m_rExec = rExec;
- m_rComp = rCompile;
- m_next = NULL;
- m_nFuncIdent = CBotVar::NextUniqNum();
-}
-
-CBotCallMethode::~CBotCallMethode()
-{
- delete m_next;
- m_next = NULL;
-}
-
-// trouve un appel acceptable selon le nom de la procédure
-// et les paramètres donnés
-
-CBotTypResult CBotCallMethode::CompileCall(const char* name, CBotVar* pThis,
- CBotVar** ppVar, CBotCStack* pStack,
- long& nIdent)
-{
- CBotCallMethode* pt = this;
- nIdent = 0;
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- CBotVar* pVar = MakeListVars(ppVar, true);
- CBotVar* pVar2 = pVar;
- CBotTypResult r = pt->m_rComp(pThis, pVar2);
- int ret = r.GivType();
- if ( ret > 20 )
- {
- if (pVar2) pStack->SetError(ret, pVar2->GivToken());
- }
- delete pVar;
- nIdent = pt->m_nFuncIdent;
- return r;
- }
- pt = pt->m_next;
- }
- return CBotTypResult(-1);
-}
-
-
-CBotString CBotCallMethode::GivName()
-{
- return m_name;
-}
-
-CBotCallMethode* CBotCallMethode::Next()
-{
- return m_next;
-}
-
-void CBotCallMethode::AddNext(CBotCallMethode* pt)
-{
- CBotCallMethode* p = this;
- while ( p->m_next != NULL ) p = p->m_next;
-
- p->m_next = pt;
-}
-
-
-int CBotCallMethode::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pToken)
-{
- CBotCallMethode* pt = this;
-
- // recherche selon l'identificateur
-
- if ( nIdent ) while ( pt != NULL )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVars, true);
- CBotVar* pVarToDelete = pVar;
-
- // puis appelle la routine externe au module
-
- int Exception = 0;
- int res = pt->m_rExec(pThis, pVar, pResult, Exception);
- pStack->SetVar(pResult);
-
- if (res == false)
- {
- if (Exception!=0)
- {
-// pStack->SetError(Exception, pVar->GivToken());
- pStack->SetError(Exception, pToken);
- }
- delete pVarToDelete;
- return false;
- }
- delete pVarToDelete;
- return true;
- }
- pt = pt->m_next;
- }
-
- // recherche selon le nom
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVars, true);
- CBotVar* pVarToDelete = pVar;
-
- int Exception = 0;
- int res = pt->m_rExec(pThis, pVar, pResult, Exception);
- pStack->SetVar(pResult);
-
- if (res == false)
- {
- if (Exception!=0)
- {
-// pStack->SetError(Exception, pVar->GivToken());
- pStack->SetError(Exception, pToken);
- }
- delete pVarToDelete;
- return false;
- }
- delete pVarToDelete;
- nIdent = pt->m_nFuncIdent;
- return true;
- }
- pt = pt->m_next;
- }
-
- return -1;
-}
-
-bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- if ( pVar == NULL ) return TX_LOWPARAM;
-
- int i = 0;
- pVar = pVar->GivItemList();
-
- while ( pVar != NULL )
- {
- i++;
- pVar = pVar->GivNext();
- }
-
- pResult->SetValInt(i);
- return true;
-}
-
-CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
-{
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
- if ( pVar->GivType() != CBotTypArrayPointer )
- return CBotTypResult( TX_BADPARAM );
- return CBotTypResult( CBotTypInt );
-}
-
-
-CBotString CBotProgram::m_DebugVarStr = "";
-
-bool rCBotDebug( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- pResult->SetValString( CBotProgram::m_DebugVarStr );
-
- return true;
-}
-
-CBotTypResult cCBotDebug( CBotVar* &pVar, void* pUser )
-{
- // pas de paramètre
- if ( pVar != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // la fonction retourne un résultat "string"
- return CBotTypResult( CBotTypString );
-}
-
-
-#include "StringFunctions.cpp"
-
-void CBotProgram::Init()
-{
- CBotToken::DefineNum( "CBotErrOpenPar", 5000) ; // manque la parenthèse ouvrante
- CBotToken::DefineNum( "CBotErrClosePar", 5001) ; // manque la parenthèse fermante
- CBotToken::DefineNum( "CBotErrNotBoolean", 5002) ; // l'expression doit être un boolean
- CBotToken::DefineNum( "CBotErrUndefVar", 5003) ; // variable non déclarée
- CBotToken::DefineNum( "CBotErrBadLeft", 5004) ; // assignation impossible ( 5 = ... )
- CBotToken::DefineNum( "CBotErrNoTerminator", 5005) ;// point-virgule attendu
- CBotToken::DefineNum( "CBotErrCaseOut", 5006) ; // case en dehors d'un switch
- CBotToken::DefineNum( "CBotErrCloseBlock", 5008) ; // manque " } "
- CBotToken::DefineNum( "CBotErrElseWhitoutIf", 5009) ;// else sans if correspondant
- CBotToken::DefineNum( "CBotErrOpenBlock", 5010) ; // manque " { "
- CBotToken::DefineNum( "CBotErrBadType1", 5011) ; // mauvais type pour l'assignation
- CBotToken::DefineNum( "CBotErrRedefVar", 5012) ; // redéfinition de la variable
- CBotToken::DefineNum( "CBotErrBadType2", 5013) ; // 2 opérandes de type incompatibles
- CBotToken::DefineNum( "CBotErrUndefCall", 5014) ; // routine inconnue
- CBotToken::DefineNum( "CBotErrNoDoubleDots", 5015) ;// " : " attendu
- CBotToken::DefineNum( "CBotErrBreakOutside", 5017) ;// break en dehors d'une boucle
- CBotToken::DefineNum( "CBotErrUndefLabel", 5019) ; // label inconnu
- CBotToken::DefineNum( "CBotErrLabel", 5018) ; // label ne peut se mettre ici
- CBotToken::DefineNum( "CBotErrNoCase", 5020) ; // manque " case "
- CBotToken::DefineNum( "CBotErrBadNum", 5021) ; // nombre attendu
- CBotToken::DefineNum( "CBotErrVoid", 5022) ; // " void " pas possible ici
- CBotToken::DefineNum( "CBotErrNoType", 5023) ; // déclaration de type attendue
- CBotToken::DefineNum( "CBotErrNoVar", 5024) ; // nom de variable attendu
- CBotToken::DefineNum( "CBotErrNoFunc", 5025) ; // nom de fonction attendu
- CBotToken::DefineNum( "CBotErrOverParam", 5026) ; // trop de paramètres
- CBotToken::DefineNum( "CBotErrRedefFunc", 5027) ; // cette fonction existe déjà
- CBotToken::DefineNum( "CBotErrLowParam", 5028) ; // pas assez de paramètres
- CBotToken::DefineNum( "CBotErrBadParam", 5029) ; // mauvais types de paramètres
- CBotToken::DefineNum( "CBotErrNbParam", 5030) ; // mauvais nombre de paramètres
- CBotToken::DefineNum( "CBotErrUndefItem", 5031) ; // élément n'existe pas dans la classe
- CBotToken::DefineNum( "CBotErrUndefClass", 5032) ; // variable n'est pas une classe
- CBotToken::DefineNum( "CBotErrNoConstruct", 5033) ; // pas de constructeur approprié
- CBotToken::DefineNum( "CBotErrRedefClass", 5034) ; // classe existe déjà
- CBotToken::DefineNum( "CBotErrCloseIndex", 5035) ; // " ] " attendu
- CBotToken::DefineNum( "CBotErrReserved", 5036) ; // mot réservé (par un DefineNum)
-
-// voici la liste des erreurs pouvant être retournées par le module
-// pour l'exécution
-
- CBotToken::DefineNum( "CBotErrZeroDiv", 6000) ; // division par zéro
- CBotToken::DefineNum( "CBotErrNotInit", 6001) ; // variable non initialisée
- CBotToken::DefineNum( "CBotErrBadThrow", 6002) ; // throw d'une valeur négative
- CBotToken::DefineNum( "CBotErrNoRetVal", 6003) ; // fonction n'a pas retourné de résultat
- CBotToken::DefineNum( "CBotErrNoRun", 6004) ; // Run() sans fonction active
- CBotToken::DefineNum( "CBotErrUndefFunc", 6005) ; // appel d'une fonction qui n'existe plus
-
- CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf );
-
- InitStringFunctions();
-
- // une fonction juste pour les debug divers
- CBotProgram::AddFunction("CBOTDEBUGDD", rCBotDebug, cCBotDebug);
- //TODO implement this deletion
- // DeleteFile("CbotDebug.txt");
-
-}
-
-void CBotProgram::Free()
-{
- CBotToken::Free() ;
- CBotCall ::Free() ;
- CBotClass::Free() ;
-}
-
+// * 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/.
+
+//////////////////////////////////////////////////////////////////////
+// database management of CBoT program
+
+#include "CBot.h"
+#include <stdio.h>
+
+CBotProgram::CBotProgram()
+{
+ m_Prog = NULL;
+ m_pRun = NULL;
+ m_pClass = NULL;
+ m_pStack = NULL;
+ m_pInstance = NULL;
+
+ m_ErrorCode = 0;
+ m_Ident = 0;
+ m_bDebugDD = 0;
+}
+
+CBotProgram::CBotProgram(CBotVar* pInstance)
+{
+ m_Prog = NULL;
+ m_pRun = NULL;
+ m_pClass = NULL;
+ m_pStack = NULL;
+ m_pInstance = pInstance;
+
+ m_ErrorCode = 0;
+ m_Ident = 0;
+ m_bDebugDD = 0;
+}
+
+
+CBotProgram::~CBotProgram()
+{
+// delete m_pClass;
+ m_pClass->Purge();
+ m_pClass = NULL;
+
+ CBotClass::FreeLock(this);
+
+ delete m_Prog;
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+}
+
+
+bool CBotProgram::Compile( const char* program, CBotStringArray& ListFonctions, void* pUser )
+{
+ int error = 0;
+ Stop();
+
+// delete m_pClass;
+ m_pClass->Purge(); // purge the old definitions of classes
+ // but without destroying the object
+ m_pClass = NULL;
+ delete m_Prog; m_Prog= NULL;
+
+ ListFonctions.SetSize(0);
+ m_ErrorCode = 0;
+
+ if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
+ pUser = m_pInstance->m_pUserPtr;
+
+ // transforms the program in Tokens
+ CBotToken* pBaseToken = CBotToken::CompileTokens(program, error);
+ if ( pBaseToken == NULL ) return false;
+
+
+ CBotCStack* pStack = new CBotCStack(NULL);
+ CBotToken* p = pBaseToken->GivNext(); // skips the first token (separator)
+
+ pStack->SetBotCall(this); // defined used routines
+ CBotCall::SetPUser(pUser);
+
+ // first made a quick pass just to take the headers of routines and classes
+ while ( pStack->IsOk() && p != NULL && p->GivType() != 0)
+ {
+ if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking
+
+ if ( p->GivType() == ID_CLASS ||
+ ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
+ {
+ CBotClass* nxt = CBotClass::Compile1(p, pStack);
+ if (m_pClass == NULL ) m_pClass = nxt;
+ else m_pClass->AddNext(nxt);
+ }
+ else
+ {
+ CBotFunction* next = CBotFunction::Compile1(p, pStack, NULL);
+ if (m_Prog == NULL ) m_Prog = next;
+ else m_Prog->AddNext(next);
+ }
+ }
+ if ( !pStack->IsOk() )
+ {
+ m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
+ delete m_Prog;
+ m_Prog = NULL;
+ delete pBaseToken;
+ return false;
+ }
+
+// CBotFunction* temp = NULL;
+ CBotFunction* next = m_Prog; // rewind the list
+
+ p = pBaseToken->GivNext(); // returns to the beginning
+
+ while ( pStack->IsOk() && p != NULL && p->GivType() != 0 )
+ {
+ if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking
+
+ if ( p->GivType() == ID_CLASS ||
+ ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
+ {
+ m_bCompileClass = true;
+ CBotClass::Compile(p, pStack); // completes the definition of the class
+ }
+ else
+ {
+ m_bCompileClass = false;
+ CBotFunction::Compile(p, pStack, next);
+ if (next->IsExtern()) ListFonctions.Add(next->GivName()/* + next->GivParams()*/);
+ next->m_pProg = this; // keeps pointers to the module
+ next = next->Next();
+ }
+ }
+
+// delete m_Prog; // the list of first pass
+// m_Prog = temp; // list of the second pass
+
+ if ( !pStack->IsOk() )
+ {
+ m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
+ delete m_Prog;
+ m_Prog = NULL;
+ }
+
+ delete pBaseToken;
+ delete pStack;
+
+ return (m_Prog != NULL);
+}
+
+
+bool CBotProgram::Start(const char* name)
+{
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+
+ m_pRun = m_Prog;
+ while (m_pRun != NULL)
+ {
+ if ( m_pRun->GivName() == name ) break;
+ m_pRun = m_pRun->m_next;
+ }
+
+ if ( m_pRun == NULL )
+ {
+ m_ErrorCode = TX_NORUN;
+ return false;
+ }
+
+#if STACKMEM
+ m_pStack = CBotStack::FirstStack();
+#else
+ m_pStack = new CBotStack(NULL); // creates an execution stack
+#endif
+
+ m_pStack->SetBotCall(this); // bases for routines
+
+ return true; // we are ready for Run ()
+}
+
+bool CBotProgram::GetPosition(const char* name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
+{
+ CBotFunction* p = m_Prog;
+ while (p != NULL)
+ {
+ if ( p->GivName() == name ) break;
+ p = p->m_next;
+ }
+
+ if ( p == NULL ) return false;
+
+ p->GetPosition(start, stop, modestart, modestop);
+ return true;
+}
+
+bool CBotProgram::Run(void* pUser, int timer)
+{
+ bool ok;
+
+ if (m_pStack == NULL || m_pRun == NULL) goto error;
+
+ m_ErrorCode = 0;
+ if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
+ pUser = m_pInstance->m_pUserPtr;
+
+ m_pStack->Reset(pUser); // empty the possible previous error, and resets the timer
+ if ( timer >= 0 ) m_pStack->SetTimer(timer);
+
+ m_pStack->SetBotCall(this); // bases for routines
+
+#if STACKRUN
+ // resumes execution on the top of the stack
+ ok = m_pStack->Execute();
+ if ( ok )
+ {
+#ifdef _DEBUG
+ CBotVar* ppVar[3];
+ ppVar[0] = CBotVar::Create("aa", CBotTypInt);
+ ppVar[1] = CBotVar::Create("bb", CBotTypInt);
+ ppVar[2] = NULL;
+ ok = m_pRun->Execute(ppVar, m_pStack, m_pInstance);
+#else
+ // returns to normal execution
+ ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
+#endif
+ }
+#else
+ ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
+#endif
+
+ // completed on a mistake?
+ if (!ok && !m_pStack->IsOk())
+ {
+ m_ErrorCode = m_pStack->GivError(m_ErrorStart, m_ErrorEnd);
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+ return true; // execution is finished!
+ }
+
+ if ( ok ) m_pRun = NULL; // more function in execution
+ return ok;
+
+error:
+ m_ErrorCode = TX_NORUN;
+ return true;
+}
+
+void CBotProgram::Stop()
+{
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+ m_pRun = NULL;
+}
+
+
+
+bool CBotProgram::GetRunPos(const char* &FunctionName, int &start, int &end)
+{
+ FunctionName = NULL;
+ start = end = 0;
+ if (m_pStack == NULL) return false;
+
+ m_pStack->GetRunPos(FunctionName, start, end);
+ return true;
+}
+
+CBotVar* CBotProgram::GivStackVars(const char* &FunctionName, int level)
+{
+ FunctionName = NULL;
+ if (m_pStack == NULL) return NULL;
+
+ return m_pStack->GivStackVars(FunctionName, level);
+}
+
+void CBotProgram::SetTimer(int n)
+{
+ CBotStack::SetTimer( n );
+}
+
+int CBotProgram::GivError()
+{
+ return m_ErrorCode;
+}
+
+void CBotProgram::SetIdent(long n)
+{
+ m_Ident = n;
+}
+
+long CBotProgram::GivIdent()
+{
+ return m_Ident;
+}
+
+bool CBotProgram::GetError(int& code, int& start, int& end)
+{
+ code = m_ErrorCode;
+ start = m_ErrorStart;
+ end = m_ErrorEnd;
+ return code > 0;
+}
+
+bool CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg)
+{
+ code = m_ErrorCode;
+ start = m_ErrorStart;
+ end = m_ErrorEnd;
+ pProg = this;
+ return code > 0;
+}
+
+CBotString CBotProgram::GivErrorText(int code)
+{
+ CBotString TextError;
+
+ TextError.LoadString( code );
+ if (TextError.IsEmpty())
+ {
+ char buf[100];
+ sprintf(buf, "Exception numéro %d.", code);
+ TextError = buf;
+ }
+ return TextError;
+}
+
+
+CBotFunction* CBotProgram::GivFunctions()
+{
+ return m_Prog;
+}
+
+bool CBotProgram::AddFunction(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
+{
+ // stores pointers to the two functions
+ return CBotCall::AddFunction(name, rExec, rCompile);
+}
+
+
+bool WriteWord(FILE* pf, unsigned short w)
+{
+ size_t lg;
+
+ lg = fwrite(&w, sizeof( unsigned short ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool ReadWord(FILE* pf, unsigned short& w)
+{
+ size_t lg;
+
+ lg = fread(&w, sizeof( unsigned short ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool WriteFloat(FILE* pf, float w)
+{
+ size_t lg;
+
+ lg = fwrite(&w, sizeof( float ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool ReadFloat(FILE* pf, float& w)
+{
+ size_t lg;
+
+ lg = fread(&w, sizeof( float ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool WriteLong(FILE* pf, long w)
+{
+ size_t lg;
+
+ lg = fwrite(&w, sizeof( long ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool ReadLong(FILE* pf, long& w)
+{
+ size_t lg;
+
+ lg = fread(&w, sizeof( long ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool WriteString(FILE* pf, CBotString s)
+{
+ size_t lg1, lg2;
+
+ lg1 = s.GivLength();
+ if (!WriteWord(pf, lg1)) return false;
+
+ lg2 = fwrite(s, 1, lg1, pf );
+ return (lg1 == lg2);
+}
+
+bool ReadString(FILE* pf, CBotString& s)
+{
+ unsigned short w;
+ char buf[1000];
+ size_t lg1, lg2;
+
+ if (!ReadWord(pf, w)) return false;
+ lg1 = w;
+ lg2 = fread(buf, 1, lg1, pf );
+ buf[lg2] = 0;
+
+ s = buf;
+ return (lg1 == lg2);
+}
+
+bool WriteType(FILE* pf, CBotTypResult type)
+{
+ int typ = type.GivType();
+ if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
+ if ( !WriteWord(pf, typ) ) return false;
+ if ( typ == CBotTypClass )
+ {
+ CBotClass* p = type.GivClass();
+ if ( !WriteString(pf, p->GivName()) ) return false;
+ }
+ if ( type.Eq( CBotTypArrayBody ) ||
+ type.Eq( CBotTypArrayPointer ) )
+ {
+ if ( !WriteWord(pf, type.GivLimite()) ) return false;
+ if ( !WriteType(pf, type.GivTypElem()) ) return false;
+ }
+ return true;
+}
+
+bool ReadType(FILE* pf, CBotTypResult& type)
+{
+ unsigned short w, ww;
+ if ( !ReadWord(pf, w) ) return false;
+ type.SetType(w);
+
+ if ( type.Eq( CBotTypIntrinsic ) )
+ {
+ type = CBotTypResult( w, "point" );
+ }
+
+ if ( type.Eq( CBotTypClass ) )
+ {
+ CBotString s;
+ if ( !ReadString(pf, s) ) return false;
+ type = CBotTypResult( w, s );
+ }
+
+ if ( type.Eq( CBotTypArrayPointer ) ||
+ type.Eq( CBotTypArrayBody ) )
+ {
+ CBotTypResult r;
+ if ( !ReadWord(pf, ww) ) return false;
+ if ( !ReadType(pf, r) ) return false;
+ type = CBotTypResult( w, r );
+ type.SetLimite((short)ww);
+ }
+ return true;
+}
+
+
+bool CBotProgram::DefineNum(const char* name, long val)
+{
+ return CBotToken::DefineNum(name, val);
+}
+
+
+bool CBotProgram::SaveState(FILE* pf)
+{
+ if (!WriteWord( pf, CBOTVERSION)) return false;
+
+
+ if ( m_pStack != NULL )
+ {
+ if (!WriteWord( pf, 1)) return false;
+ if (!WriteString( pf, m_pRun->GivName() )) return false;
+ if (!m_pStack->SaveState(pf)) return false;
+ }
+ else
+ {
+ if (!WriteWord( pf, 0)) return false;
+ }
+ return true;
+}
+
+
+bool CBotProgram::RestoreState(FILE* pf)
+{
+ unsigned short w;
+ CBotString s;
+
+ Stop();
+
+ if (!ReadWord( pf, w )) return false;
+ if ( w != CBOTVERSION ) return false;
+
+ if (!ReadWord( pf, w )) return false;
+ if ( w == 0 ) return true;
+
+ if (!ReadString( pf, s )) return false;
+ Start(s); // point de reprise
+
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+
+ // retrieves the stack from the memory
+ // uses a NULL pointer (m_pStack) but it's ok like that
+ if (!m_pStack->RestoreState(pf, m_pStack)) return false;
+ m_pStack->SetBotCall(this); // bases for routines
+
+ // restored some states in the stack according to the structure
+ m_pRun->RestoreState(NULL, m_pStack, m_pInstance);
+ return true;
+}
+
+int CBotProgram::GivVersion()
+{
+ return CBOTVERSION;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+
+CBotCall* CBotCall::m_ListCalls = NULL;
+
+CBotCall::CBotCall(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
+{
+ m_name = name;
+ m_rExec = rExec;
+ m_rComp = rCompile;
+ m_next = NULL;
+ m_nFuncIdent = CBotVar::NextUniqNum();
+}
+
+CBotCall::~CBotCall()
+{
+ if (m_next) delete m_next;
+ m_next = NULL;
+}
+
+void CBotCall::Free()
+{
+ delete CBotCall::m_ListCalls;
+}
+
+bool CBotCall::AddFunction(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
+{
+ CBotCall* p = m_ListCalls;
+ CBotCall* pp = NULL;
+
+ if ( p != NULL ) while ( p->m_next != NULL )
+ {
+ if ( p->GivName() == name )
+ {
+ // frees redefined function
+ if ( pp ) pp->m_next = p->m_next;
+ else m_ListCalls = p->m_next;
+ pp = p;
+ p = p->m_next;
+ pp->m_next = NULL; // not to destroy the following list
+ delete pp;
+ continue;
+ }
+ pp = p; // previous pointer
+ p = p->m_next;
+ }
+
+ pp = new CBotCall(name, rExec, rCompile);
+
+ if (p) p->m_next = pp;
+ else m_ListCalls = pp;
+
+ return true;
+}
+
+
+// transforms the array of pointers to variables
+// in a chained list of variables
+CBotVar* MakeListVars(CBotVar** ppVars, bool bSetVal=false)
+{
+ int i = 0;
+ CBotVar* pVar = NULL;
+
+ while( true )
+ {
+ ppVars[i];
+ if ( ppVars[i] == NULL ) break;
+
+ CBotVar* pp = CBotVar::Create(ppVars[i]);
+ if (bSetVal) pp->Copy(ppVars[i]);
+ else
+ if ( ppVars[i]->GivType() == CBotTypPointer )
+ pp->SetClass( ppVars[i]->GivClass());
+// copy the pointer according to indirections
+ if (pVar == NULL) pVar = pp;
+ else pVar->AddNext(pp);
+ i++;
+ }
+ return pVar;
+}
+
+// is acceptable by a call procedure name
+// and given parameters
+
+CBotTypResult CBotCall::CompileCall(CBotToken* &p, CBotVar** ppVar, CBotCStack* pStack, long& nIdent)
+{
+ nIdent = 0;
+ CBotCall* pt = m_ListCalls;
+ CBotString name = p->GivString();
+
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ CBotVar* pVar = MakeListVars(ppVar);
+ CBotVar* pVar2 = pVar;
+ CBotTypResult r = pt->m_rComp(pVar2, m_pUser);
+ int ret = r.GivType();
+
+ // if a class is returned, it is actually a pointer
+ if ( ret == CBotTypClass ) r.SetType( ret = CBotTypPointer );
+
+ if ( ret > 20 )
+ {
+ if (pVar2) pStack->SetError(ret, p /*pVar2->GivToken()*/ );
+ }
+ delete pVar;
+ nIdent = pt->m_nFuncIdent;
+ return r;
+ }
+ pt = pt->m_next;
+ }
+ return -1;
+}
+
+void* CBotCall::m_pUser = NULL;
+
+void CBotCall::SetPUser(void* pUser)
+{
+ m_pUser = pUser;
+}
+
+bool CBotCall::CheckCall(const char* name)
+{
+ CBotCall* p = m_ListCalls;
+
+ while ( p != NULL )
+ {
+ if ( name == p->GivName() ) return true;
+ p = p->m_next;
+ }
+ return false;
+}
+
+
+
+CBotString CBotCall::GivName()
+{
+ return m_name;
+}
+
+CBotCall* CBotCall::Next()
+{
+ return m_next;
+}
+
+
+int CBotCall::DoCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack, CBotTypResult& rettype)
+{
+ CBotCall* pt = m_ListCalls;
+
+ if ( nIdent ) while ( pt != NULL )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ goto fund;
+ }
+ pt = pt->m_next;
+ }
+
+ pt = m_ListCalls;
+
+ if ( token != NULL )
+ {
+ CBotString name = token->GivString();
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ nIdent = pt->m_nFuncIdent;
+ goto fund;
+ }
+ pt = pt->m_next;
+ }
+ }
+
+ return -1;
+
+fund:
+#if !STACKRUN
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVar, true);
+ CBotVar* pVarToDelete = pVar;
+
+ // creates a variable to the result
+ CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
+
+ CBotVar* pRes = pResult;
+ int Exception = 0;
+ int res = pt->m_rExec(pVar, pResult, Exception, pStack->GivPUser());
+
+ if ( pResult != pRes ) delete pRes; // different result if made
+ delete pVarToDelete;
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+ pStack->SetError(Exception, token);
+ }
+ delete pResult;
+ return false;
+ }
+ pStack->SetVar(pResult);
+
+ if ( rettype.GivType() > 0 && pResult == NULL )
+ {
+ pStack->SetError(TX_NORETVAL, token);
+ }
+ nIdent = pt->m_nFuncIdent;
+ return true;
+
+#else
+
+ CBotStack* pile = pStack->AddStackEOX(pt);
+ if ( pile == EOX ) return true;
+
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVar, true);
+ CBotVar* pVarToDelete = pVar;
+
+ // creates a variable to the result
+ CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
+
+ pile->SetVar( pVar );
+
+ CBotStack* pile2 = pile->AddStack();
+ pile2->SetVar( pResult );
+
+ pile->SetError(0, token); // for the position on error + away
+ return pt->Run( pStack );
+
+#endif
+
+}
+
+#if STACKRUN
+
+bool CBotCall::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack)
+{
+ CBotCall* pt = m_ListCalls;
+
+ {
+ CBotString name = token->GivString();
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ nIdent = pt->m_nFuncIdent;
+
+ CBotStack* pile = pStack->RestoreStackEOX(pt);
+ if ( pile == NULL ) return true;
+
+ CBotStack* pile2 = pile->RestoreStack();
+ return true;
+ }
+ pt = pt->m_next;
+ }
+ }
+
+ return false;
+}
+
+bool CBotCall::Run(CBotStack* pStack)
+{
+ CBotStack* pile = pStack->AddStackEOX(this);
+ if ( pile == EOX ) return true;
+ CBotVar* pVar = pile->GivVar();
+
+ CBotStack* pile2 = pile->AddStack();
+ CBotVar* pResult = pile2->GivVar();
+ CBotVar* pRes = pResult;
+
+ int Exception = 0;
+ int res = m_rExec(pVar, pResult, Exception, pStack->GivPUser());
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+ pStack->SetError(Exception);
+ }
+ if ( pResult != pRes ) delete pResult; // different result if made
+ return false;
+ }
+
+ if ( pResult != NULL ) pStack->SetCopyVar( pResult );
+ if ( pResult != pRes ) delete pResult; // different result if made
+
+ return true;
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+CBotCallMethode::CBotCallMethode(const char* name,
+ bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
+ CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
+{
+ m_name = name;
+ m_rExec = rExec;
+ m_rComp = rCompile;
+ m_next = NULL;
+ m_nFuncIdent = CBotVar::NextUniqNum();
+}
+
+CBotCallMethode::~CBotCallMethode()
+{
+ delete m_next;
+ m_next = NULL;
+}
+
+// is acceptable by a call procedure name
+// and given parameters
+
+CBotTypResult CBotCallMethode::CompileCall(const char* name, CBotVar* pThis,
+ CBotVar** ppVar, CBotCStack* pStack,
+ long& nIdent)
+{
+ CBotCallMethode* pt = this;
+ nIdent = 0;
+
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ CBotVar* pVar = MakeListVars(ppVar, true);
+ CBotVar* pVar2 = pVar;
+ CBotTypResult r = pt->m_rComp(pThis, pVar2);
+ int ret = r.GivType();
+ if ( ret > 20 )
+ {
+ if (pVar2) pStack->SetError(ret, pVar2->GivToken());
+ }
+ delete pVar;
+ nIdent = pt->m_nFuncIdent;
+ return r;
+ }
+ pt = pt->m_next;
+ }
+ return CBotTypResult(-1);
+}
+
+
+CBotString CBotCallMethode::GivName()
+{
+ return m_name;
+}
+
+CBotCallMethode* CBotCallMethode::Next()
+{
+ return m_next;
+}
+
+void CBotCallMethode::AddNext(CBotCallMethode* pt)
+{
+ CBotCallMethode* p = this;
+ while ( p->m_next != NULL ) p = p->m_next;
+
+ p->m_next = pt;
+}
+
+
+int CBotCallMethode::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pToken)
+{
+ CBotCallMethode* pt = this;
+
+ // search by the identifier
+
+ if ( nIdent ) while ( pt != NULL )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVars, true);
+ CBotVar* pVarToDelete = pVar;
+
+ // then calls the routine external to the module
+
+ int Exception = 0;
+ int res = pt->m_rExec(pThis, pVar, pResult, Exception);
+ pStack->SetVar(pResult);
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+// pStack->SetError(Exception, pVar->GivToken());
+ pStack->SetError(Exception, pToken);
+ }
+ delete pVarToDelete;
+ return false;
+ }
+ delete pVarToDelete;
+ return true;
+ }
+ pt = pt->m_next;
+ }
+
+ // search by name
+
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVars, true);
+ CBotVar* pVarToDelete = pVar;
+
+ int Exception = 0;
+ int res = pt->m_rExec(pThis, pVar, pResult, Exception);
+ pStack->SetVar(pResult);
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+// pStack->SetError(Exception, pVar->GivToken());
+ pStack->SetError(Exception, pToken);
+ }
+ delete pVarToDelete;
+ return false;
+ }
+ delete pVarToDelete;
+ nIdent = pt->m_nFuncIdent;
+ return true;
+ }
+ pt = pt->m_next;
+ }
+
+ return -1;
+}
+
+bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ if ( pVar == NULL ) return TX_LOWPARAM;
+
+ int i = 0;
+ pVar = pVar->GivItemList();
+
+ while ( pVar != NULL )
+ {
+ i++;
+ pVar = pVar->GivNext();
+ }
+
+ pResult->SetValInt(i);
+ return true;
+}
+
+CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
+{
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+ if ( pVar->GivType() != CBotTypArrayPointer )
+ return CBotTypResult( TX_BADPARAM );
+ return CBotTypResult( CBotTypInt );
+}
+
+
+CBotString CBotProgram::m_DebugVarStr = "";
+
+bool rCBotDebug( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ pResult->SetValString( CBotProgram::m_DebugVarStr );
+
+ return true;
+}
+
+CBotTypResult cCBotDebug( CBotVar* &pVar, void* pUser )
+{
+ // no parameter
+ if ( pVar != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // function returns a result "string"
+ return CBotTypResult( CBotTypString );
+}
+
+
+#include "StringFunctions.cpp"
+
+void CBotProgram::Init()
+{
+ CBotToken::DefineNum( "CBotErrOpenPar", 5000) ; // missing the opening parenthesis
+ CBotToken::DefineNum( "CBotErrClosePar", 5001) ; // missing the closing parenthesis
+ CBotToken::DefineNum( "CBotErrNotBoolean", 5002) ; // expression must be a boolean
+ CBotToken::DefineNum( "CBotErrUndefVar", 5003) ; // undeclared variable
+ CBotToken::DefineNum( "CBotErrBadLeft", 5004) ; // impossible assignment (5 = ...)
+ CBotToken::DefineNum( "CBotErrNoTerminator", 5005) ;// semicolon expected
+ CBotToken::DefineNum( "CBotErrCaseOut", 5006) ; // case outside a switch
+ CBotToken::DefineNum( "CBotErrCloseBlock", 5008) ; // missing " } "
+ CBotToken::DefineNum( "CBotErrElseWhitoutIf", 5009) ;// else without matching if
+ CBotToken::DefineNum( "CBotErrOpenBlock", 5010) ; // missing " { "
+ CBotToken::DefineNum( "CBotErrBadType1", 5011) ; // wrong type for the assignment
+ CBotToken::DefineNum( "CBotErrRedefVar", 5012) ; // redefinition of the variable
+ CBotToken::DefineNum( "CBotErrBadType2", 5013) ; // two operands are incompatible
+ CBotToken::DefineNum( "CBotErrUndefCall", 5014) ; // routine unknown
+ CBotToken::DefineNum( "CBotErrNoDoubleDots", 5015) ;// " : " expected
+ CBotToken::DefineNum( "CBotErrBreakOutside", 5017) ;// break outside of a loop
+ CBotToken::DefineNum( "CBotErrUndefLabel", 5019) ; // unknown label
+ CBotToken::DefineNum( "CBotErrLabel", 5018) ; // label can not get here
+ CBotToken::DefineNum( "CBotErrNoCase", 5020) ; // missing " case "
+ CBotToken::DefineNum( "CBotErrBadNum", 5021) ; // expected number
+ CBotToken::DefineNum( "CBotErrVoid", 5022) ; // " void " not possble here
+ CBotToken::DefineNum( "CBotErrNoType", 5023) ; // type declaration expected
+ CBotToken::DefineNum( "CBotErrNoVar", 5024) ; // variable name expected
+ CBotToken::DefineNum( "CBotErrNoFunc", 5025) ; // expected function name
+ CBotToken::DefineNum( "CBotErrOverParam", 5026) ; // too many parameters
+ CBotToken::DefineNum( "CBotErrRedefFunc", 5027) ; // this function already exists
+ CBotToken::DefineNum( "CBotErrLowParam", 5028) ; // not enough parameters
+ CBotToken::DefineNum( "CBotErrBadParam", 5029) ; // mauvais types de paramètres
+ CBotToken::DefineNum( "CBotErrNbParam", 5030) ; // wrong number of parameters
+ CBotToken::DefineNum( "CBotErrUndefItem", 5031) ; // element does not exist in the class
+ CBotToken::DefineNum( "CBotErrUndefClass", 5032) ; // variable is not a class
+ CBotToken::DefineNum( "CBotErrNoConstruct", 5033) ; // no appropriate constructor
+ CBotToken::DefineNum( "CBotErrRedefClass", 5034) ; // Class already exists
+ CBotToken::DefineNum( "CBotErrCloseIndex", 5035) ; // " ] " expected
+ CBotToken::DefineNum( "CBotErrReserved", 5036) ; // reserved word (for a DefineNum)
+
+// Here are the list of errors that can be returned by the module
+// for the execution
+
+ CBotToken::DefineNum( "CBotErrZeroDiv", 6000) ; // division by zero
+ CBotToken::DefineNum( "CBotErrNotInit", 6001) ; // uninitialized variable
+ CBotToken::DefineNum( "CBotErrBadThrow", 6002) ; // throw a negative value
+ CBotToken::DefineNum( "CBotErrNoRetVal", 6003) ; // function did not return results
+ CBotToken::DefineNum( "CBotErrNoRun", 6004) ; // active Run () without a function
+ CBotToken::DefineNum( "CBotErrUndefFunc", 6005) ; // Calling a function that no longer exists
+
+ CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf );
+
+ InitStringFunctions();
+
+ // just a function for various debug
+ CBotProgram::AddFunction("CBOTDEBUGDD", rCBotDebug, cCBotDebug);
+ //TODO implement this deletion
+ // DeleteFile("CbotDebug.txt");
+
+}
+
+void CBotProgram::Free()
+{
+ CBotToken::Free() ;
+ CBotCall ::Free() ;
+ CBotClass::Free() ;
+}
+
diff --git a/src/CBot/CBotWhile.cpp b/src/CBot/CBotWhile.cpp
index fcb825c..36923ae 100644
--- a/src/CBot/CBotWhile.cpp
+++ b/src/CBot/CBotWhile.cpp
@@ -1,1427 +1,1433 @@
-// * 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/.///////////////////////////////////////////////////////////////////////
-// ce fichier défini les instructions suivantes:
-// CBotWhile "while (condition) {instructions}"
-// CBotDo "do {instructions} while (condition)"
-// CBotFor "for (init, condition, incr) {instructions}"
-// CBotSwitch "switch (val) {instructions}"
-// CBotCase "case val:"
-// CBotBreak "break", "break label", "continu", "continu label"
-// CBotTry "try {instructions}"
-// CBotCatch "catch (condition) {instructions}" ou "finally"
-// CBotThrow "throw execption"
-
-
-#include "CBot.h"
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "while"
-
-CBotWhile::CBotWhile()
-{
- m_Condition =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotWhile"; // debug
-}
-
-CBotWhile::~CBotWhile()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotWhile* inst = new CBotWhile(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_WHILE)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe
-
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (il peut être vide !
-
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "while"
-
-bool CBotWhile :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != true )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // la condition est vrai, passe dans le second mode
-
- if (!pile->SetState(1)) return false; // prêt pour la suite
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(0, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au test pour recommencer
- if (!pile->SetState(0, 0)) return false;
- continue;
- }
-}
-
-void CBotWhile :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- m_Condition->RestoreState(pile, bMain);
- return;
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "repeat"
-
-CBotRepeat::CBotRepeat()
-{
- m_NbIter =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotRepeat"; // debug
-}
-
-CBotRepeat::~CBotRepeat()
-{
- delete m_NbIter; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotRepeat* inst = new CBotRepeat(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_REPEAT)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( IsOfType(p, ID_OPENPAR ) )
- {
- CBotToken* ppp = p; // conserve le ^au token (position début)
- if ( NULL != (inst->m_NbIter = CBotExpression::Compile( p, pStk )) )
- {
- if ( pStk->GivType() < CBotTypLong )
- {
- if ( IsOfType(p, ID_CLOSEPAR ) )
- {
-
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (il peut être vide !
-
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStk->SetStartError(ppp->GivStart());
- pStk->SetError( TX_BADTYPE, p->GivStart() );
- }
- pStack->SetError(TX_ENDOF, p);
- }
- pStack->SetError(TX_OPENPAR, p->GivStart()); // manque la parenthèse
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "repeat"
-
-bool CBotRepeat :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue le nombre d'itération
- if ( !m_NbIter->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- int n;
- if ( !pile->IsOk() || ( n = pile->GivVal() ) < 1 )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // met le nombre d'itération +1 dans le "state"
-
- if (!pile->SetState(n+1)) return false; // prêt pour la suite
- continue; // passe à la suite
-
- case 1:
- // fin normale de la boucle
- return pj->Return(pile); // transmet le résultat et libère la pile
-
- default:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(pile->GivState()-1, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au test pour recommencer
- if (!pile->SetState(pile->GivState()-1, 0)) return false;
- continue;
- }
-}
-
-void CBotRepeat :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- m_NbIter->RestoreState(pile, bMain);
- return;
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "do"
-
-CBotDo::CBotDo()
-{
- m_Condition =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotDo"; // debug
-}
-
-CBotDo::~CBotDo()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotDo* inst = new CBotDo(); // crée l'objet
-
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_DO)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
-
- // cherche un bloc d'instruction après le do
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- if (IsOfType(p, ID_WHILE))
- {
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe
- if (IsOfType(p, ID_SEP))
- {
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
- }
- pStk->SetError(TX_WHILE, p->GivStart());
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "do"
-
-bool CBotDo :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(1, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- if (!pile->SetState(1)) return false; // prêt pour la suite
-
- case 1:
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != true )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au bloc d'instruction pour recommencer
- if (!pile->SetState(0, 0)) return false;
- continue;
- }
-}
-
-void CBotDo :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // restitue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
-
- case 1:
- // restitue la condition
- m_Condition->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "for"
-
-CBotFor::CBotFor()
-{
- m_Init =
- m_Test =
- m_Incr =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotFor"; // debug
-}
-
-CBotFor::~CBotFor()
-{
- delete m_Init;
- delete m_Test;
- delete m_Incr;
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotFor* inst = new CBotFor(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_FOR)) return NULL; // ne devrait jamais arriver
-
- if ( !IsOfType(p, ID_OPENPAR)) // manque la parenthèse ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- return NULL;
- }
-
- CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp
-
- // compile les instructions pour initialisation
- inst->m_Init = CBotListExpression::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( !IsOfType(p, ID_SEP)) // manque le point-virgule ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
- }
- inst->m_Test = CBotBoolExpr::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( !IsOfType(p, ID_SEP)) // manque le point-virgule ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
- }
- inst->m_Incr = CBotListExpression::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( IsOfType(p, ID_CLOSEPAR)) // manque la parenthèse ?
- {
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
- if ( pStk->IsOk() )
- return pStack->Return(inst, pStk);;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- }
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction "for"
-
-bool CBotFor :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this, true); // ajoute un élément à la pile (variables locales)
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 4 états possibles (selon reprise)
- case 0:
- // évalue l'initialisation
- if ( m_Init != NULL &&
- !m_Init->Execute(pile) ) return false; // interrompu ici ?
- if (!pile->SetState(1)) return false; // prêt pour la suite
-
- case 1:
- // évalue la condition
- if ( m_Test != NULL ) // pas de condition ? -> vrai !
- {
- if (!m_Test->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != true )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
- }
-
- // la condition est vrai, passe à la suite
- if (!pile->SetState(2)) return false; // prêt pour la suite
-
- case 2:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(3, m_label)) continue; // si continue, passe à l'incrémentation
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- if (!pile->SetState(3)) return false; // prêt pour la suite
-
- case 3:
- // évalue l'incrémentation
- if ( m_Incr != NULL &&
- !m_Incr->Execute(pile) ) return false; // interrompu ici ?
-
- // repasse au test pour recommencer
- if (!pile->SetState(1, 0)) return false; // revient au test
- continue;
- }
-}
-
-void CBotFor :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile (variables locales)
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 4 états possibles (selon reprise)
- case 0:
- // évalue l'initialisation
- if ( m_Init != NULL ) m_Init->RestoreState(pile, true); // interrompu ici !
- return;
-
- case 1:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // définitions variables
-
- // évalue la condition
- if ( m_Test != NULL ) m_Test->RestoreState(pile, true); // interrompu ici !
- return;
-
- case 2:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // définitions variables
-
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, true);
- return;
-
- case 3:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // définitions variables
-
- // évalue l'incrémentation
- if ( m_Incr != NULL ) m_Incr->RestoreState(pile, true); // interrompu ici !
- return;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une liste d'expression
-// n'est utilisé que pour l'instruction for
-// dans l'intitialisation et dans l'incrémentation
-
-CBotListExpression::CBotListExpression()
-{
- m_Expr = NULL;
- name = "CBotListExpression";
-}
-
-CBotListExpression::~CBotListExpression()
-{
- delete m_Expr;
-}
-
-// cherche une déclaration de variable ou une expression
-
-static CBotInstr* CompileInstrOrDefVar(CBotToken* &p, CBotCStack* pStack)
-{
- CBotInstr* i = CBotInt::Compile( p, pStack, false, true ); // est-ce une déclaration d'un entier ?
- if ( i== NULL ) i = CBotFloat::Compile( p, pStack, false, true ); // ou d'un nombre réel ?
- if ( i== NULL ) i = CBotBoolean::Compile( p, pStack, false, true ); // ou d'un booléen ?
- if ( i== NULL ) i = CBotIString::Compile( p, pStack, false, true ); // ou d'une chaîne ?
- if ( i== NULL ) i = CBotExpression::Compile( p, pStack ); // compile une expression
- return i;
-}
-
-CBotInstr* CBotListExpression::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotListExpression* inst = new CBotListExpression();
-
- inst->m_Expr = CompileInstrOrDefVar( p, pStack ); // compile la première expression de la liste
- if (pStack->IsOk())
- {
- while ( IsOfType(p, ID_COMMA) ) // plusieurs instructions ?
- {
- CBotInstr* i = CompileInstrOrDefVar( p, pStack ); // est-ce une déclaration d'un entier ?
- inst->m_Expr->AddNext(i); // ajoute à la suite
- if ( !pStack->IsOk() )
- {
- delete inst;
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
- }
- return inst;
- }
- delete inst;
- return NULL;
-}
-
-bool CBotListExpression::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack();// indispensable
- CBotInstr* p = m_Expr; // la première expression
-
- int state = pile->GivState();
- while (state-->0) p = p->GivNext(); // revient sur l'opération interrompue
-
- if ( p != NULL ) while (true)
- {
- if ( !p->Execute(pile) ) return false;
- p = p->GivNext();
- if ( p == NULL ) break;
- if (!pile->IncState()) return false; // prêt pour la suivante
- }
- return pj->Return(pile);
-}
-
-void CBotListExpression::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotStack* pile = pj;
- int state = 0x7000;
-
- if ( bMain )
- {
- pile = pj->RestoreStack();
- if ( pile == NULL ) return;
- state = pile->GivState();
- }
-
- CBotInstr* p = m_Expr; // la première expression
-
- while (p != NULL && state-->0)
- {
- p->RestoreState(pile, false);
- p = p->GivNext(); // revient sur l'opération interrompue
- }
-
- if ( p != NULL )
- {
- p->RestoreState(pile, bMain);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "switch"
-
-CBotSwitch::CBotSwitch()
-{
- m_Value =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotSwitch"; // debug
-}
-
-CBotSwitch::~CBotSwitch()
-{
- delete m_Value; // libère la valeur
- delete m_Block; // libère le bloc d'instruction
-}
-
-
-CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotSwitch* inst = new CBotSwitch(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_SWITCH)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( IsOfType(p, ID_OPENPAR ) )
- {
- if ( NULL != (inst->m_Value = CBotExpression::Compile( p, pStk )) )
- {
- if ( pStk->GivType() < CBotTypLong )
- {
- if ( IsOfType(p, ID_CLOSEPAR ) )
- {
- if ( IsOfType(p, ID_OPBLK ) )
- {
- IncLvl();
-
- while( !IsOfType( p, ID_CLBLK ) )
- {
- if ( p->GivType() == ID_CASE || p->GivType() == ID_DEFAULT)
- {
- CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp
-
- CBotInstr* i = CBotCase::Compile( p, pStk2 );
- if (i == NULL)
- {
- delete inst;
- return pStack->Return(NULL, pStk2);
- }
- delete pStk2;
- if ( inst->m_Block == NULL ) inst->m_Block = i;
- else inst->m_Block->AddNext(i);
- continue;
- }
-
- if ( inst->m_Block == NULL )
- {
- pStk->SetError(TX_NOCASE, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true );
- if ( !pStk->IsOk() )
- {
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- inst->m_Block->AddNext(i);
-
- if ( p == NULL )
- {
- pStk->SetError(TX_CLOSEBLK, -1);
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- }
- DecLvl();
-
- if ( inst->m_Block == NULL )
- {
- pStk->SetError(TX_NOCASE, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- // le bloc d'instruction est ok
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- pStk->SetError( TX_OPENBLK, p->GivStart() );
- }
- pStk->SetError( TX_CLOSEPAR, p->GivStart() );
- }
- pStk->SetError( TX_BADTYPE, p->GivStart() );
- }
- }
- pStk->SetError( TX_OPENPAR, p->GivStart());
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "switch"
-
-bool CBotSwitch :: Execute(CBotStack* &pj)
-{
- CBotStack* pile1 = pj->AddStack(this); // ajoute un élément à la pile
-// if ( pile1 == EOX ) return true;
-
- CBotInstr* p = m_Block; // la première expression
-
- int state = pile1->GivState();
- if (state == 0)
- {
- if ( !m_Value->Execute(pile1) ) return false;
- pile1->SetState(state = -1);
- }
-
- if ( pile1->IfStep() ) return false;
-
- if ( state == -1 )
- {
- state = 0;
- int val = pile1->GivVal(); // résultat de la valeur
-
- CBotStack* pile2 = pile1->AddStack();
- while ( p != NULL ) // recherche le case correspondant dans la liste
- {
- state++;
- if ( p->CompCase( pile2, val ) ) break; // trouvé le case
- p = p->GivNext();
- }
- pile2->Delete();
-
- if ( p == NULL ) return pj->Return(pile1); // terminé si plus rien
-
- if ( !pile1->SetState(state) ) return false;
- }
-
- p = m_Block; // revient au début
- while (state-->0) p = p->GivNext(); // avance dans la liste
-
- while( p != NULL )
- {
- if ( !p->Execute(pile1) ) return pj->BreakReturn(pile1);
- if ( !pile1->IncState() ) return false;
- p = p->GivNext();
- }
- return pj->Return(pile1);
-}
-
-void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile1 = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile1 == NULL ) return;
-
- CBotInstr* p = m_Block; // la première expression
-
- int state = pile1->GivState();
- if (state == 0)
- {
- m_Value->RestoreState(pile1, bMain);
- return;
- }
-
- if ( state == -1 )
- {
- return;
- }
-
-// p = m_Block; // revient au début
- while ( p != NULL && state-- > 0 )
- {
- p->RestoreState(pile1, false);
- p = p->GivNext(); // avance dans la liste
- }
-
- if( p != NULL )
- {
- p->RestoreState(pile1, true);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "case"
-// on est forcément dans un bloc d'instruction "switch"
-
-CBotCase::CBotCase()
-{
- m_Value = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotCase"; // debug
-}
-
-CBotCase::~CBotCase()
-{
- delete m_Value; // libère la valeur
-}
-
-
-CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCase* inst = new CBotCase(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return NULL; // ne devrait jamais arriver
-
- if ( pp->GivType() == ID_CASE )
- {
- pp = p;
- inst->m_Value = CBotExprNum::Compile(p, pStack);
- if ( inst->m_Value == NULL )
- {
- pStack->SetError( TX_BADNUM, pp );
- delete inst;
- return NULL;
- }
- }
- if ( !IsOfType( p, ID_DOTS ))
- {
- pStack->SetError( TX_MISDOTS, p->GivStart() );
- delete inst;
- return NULL;
- }
-
- return inst;
-}
-
-// exécution de l'instruction "case"
-
-bool CBotCase::Execute(CBotStack* &pj)
-{
- return true; // l'instruction "case" ne fait rien !
-}
-
-void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
-{
-}
-
-// routine permettant de trouver le point d'entrée "case"
-// correspondant à la valeur cherchée
-
-bool CBotCase::CompCase(CBotStack* &pile, int val)
-{
- if ( m_Value == NULL ) return true; // cas pour "default"
-
- while (!m_Value->Execute(pile)); // met sur la pile la valeur correpondant (sans interruption)
- return (pile->GivVal() == val); // compare avec la valeur cherchée
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "break" ou "continu"
-
-CBotBreak::CBotBreak()
-{
- name = "CBotBreak"; // debug
-}
-
-CBotBreak::~CBotBreak()
-{
-}
-
-CBotInstr* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p; // conserve le ^au token (position début)
- int type = p->GivType();
-
- if (!IsOfType(p, ID_BREAK, ID_CONTINUE)) return NULL; // ne devrait jamais arriver
-
- if ( !ChkLvl(CBotString(), type ) )
- {
- pStack->SetError(TX_BREAK, pp);
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
-
- CBotBreak* inst = new CBotBreak(); // crée l'objet
- inst->SetToken(pp); // garde l'opération
-
- pp = p;
- if ( IsOfType( p, TokenTypVar ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- if ( !ChkLvl(inst->m_label, type ) )
- {
- delete inst;
- pStack->SetError(TX_NOLABEL, pp);
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
- }
-
- if (IsOfType(p, ID_SEP))
- {
- return inst; // et le donne à qui veux
- }
- delete inst;
-
- pStack->SetError(TX_ENDOF, p->GivStart());
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécution l'instructino "break" ou "continu"
-
-bool CBotBreak :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- pile->SetBreak(m_token.GivType()==ID_BREAK ? 1 : 2, m_label);
- return pj->Return(pile);
-}
-
-void CBotBreak :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "try"
-
-CBotTry::CBotTry()
-{
- m_ListCatch = NULL;
- m_FinalInst =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotTry"; // debug
-}
-
-CBotTry::~CBotTry()
-{
- delete m_ListCatch; // libère la liste
- delete m_Block; // libère le bloc d'instruction
- delete m_FinalInst;
-}
-
-CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotTry* inst = new CBotTry(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_TRY)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk );
- CBotCatch** pn = &inst->m_ListCatch;
-
- while (pStk->IsOk() && p->GivType() == ID_CATCH)
- {
- CBotCatch* i = CBotCatch::Compile(p, pStk);
- *pn = i;
- pn = &i->m_next;
- }
-
- if (pStk->IsOk() && IsOfType( p, ID_FINALLY) )
- {
- inst->m_FinalInst = CBotBlock::CompileBlkOrInst( p, pStk );
- }
-
- if (pStk->IsOk())
- {
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction Try
-// gère le retour d'exceptions
-// les arrêts par suspension
-// et les "finaly"
-
-bool CBotTry :: Execute(CBotStack* &pj)
-{
- int val;
-
- CBotStack* pile1 = pj->AddStack(this); // ajoute un élément à la pile
-// if ( pile1 == EOX ) return true;
-
- if ( pile1->IfStep() ) return false;
- // ou le retrouve en cas de reprise
- CBotStack* pile0 = pj->AddStack2(); // ajoute un élément à la pile secondaire
- CBotStack* pile2 = pile0->AddStack();
-
- if ( pile1->GivState() == 0 )
- {
- if ( m_Block->Execute(pile1) )
- {
- if ( m_FinalInst == NULL ) return pj->Return(pile1);
- pile1->SetState(-2); // passe au final
- }
-
- val = pile1->GivError();
- if ( val == 0 && CBotStack::m_initimer == 0 ) // en mode de step ?
- return false; // ne fait pas le catch
-
- pile1->IncState();
- pile2->SetState(val); // mémorise le numéro de l'erreur
- pile1->SetError(0); // pour l'instant il n'y a plus d'erreur !
-
- if ( val == 0 && CBotStack::m_initimer < 0 ) // en mode de step ?
- return false; // ne fait pas le catch
- }
-
- // il y a eu une interruption
- // voir de quoi il en retourne
-
- CBotCatch* pc = m_ListCatch;
- int state = (short)pile1->GivState(); // où en étions-nous ?
- val = pile2->GivState(); // pour quelle erreur ?
- pile0->SetState(1); // marquage pour GetRunPos
-
- if ( val >= 0 && state > 0 ) while ( pc != NULL )
- {
- if ( --state <= 0 )
- {
- // demande au bloc catch s'il se sent concerné
- if ( !pc->TestCatch(pile2, val) ) return false; // suspendu !
- pile1->IncState();
- }
- if ( --state <= 0 )
- {
- if ( pile2->GivVal() == true )
- {
-// pile0->SetState(1);
-
- if ( !pc->Execute(pile2) ) return false; // exécute l'opération
- if ( m_FinalInst == NULL )
- return pj->Return(pile2); // termine le try
-
- pile1->SetState(-2); // passe au final
- break;
- }
- pile1->IncState();
- }
- pc = pc->m_next;
- }
- if ( m_FinalInst != NULL &&
- pile1->GivState() > 0 && val != 0 ) pile1->SetState(-1);// si arret alors fait le final
-
- if (pile1->GivState() <= -1)
- {
-// pile0->SetState(1);
-
- if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return false;
- if (!pile2->IsOk()) return pj->Return(pile2); // garde cette exception
- pile2->SetError(pile1->GivState()==-1 ? val : 0); // remet l'erreur initiale
- return pj->Return(pile2);
- }
-
- pile1->SetState(0); // revient à l'évaluation
- pile0->SetState(0); // revient à l'évaluation
- if ( val != 0 && m_ListCatch == NULL && m_FinalInst == NULL )
- return pj->Return(pile2); // termine le try sans exception aucune
-
- pile1->SetError(val); // remet l'erreur
- return false; // ce n'est pas pour nous
-}
-
-
-void CBotTry :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- int val;
- CBotStack* pile1 = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile1 == NULL ) return;
- // ou le retrouve en cas de reprise
- CBotStack* pile0 = pj->AddStack2(); // ajoute un élément à la pile secondaire
- if ( pile0 == NULL ) return;
-
- CBotStack* pile2 = pile0->RestoreStack();
- if ( pile2 == NULL ) return;
-
- m_Block->RestoreState(pile1, bMain);
- if ( pile0->GivState() == 0 )
- {
- return;
- }
-
- // il y a eu une interruption
- // voir de quoi il en retourne
-
- CBotCatch* pc = m_ListCatch;
- int state = pile1->GivState(); // où en étions-nous ?
- val = pile2->GivState(); // pour quelle erreur ?
-
- if ( val >= 0 && state > 0 ) while ( pc != NULL )
- {
- if ( --state <= 0 )
- {
- // demande au bloc catch s'il se sent concerné
- pc->RestoreCondState(pile2, bMain); // suspendu !
- return;
- }
- if ( --state <= 0 )
- {
- if ( pile2->GivVal() == true )
- {
- pc->RestoreState(pile2, bMain); // exécute l'opération
- return;
- }
- }
- pc = pc->m_next;
- }
-
- if (pile1->GivState() <= -1)
- {
- m_FinalInst->RestoreState(pile2, bMain);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "catch"
-
-CBotCatch::CBotCatch()
-{
- m_Cond =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- m_next = NULL;
-
- name = "CBotCatch"; // debug
-}
-
-CBotCatch::~CBotCatch()
-{
- delete m_Cond; // libère la liste
- delete m_Block; // libère le bloc d'instruction
- delete m_next; // et la suite
-}
-
-CBotCatch* CBotCatch::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCatch* inst = new CBotCatch(); // crée l'objet
- pStack->SetStartError(p->GivStart());
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_CATCH)) return NULL; // ne devrait jamais arriver
-
- if (IsOfType(p, ID_OPENPAR))
- {
- inst->m_Cond = CBotExpression::Compile(p, pStack);
- if (( pStack->GivType() < CBotTypLong ||
- pStack->GivTypResult().Eq(CBotTypBoolean) )&& pStack->IsOk() )
- {
- if (IsOfType(p, ID_CLOSEPAR))
- {
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStack );
- if ( pStack->IsOk() )
- return inst; // rend l'objet à qui le demande
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStack->SetError(TX_BADTYPE, p->GivStart());
- }
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst; // erreur, libère la place
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécution de "catch"
-
-bool CBotCatch :: Execute(CBotStack* &pj)
-{
- if ( m_Block == NULL ) return true;
- return m_Block->Execute(pj); // exécute le bloc associé
-}
-
-void CBotCatch :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( bMain && m_Block != NULL ) m_Block->RestoreState(pj, bMain);
-}
-
-void CBotCatch :: RestoreCondState(CBotStack* &pj, bool bMain)
-{
- m_Cond->RestoreState(pj, bMain);
-}
-
-// routine pour savoir si le catch est à faire ou non
-
-bool CBotCatch :: TestCatch(CBotStack* &pile, int val)
-{
- if ( !m_Cond->Execute(pile) ) return false;
-
- if ( val > 0 || pile->GivType() != CBotTypBoolean )
- {
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
- var->SetValInt( pile->GivVal() == val );
- pile->SetVar(var); // remet sur la pile
- }
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "throw"
-
-CBotThrow::CBotThrow()
-{
- m_Value = NULL; // NULL pour que delete soit possible sans autre
-
- name = "CBotThrow"; // debug
-}
-
-CBotThrow::~CBotThrow()
-{
- delete m_Value;
-}
-
-CBotInstr* CBotThrow::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- pStack->SetStartError(p->GivStart());
-
- CBotThrow* inst = new CBotThrow(); // crée l'objet
- inst->SetToken(p);
-
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if (!IsOfType(p, ID_THROW)) return NULL; // ne devrait jamais arriver
-
- inst->m_Value = CBotExpression::Compile( p, pStack );
-
- if (pStack->GivType() < CBotTypLong && pStack->IsOk())
- {
- return inst; // rend l'objet à qui le demande
- }
- pStack->SetError(TX_BADTYPE, pp);
-
- delete inst; // erreur, libère la place
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction "throw"
-
-bool CBotThrow :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return true;
-
- if ( pile->GivState() == 0 )
- {
- if ( !m_Value->Execute(pile) ) return false;
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return false;
-
- int val = pile->GivVal();
- if ( val < 0 ) val = TX_BADTHROW;
- pile->SetError( val, &m_token );
- return pj->Return( pile );
-}
-
-void CBotThrow :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState() == 0 )
- {
- m_Value->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-
-////////////////////////////////////////////////////////////
-
-
-CBotStartDebugDD::CBotStartDebugDD()
-{
- name = "CBotStartDebugDD"; // debug
-}
-
-CBotStartDebugDD::~CBotStartDebugDD()
-{
-}
-
-CBotInstr* CBotStartDebugDD::Compile(CBotToken* &p, CBotCStack* pStack)
-{
-
- if (!IsOfType(p, ID_DEBUGDD)) return NULL; // ne devrait jamais arriver
-
- return new CBotStartDebugDD(); // crée l'objet
-
-}
-
-// exécute l'instruction "throw"
-
-bool CBotStartDebugDD :: Execute(CBotStack* &pj)
-{
- CBotProgram* p = pj->GivBotCall();
- p->m_bDebugDD = true;
-
- return true;
-}
-
+// * 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/.
+
+///////////////////////////////////////////////////////////////////////
+// This file defined the following statements:
+// CBotWhile "while (condition) {instructions}"
+// CBotDo "do {instructions} while (condition)"
+// CBotFor "for (init, condition, incr) {instructions}"
+// CBotSwitch "switch (val) {instructions}"
+// CBotCase "case val:"
+// CBotBreak "break", "break label", "continu", "continu label"
+// CBotTry "try {instructions}"
+// CBotCatch "catch (condition) {instructions}" or "finally"
+// CBotThrow "throw execption"
+
+
+#include "CBot.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compile an instruction "while"
+
+CBotWhile::CBotWhile()
+{
+ m_Condition =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotWhile"; // debug
+}
+
+CBotWhile::~CBotWhile()
+{
+ delete m_Condition; // frees the condition
+ delete m_Block; // releases the block instruction
+}
+
+CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotWhile* inst = new CBotWhile(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // records the name of the label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_WHILE)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+ // a bit of battery please (??)
+
+ if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
+ {
+ // the condition exists
+
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+
+ if ( pStk->IsOk() )
+ {
+ // the statement block is ok (it may be empty!
+
+ return pStack->Return(inst, pStk); // return an object to the application
+ // makes the object to which the application
+ }
+ }
+
+ delete inst; // error, frees the place
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// executes a "while" instruction
+
+bool CBotWhile :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // adds an item to the stack
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the condition
+ if ( !m_Condition->Execute(pile) ) return false; // interrupted here?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ if ( !pile->IsOk() || pile->GivVal() != true )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // the condition is true, pass in the second mode
+
+ if (!pile->SetState(1)) return false; // ready for further
+
+ case 1:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(0, m_label)) continue; // if continued, will return to test
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // returns to the test again
+ if (!pile->SetState(0, 0)) return false;
+ continue;
+ }
+}
+
+void CBotWhile :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the condition
+ m_Condition->RestoreState(pile, bMain);
+ return;
+
+ case 1:
+ // evaluates the associated statement block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "repeat"
+
+CBotRepeat::CBotRepeat()
+{
+ m_NbIter =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotRepeat"; // debug
+}
+
+CBotRepeat::~CBotRepeat()
+{
+ delete m_NbIter; // frees the condition
+ delete m_Block; // frees the instruction block
+}
+
+CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotRepeat* inst = new CBotRepeat(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_REPEAT)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+ if ( IsOfType(p, ID_OPENPAR ) )
+ {
+ CBotToken* ppp = p; // preserves the ^ token (starting position)
+ if ( NULL != (inst->m_NbIter = CBotExpression::Compile( p, pStk )) )
+ {
+ if ( pStk->GivType() < CBotTypLong )
+ {
+ if ( IsOfType(p, ID_CLOSEPAR ) )
+ {
+
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+
+ if ( pStk->IsOk() )
+ {
+ // the statement block is ok (it may be empty!
+
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ pStk->SetStartError(ppp->GivStart());
+ pStk->SetError( TX_BADTYPE, p->GivStart() );
+ }
+ pStack->SetError(TX_ENDOF, p);
+ }
+ pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// execution of intruction "repeat"
+
+bool CBotRepeat :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // adds an item to the stack
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the number of iterations
+ if ( !m_NbIter->Execute(pile) ) return false; // interrupted here ?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ int n;
+ if ( !pile->IsOk() || ( n = pile->GivVal() ) < 1 )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // puts the number of iterations +1 to the "state"
+
+ if (!pile->SetState(n+1)) return false; // ready for further
+ continue; // continue as a result
+
+ case 1:
+ // normal end of the loop
+ return pj->Return(pile); // sends the results and releases the stack
+
+ default:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(pile->GivState()-1, m_label)) continue; // if continued, will return to test
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // returns to the test again
+ if (!pile->SetState(pile->GivState()-1, 0)) return false;
+ continue;
+ }
+}
+
+void CBotRepeat :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the condition
+ m_NbIter->RestoreState(pile, bMain);
+ return;
+
+ case 1:
+ // evaluates the associated statement block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compile the instruction "do"
+
+CBotDo::CBotDo()
+{
+ m_Condition =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotDo"; // debug
+}
+
+CBotDo::~CBotDo()
+{
+ delete m_Condition; // frees the condition
+ delete m_Block; // frees the instruction block
+}
+
+CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotDo* inst = new CBotDo(); // creates the object
+
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_DO)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+
+ // looking for a statement block after the do
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+
+ if ( pStk->IsOk() )
+ {
+ if (IsOfType(p, ID_WHILE))
+ {
+ if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
+ {
+ // the condition exists
+ if (IsOfType(p, ID_SEP))
+ {
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ }
+ }
+ pStk->SetError(TX_WHILE, p->GivStart());
+ }
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// executes instruction "do"
+
+bool CBotDo :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // adds an item to the stack
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(1, m_label)) continue; // if continued, will return to test
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ if (!pile->SetState(1)) return false; // ready for further
+
+ case 1:
+ // evaluates the condition
+ if ( !m_Condition->Execute(pile) ) return false; // interrupted here ?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ if ( !pile->IsOk() || pile->GivVal() != true )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // returns to instruction block to start
+ if (!pile->SetState(0, 0)) return false;
+ continue;
+ }
+}
+
+void CBotDo :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // restores the assosiated statement's block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
+ return;
+
+ case 1:
+ // restores the condition
+ m_Condition->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "for"
+
+CBotFor::CBotFor()
+{
+ m_Init =
+ m_Test =
+ m_Incr =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotFor"; // debug
+}
+
+CBotFor::~CBotFor()
+{
+ delete m_Init;
+ delete m_Test;
+ delete m_Incr;
+ delete m_Block; // frees the instruction block
+}
+
+CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotFor* inst = new CBotFor(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_FOR)) return NULL; // should never happen
+
+ if ( !IsOfType(p, ID_OPENPAR)) // missing parenthesis ?
+ {
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ return NULL;
+ }
+
+ CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp
+
+ // compiles instructions for initialization
+ inst->m_Init = CBotListExpression::Compile( p, pStk );
+ if ( pStk->IsOk() )
+ {
+ if ( !IsOfType(p, ID_SEP)) // lack the semicolon?
+ {
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+ }
+ inst->m_Test = CBotBoolExpr::Compile( p, pStk );
+ if ( pStk->IsOk() )
+ {
+ if ( !IsOfType(p, ID_SEP)) // lack the semicolon?
+ {
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+ }
+ inst->m_Incr = CBotListExpression::Compile( p, pStk );
+ if ( pStk->IsOk() )
+ {
+ if ( IsOfType(p, ID_CLOSEPAR)) // missing parenthesis ?
+ {
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+ if ( pStk->IsOk() )
+ return pStack->Return(inst, pStk);;
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ }
+ }
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// execution of instruction "for"
+
+bool CBotFor :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this, true); // adds an item to the stack (variables locales)
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are four possible states (depending on recovery)
+ case 0:
+ // initialize
+ if ( m_Init != NULL &&
+ !m_Init->Execute(pile) ) return false; // interrupted here ?
+ if (!pile->SetState(1)) return false; // ready for further
+
+ case 1:
+ // evaluates the condition
+ if ( m_Test != NULL ) // no strings attached? -> True!
+ {
+ if (!m_Test->Execute(pile) ) return false; // interrupted here ?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ if ( !pile->IsOk() || pile->GivVal() != true )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+ }
+
+ // la condition est vrai, passe à la suite
+ if (!pile->SetState(2)) return false; // ready for further
+
+ case 2:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(3, m_label)) continue; // if continued, going on to incrementation
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ if (!pile->SetState(3)) return false; // ready for further
+
+ case 3:
+ // evalutate the incrementation
+ if ( m_Incr != NULL &&
+ !m_Incr->Execute(pile) ) return false; // interrupted here ?
+
+ // returns to the test again
+ if (!pile->SetState(1, 0)) return false; // returns to the test
+ continue;
+ }
+}
+
+void CBotFor :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack (variables locales)
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are four possible states (depending on recovery)
+ case 0:
+ // initialize
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, true); // interrupted here !
+ return;
+
+ case 1:
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variables definitions
+
+ // evaluates the condition
+ if ( m_Test != NULL ) m_Test->RestoreState(pile, true); // interrupted here !
+ return;
+
+ case 2:
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variable definitions
+
+ // evaluates the associated statement block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, true);
+ return;
+
+ case 3:
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variable definitions
+
+ // evaluate the incrementation
+ if ( m_Incr != NULL ) m_Incr->RestoreState(pile, true); // interrupted here !
+ return;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compiles a list of expressions
+// is used only in "for" statement
+// in incrementing and intitialisation
+
+CBotListExpression::CBotListExpression()
+{
+ m_Expr = NULL;
+ name = "CBotListExpression";
+}
+
+CBotListExpression::~CBotListExpression()
+{
+ delete m_Expr;
+}
+
+// seeks a declaration of variable or expression
+
+static CBotInstr* CompileInstrOrDefVar(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotInstr* i = CBotInt::Compile( p, pStack, false, true ); // Is this a declaration of an integer?
+ if ( i== NULL ) i = CBotFloat::Compile( p, pStack, false, true ); // or a real number?
+ if ( i== NULL ) i = CBotBoolean::Compile( p, pStack, false, true ); // or a boolean?
+ if ( i== NULL ) i = CBotIString::Compile( p, pStack, false, true ); // ar a string?
+ if ( i== NULL ) i = CBotExpression::Compile( p, pStack ); // compiles an expression
+ return i;
+}
+
+CBotInstr* CBotListExpression::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotListExpression* inst = new CBotListExpression();
+
+ inst->m_Expr = CompileInstrOrDefVar( p, pStack ); // compile the first expression in a list
+ if (pStack->IsOk())
+ {
+ while ( IsOfType(p, ID_COMMA) ) // more instructions?
+ {
+ CBotInstr* i = CompileInstrOrDefVar( p, pStack ); // Is this a declaration of an integer?
+ inst->m_Expr->AddNext(i); // added after
+ if ( !pStack->IsOk() )
+ {
+ delete inst;
+ return NULL; // no object, the error is on the stack
+ }
+ }
+ return inst;
+ }
+ delete inst;
+ return NULL;
+}
+
+bool CBotListExpression::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(); // essential
+ CBotInstr* p = m_Expr; // the first expression
+
+ int state = pile->GivState();
+ while (state-->0) p = p->GivNext(); // returns to the interrupted operation
+
+ if ( p != NULL ) while (true)
+ {
+ if ( !p->Execute(pile) ) return false;
+ p = p->GivNext();
+ if ( p == NULL ) break;
+ if (!pile->IncState()) return false; // ready for next
+ }
+ return pj->Return(pile);
+}
+
+void CBotListExpression::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotStack* pile = pj;
+ int state = 0x7000;
+
+ if ( bMain )
+ {
+ pile = pj->RestoreStack();
+ if ( pile == NULL ) return;
+ state = pile->GivState();
+ }
+
+ CBotInstr* p = m_Expr; // the first expression
+
+ while (p != NULL && state-->0)
+ {
+ p->RestoreState(pile, false);
+ p = p->GivNext(); // returns to the interrupted operation
+ }
+
+ if ( p != NULL )
+ {
+ p->RestoreState(pile, bMain);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "switch"
+
+CBotSwitch::CBotSwitch()
+{
+ m_Value =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotSwitch"; // debug
+}
+
+CBotSwitch::~CBotSwitch()
+{
+ delete m_Value; // frees the value
+ delete m_Block; // frees the instruction block
+}
+
+
+CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotSwitch* inst = new CBotSwitch(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_SWITCH)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+ if ( IsOfType(p, ID_OPENPAR ) )
+ {
+ if ( NULL != (inst->m_Value = CBotExpression::Compile( p, pStk )) )
+ {
+ if ( pStk->GivType() < CBotTypLong )
+ {
+ if ( IsOfType(p, ID_CLOSEPAR ) )
+ {
+ if ( IsOfType(p, ID_OPBLK ) )
+ {
+ IncLvl();
+
+ while( !IsOfType( p, ID_CLBLK ) )
+ {
+ if ( p->GivType() == ID_CASE || p->GivType() == ID_DEFAULT)
+ {
+ CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp
+
+ CBotInstr* i = CBotCase::Compile( p, pStk2 );
+ if (i == NULL)
+ {
+ delete inst;
+ return pStack->Return(NULL, pStk2);
+ }
+ delete pStk2;
+ if ( inst->m_Block == NULL ) inst->m_Block = i;
+ else inst->m_Block->AddNext(i);
+ continue;
+ }
+
+ if ( inst->m_Block == NULL )
+ {
+ pStk->SetError(TX_NOCASE, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ if ( !pStk->IsOk() )
+ {
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ inst->m_Block->AddNext(i);
+
+ if ( p == NULL )
+ {
+ pStk->SetError(TX_CLOSEBLK, -1);
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ }
+ DecLvl();
+
+ if ( inst->m_Block == NULL )
+ {
+ pStk->SetError(TX_NOCASE, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ // the statement block is ok
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+ pStk->SetError( TX_OPENBLK, p->GivStart() );
+ }
+ pStk->SetError( TX_CLOSEPAR, p->GivStart() );
+ }
+ pStk->SetError( TX_BADTYPE, p->GivStart() );
+ }
+ }
+ pStk->SetError( TX_OPENPAR, p->GivStart());
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// executes instruction "switch"
+
+bool CBotSwitch :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack
+// if ( pile1 == EOX ) return true;
+
+ CBotInstr* p = m_Block; // first expression
+
+ int state = pile1->GivState();
+ if (state == 0)
+ {
+ if ( !m_Value->Execute(pile1) ) return false;
+ pile1->SetState(state = -1);
+ }
+
+ if ( pile1->IfStep() ) return false;
+
+ if ( state == -1 )
+ {
+ state = 0;
+ int val = pile1->GivVal(); // result of the value
+
+ CBotStack* pile2 = pile1->AddStack();
+ while ( p != NULL ) // search for the corresponding case in a list
+ {
+ state++;
+ if ( p->CompCase( pile2, val ) ) break; // found the case
+ p = p->GivNext();
+ }
+ pile2->Delete();
+
+ if ( p == NULL ) return pj->Return(pile1); // completed if nothing
+
+ if ( !pile1->SetState(state) ) return false;
+ }
+
+ p = m_Block; // returns to the beginning
+ while (state-->0) p = p->GivNext(); // advance in the list
+
+ while( p != NULL )
+ {
+ if ( !p->Execute(pile1) ) return pj->BreakReturn(pile1);
+ if ( !pile1->IncState() ) return false;
+ p = p->GivNext();
+ }
+ return pj->Return(pile1);
+}
+
+void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile1 == NULL ) return;
+
+ CBotInstr* p = m_Block; // first expression
+
+ int state = pile1->GivState();
+ if (state == 0)
+ {
+ m_Value->RestoreState(pile1, bMain);
+ return;
+ }
+
+ if ( state == -1 )
+ {
+ return;
+ }
+
+// p = m_Block; // returns to the beginning
+ while ( p != NULL && state-- > 0 )
+ {
+ p->RestoreState(pile1, false);
+ p = p->GivNext(); // advance in the list
+ }
+
+ if( p != NULL )
+ {
+ p->RestoreState(pile1, true);
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "case"
+// we are bound to the statement block "switch"
+
+CBotCase::CBotCase()
+{
+ m_Value = NULL; // NULL so that delete is not possible further
+ name = "CBotCase"; // debug
+}
+
+CBotCase::~CBotCase()
+{
+ delete m_Value; // frees the value
+}
+
+
+CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCase* inst = new CBotCase(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return NULL; // should never happen
+
+ if ( pp->GivType() == ID_CASE )
+ {
+ pp = p;
+ inst->m_Value = CBotExprNum::Compile(p, pStack);
+ if ( inst->m_Value == NULL )
+ {
+ pStack->SetError( TX_BADNUM, pp );
+ delete inst;
+ return NULL;
+ }
+ }
+ if ( !IsOfType( p, ID_DOTS ))
+ {
+ pStack->SetError( TX_MISDOTS, p->GivStart() );
+ delete inst;
+ return NULL;
+ }
+
+ return inst;
+}
+
+// execution of instruction "case"
+
+bool CBotCase::Execute(CBotStack* &pj)
+{
+ return true; // the "case" statement does nothing!
+}
+
+void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
+{
+}
+
+// routine to find the entry point of "case"
+// corresponding to the value seen
+
+bool CBotCase::CompCase(CBotStack* &pile, int val)
+{
+ if ( m_Value == NULL ) return true; // "default" case
+
+ while (!m_Value->Execute(pile)); // puts the value on the correspondent stack (without interruption)
+ return (pile->GivVal() == val); // compared with the given value
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "break" or "continu"
+
+CBotBreak::CBotBreak()
+{
+ name = "CBotBreak"; // debug
+}
+
+CBotBreak::~CBotBreak()
+{
+}
+
+CBotInstr* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+ int type = p->GivType();
+
+ if (!IsOfType(p, ID_BREAK, ID_CONTINUE)) return NULL; // should never happen
+
+ if ( !ChkLvl(CBotString(), type ) )
+ {
+ pStack->SetError(TX_BREAK, pp);
+ return NULL; // no object, the error is on the stack
+ }
+
+ CBotBreak* inst = new CBotBreak(); // creates the object
+ inst->SetToken(pp); // keeps the operation
+
+ pp = p;
+ if ( IsOfType( p, TokenTypVar ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ if ( !ChkLvl(inst->m_label, type ) )
+ {
+ delete inst;
+ pStack->SetError(TX_NOLABEL, pp);
+ return NULL; // no object, the error is on the stack
+ }
+ }
+
+ if (IsOfType(p, ID_SEP))
+ {
+ return inst; // return what it wants
+ }
+ delete inst;
+
+ pStack->SetError(TX_ENDOF, p->GivStart());
+ return NULL; // no object, the error is on the stack
+}
+
+// execution of statement "break" or "continu"
+
+bool CBotBreak :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ pile->SetBreak(m_token.GivType()==ID_BREAK ? 1 : 2, m_label);
+ return pj->Return(pile);
+}
+
+void CBotBreak :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( bMain ) pj->RestoreStack(this);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "try"
+
+CBotTry::CBotTry()
+{
+ m_ListCatch = NULL;
+ m_FinalInst =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotTry"; // debug
+}
+
+CBotTry::~CBotTry()
+{
+ delete m_ListCatch; // frees the list
+ delete m_Block; // frees the instruction block
+ delete m_FinalInst;
+}
+
+CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotTry* inst = new CBotTry(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_TRY)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk );
+ CBotCatch** pn = &inst->m_ListCatch;
+
+ while (pStk->IsOk() && p->GivType() == ID_CATCH)
+ {
+ CBotCatch* i = CBotCatch::Compile(p, pStk);
+ *pn = i;
+ pn = &i->m_next;
+ }
+
+ if (pStk->IsOk() && IsOfType( p, ID_FINALLY) )
+ {
+ inst->m_FinalInst = CBotBlock::CompileBlkOrInst( p, pStk );
+ }
+
+ if (pStk->IsOk())
+ {
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// execution of instruction Try
+// manages the return of exceptions
+// stops (judgements) by suspension
+// and "finally"
+
+bool CBotTry :: Execute(CBotStack* &pj)
+{
+ int val;
+
+ CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack
+// if ( pile1 == EOX ) return true;
+
+ if ( pile1->IfStep() ) return false;
+ // or find in case of recovery
+ CBotStack* pile0 = pj->AddStack2(); // adds an element to the secondary stack
+ CBotStack* pile2 = pile0->AddStack();
+
+ if ( pile1->GivState() == 0 )
+ {
+ if ( m_Block->Execute(pile1) )
+ {
+ if ( m_FinalInst == NULL ) return pj->Return(pile1);
+ pile1->SetState(-2); // passes final
+ }
+
+ val = pile1->GivError();
+ if ( val == 0 && CBotStack::m_initimer == 0 ) // mode step?
+ return false; // does not make the catch
+
+ pile1->IncState();
+ pile2->SetState(val); // stores the error number
+ pile1->SetError(0); // for now there is are more errors!
+
+ if ( val == 0 && CBotStack::m_initimer < 0 ) // mode step?
+ return false; // does not make the catch
+ }
+
+ // there was an interruption
+ // see what it returns
+
+ CBotCatch* pc = m_ListCatch;
+ int state = (short)pile1->GivState(); // where were we?
+ val = pile2->GivState(); // what error?
+ pile0->SetState(1); // marking the GetRunPos
+
+ if ( val >= 0 && state > 0 ) while ( pc != NULL )
+ {
+ if ( --state <= 0 )
+ {
+ // request to the catch block if they feel concerned
+ // demande au bloc catch s'il se sent concerné
+ if ( !pc->TestCatch(pile2, val) ) return false; // suspend !
+ pile1->IncState();
+ }
+ if ( --state <= 0 )
+ {
+ if ( pile2->GivVal() == true )
+ {
+// pile0->SetState(1);
+
+ if ( !pc->Execute(pile2) ) return false; // performs the operation
+ if ( m_FinalInst == NULL )
+ return pj->Return(pile2); // ends the try
+
+ pile1->SetState(-2); // passes final
+ break;
+ }
+ pile1->IncState();
+ }
+ pc = pc->m_next;
+ }
+ if ( m_FinalInst != NULL &&
+ pile1->GivState() > 0 && val != 0 ) pile1->SetState(-1);// if stop then made the final
+
+ if (pile1->GivState() <= -1)
+ {
+// pile0->SetState(1);
+
+ if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return false;
+ if (!pile2->IsOk()) return pj->Return(pile2); // keep this exception
+ pile2->SetError(pile1->GivState()==-1 ? val : 0); // gives the initial error
+ return pj->Return(pile2);
+ }
+
+ pile1->SetState(0); // returns to the evaluation
+ pile0->SetState(0); // returns to the evaluation
+ if ( val != 0 && m_ListCatch == NULL && m_FinalInst == NULL )
+ return pj->Return(pile2); // ends the try without exception
+
+ pile1->SetError(val); // gives the error
+ return false; // it's not for us
+}
+
+
+void CBotTry :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ int val;
+ CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile1 == NULL ) return;
+ // or find in case of recovery
+ CBotStack* pile0 = pj->AddStack2(); // adds an item to the secondary stack
+ if ( pile0 == NULL ) return;
+
+ CBotStack* pile2 = pile0->RestoreStack();
+ if ( pile2 == NULL ) return;
+
+ m_Block->RestoreState(pile1, bMain);
+ if ( pile0->GivState() == 0 )
+ {
+ return;
+ }
+
+ // there was an interruption
+ // see what it returns
+
+ CBotCatch* pc = m_ListCatch;
+ int state = pile1->GivState(); // where were we ?
+ val = pile2->GivState(); // what error ?
+
+ if ( val >= 0 && state > 0 ) while ( pc != NULL )
+ {
+ if ( --state <= 0 )
+ {
+ // request to the catch block if they feel concerned
+ // demande au bloc catch s'il se sent concerné
+ pc->RestoreCondState(pile2, bMain); // suspend !
+ return;
+ }
+ if ( --state <= 0 )
+ {
+ if ( pile2->GivVal() == true )
+ {
+ pc->RestoreState(pile2, bMain); // execute the operation
+ return;
+ }
+ }
+ pc = pc->m_next;
+ }
+
+ if (pile1->GivState() <= -1)
+ {
+ m_FinalInst->RestoreState(pile2, bMain);
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "catch"
+
+CBotCatch::CBotCatch()
+{
+ m_Cond =
+ m_Block = NULL; // NULL so that delete is not possible further
+ m_next = NULL;
+
+ name = "CBotCatch"; // debug
+}
+
+CBotCatch::~CBotCatch()
+{
+ delete m_Cond; // frees the list
+ delete m_Block; // frees the instruction block
+ delete m_next; // and subsequent
+}
+
+CBotCatch* CBotCatch::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCatch* inst = new CBotCatch(); // creates the object
+ pStack->SetStartError(p->GivStart());
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_CATCH)) return NULL; // should never happen
+
+ if (IsOfType(p, ID_OPENPAR))
+ {
+ inst->m_Cond = CBotExpression::Compile(p, pStack);
+ if (( pStack->GivType() < CBotTypLong ||
+ pStack->GivTypResult().Eq(CBotTypBoolean) )&& pStack->IsOk() )
+ {
+ if (IsOfType(p, ID_CLOSEPAR))
+ {
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStack );
+ if ( pStack->IsOk() )
+ return inst; // return an object to the application
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ pStack->SetError(TX_BADTYPE, p->GivStart());
+ }
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ delete inst; // error, frees up
+ return NULL; // no object, the error is on the stack
+}
+
+// execution of "catch"
+
+bool CBotCatch :: Execute(CBotStack* &pj)
+{
+ if ( m_Block == NULL ) return true;
+ return m_Block->Execute(pj); // executes the associated block
+}
+
+void CBotCatch :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( bMain && m_Block != NULL ) m_Block->RestoreState(pj, bMain);
+}
+
+void CBotCatch :: RestoreCondState(CBotStack* &pj, bool bMain)
+{
+ m_Cond->RestoreState(pj, bMain);
+}
+
+// routine to see if the catch is to do or not
+
+bool CBotCatch :: TestCatch(CBotStack* &pile, int val)
+{
+ if ( !m_Cond->Execute(pile) ) return false;
+
+ if ( val > 0 || pile->GivType() != CBotTypBoolean )
+ {
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
+ var->SetValInt( pile->GivVal() == val );
+ pile->SetVar(var); // calls on the stack
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "throw"
+
+CBotThrow::CBotThrow()
+{
+ m_Value = NULL; // NULL so that delete is not possible further
+
+ name = "CBotThrow"; // debug
+}
+
+CBotThrow::~CBotThrow()
+{
+ delete m_Value;
+}
+
+CBotInstr* CBotThrow::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ pStack->SetStartError(p->GivStart());
+
+ CBotThrow* inst = new CBotThrow(); // creates the object
+ inst->SetToken(p);
+
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if (!IsOfType(p, ID_THROW)) return NULL; // should never happen
+
+ inst->m_Value = CBotExpression::Compile( p, pStack );
+
+ if (pStack->GivType() < CBotTypLong && pStack->IsOk())
+ {
+ return inst; // return an object to the application
+ }
+ pStack->SetError(TX_BADTYPE, pp);
+
+ delete inst; // error, frees up
+ return NULL; // no object, the error is on the stack
+}
+
+// execution of instruction "throw"
+
+bool CBotThrow :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+// if ( pile == EOX ) return true;
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( !m_Value->Execute(pile) ) return false;
+ pile->IncState();
+ }
+
+ if ( pile->IfStep() ) return false;
+
+ int val = pile->GivVal();
+ if ( val < 0 ) val = TX_BADTHROW;
+ pile->SetError( val, &m_token );
+ return pj->Return( pile );
+}
+
+void CBotThrow :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if ( pile == NULL ) return;
+
+ if ( pile->GivState() == 0 )
+ {
+ m_Value->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////
+
+
+CBotStartDebugDD::CBotStartDebugDD()
+{
+ name = "CBotStartDebugDD"; // debug
+}
+
+CBotStartDebugDD::~CBotStartDebugDD()
+{
+}
+
+CBotInstr* CBotStartDebugDD::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+
+ if (!IsOfType(p, ID_DEBUGDD)) return NULL; // should never happen
+
+ return new CBotStartDebugDD(); // creates the object
+
+}
+
+// execution of instruction "throw"
+
+bool CBotStartDebugDD :: Execute(CBotStack* &pj)
+{
+ CBotProgram* p = pj->GivBotCall();
+ p->m_bDebugDD = true;
+
+ return true;
+}
+
diff --git a/src/CBot/ClassFILE.cpp b/src/CBot/ClassFILE.cpp
index 330e814..b6c944c 100644
--- a/src/CBot/ClassFILE.cpp
+++ b/src/CBot/ClassFILE.cpp
@@ -12,13 +12,15 @@
// * 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/.// ClassFile.cpp
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// ClassFile.cpp
//
-// définition des méthodes pour la classe FILE
+// definition of methods for class FILE
-// Variables statiques
+// Static variables
static CBotClass* m_pClassFILE;
static CBotProgram* m_pFuncFile;
@@ -26,7 +28,7 @@ static int m_CompteurFileOpen = 0;
-// Prépare un nom de fichier.
+// Prepares a file name.
void PrepareFilename(CBotString &filename) //DD!
{
@@ -35,67 +37,67 @@ void PrepareFilename(CBotString &filename) //DD!
pos = filename.ReverseFind('\\');
if ( pos > 0 )
{
- filename = filename.Mid(pos+1); // enlève les dossiers
+ filename = filename.Mid(pos+1); // remove the records (files)??
}
pos = filename.ReverseFind('/');
if ( pos > 0 )
{
- filename = filename.Mid(pos+1); // aussi ceux avec /
+ filename = filename.Mid(pos+1); // also those with /
}
pos = filename.ReverseFind(':');
if ( pos > 0 )
{
- filename = filename.Mid(pos+1); // enlève aussi la lettre d'unité C:
+ filename = filename.Mid(pos+1); // also removes the drive letter C:
}
filename = CBotString("files\\") + filename;
}
-// constructeur de la classe
-// reçois le nom du fichier en paramètre
+// constructor of the class
+// gets the filename as a parameter
-// exécution
+// execution
bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
CBotString mode;
- // accepte sans paramètre
+ // accepts no parameters
if ( pVar == NULL ) return TRUE;
- // qui doit être une chaîne de caractères
+ // must be a string
if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
CBotString filename = pVar->GivValString();
PrepareFilename(filename); //DR
- // il peut y avoir un second paramètre
+ // there may be a second parameter
pVar = pVar->GivNext();
if ( pVar != NULL )
{
- // récupère le mode
+ // recovers the mode
mode = pVar->GivValString();
if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
- // pas de 3e paramètre
+ // no third parameter, only two or one possible
if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
}
- // enregistre le nom du fichier
+ // save the file name
pVar = pThis->GivItem("filename");
pVar->SetValString(filename);
if ( ! mode.IsEmpty() )
{
- // ouvre le ficher demandé
+ // open the called file
FILE* pFile = fopen( filename, mode );
if ( pFile == NULL ) { Exception = CBotErrFileOpen; return FALSE; }
m_CompteurFileOpen ++;
- // enregiste le canal du fichier
+ // save the handle of file
pVar = pThis->GivItem("handle");
pVar->SetValInt((long)pFile);
}
@@ -106,21 +108,21 @@ bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exceptio
// compilation
CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
{
- // accepte sans paramètre
+ // accepts no parameters
if ( pVar == NULL ) return CBotTypResult( 0 );
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // il peut y avoir un second paramètre
+ // there may be a second parameter
pVar = pVar->GivNext();
if ( pVar != NULL )
{
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // pas de 3e paramètre
+ // no third parameter
if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
}
@@ -129,15 +131,15 @@ CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
}
-// destructeur de la classe
+// destructor of the class
-// exécution
+// execution
bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // récupère l'élément "handle"
+ // retrieves the element "handle"
pVar = pThis->GivItem("handle");
- // pas ouvert ? pas de problème
+ // not open? no problem
if ( pVar->GivInit() != IS_DEF) return TRUE;
FILE* pFile= (FILE*)pVar->GivValInt();
@@ -150,52 +152,52 @@ bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception
}
-// méthode FILE :: open
-// reçois le mode r/w en paramètre
+// FILE :: open method
+// get the r / w mode as a parameter
-// exécution
+// execution
bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il doit y avoir un paramètre
+ // there must be a parameter
if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
- // qui doit être une chaîne de caractères
+ // must be a string
if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
- // il peut y avoir un second paramètre
+ // there may be a second parameter
if ( pVar->GivNext() != NULL )
{
- // dans ce cas le premier paramètre est le nom du fichier
+ // in this case the first parameter is the file name
CBotString filename = pVar->GivValString();
PrepareFilename(filename); //DR
- // enregistre le nom du fichier
+ // saves the file name
CBotVar* pVar2 = pThis->GivItem("filename");
pVar2->SetValString(filename);
- // paramètre suivant est le mode
+ // next parameter is the mode
pVar = pVar -> GivNext();
}
CBotString mode = pVar->GivValString();
if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
- // pas de 3e paramètre
+ // No third parameter
if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
- // récupère l'élément "handle"
+ // retrieves the element "handle"
pVar = pThis->GivItem("handle");
- // qui doit pas être initialisé
+ // which must not be initialized
if ( pVar->GivInit() == IS_DEF) { Exception = CBotErrFileOpen; return FALSE; }
- // reprend le nom du fichier
+ // contains filename
pVar = pThis->GivItem("filename");
CBotString filename = pVar->GivValString();
- PrepareFilename(filename); //DD! (si le nom a été attribué par h.filename = "...";
+ PrepareFilename(filename); //DD! (if the name was assigned by h.filename = "...";
- // ouvre le ficher demandé
+ // open requsted file
FILE* pFile = fopen( filename, mode );
if ( pFile == NULL ) //DR
{
@@ -205,7 +207,7 @@ bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
m_CompteurFileOpen ++;
- // enregiste le canal du fichier
+ // saves the handle of file
pVar = pThis->GivItem("handle");
pVar->SetValInt((long)pFile);
@@ -216,39 +218,39 @@ bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
// compilation
CBotTypResult cfopen (CBotVar* pThis, CBotVar* &pVar)
{
- // il doit y avoir un paramètre
+ // there must be a parameter
if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // il peut y avoir un second paramètre
+ // there may be a second parameter
pVar = pVar->GivNext();
if ( pVar != NULL )
{
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // pas de 3e paramètre
+ // no third parameter
if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
}
- // le résultat est de type bool
+ // the result is of type bool
return CBotTypResult(CBotTypBoolean); //DR
}
-// méthode FILE :: close
+// FILE :: close method
-// exécution
+// execution
bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il ne doit pas y avoir de paramètre
+ // it should not be any parameter
if ( pVar != NULL ) return CBotErrOverParam;
- // récupère l'élément "handle"
+ // retrieves the element "handle"
pVar = pThis->GivItem("handle");
if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
@@ -265,27 +267,27 @@ bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
// compilation
CBotTypResult cfclose (CBotVar* pThis, CBotVar* &pVar)
{
- // il ne doit pas y avoir de paramètre
+ // it should not be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat "void"
+ // function returns a result "void"
return CBotTypResult( 0 );
}
-// méthode FILE :: writeln
+// FILE :: writeln method
-// exécution
+// execution
bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il doit y avoir un paramètre
+ // there must be a parameter
if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
- // qui doit être une chaîne de caractères
+ // must be a string
if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
CBotString param = pVar->GivValString();
- // récupère l'élément "handle"
+ //retrieves the element "handle"
pVar = pThis->GivItem("handle");
if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
@@ -294,7 +296,7 @@ bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
int res = fputs(param+CBotString("\n"), pFile);
- // en cas d'erreur génère une exception
+ // on error throws an exception
if ( res < 0 ) { Exception = CBotErrWrite; return FALSE; }
return TRUE;
@@ -303,28 +305,28 @@ bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
// compilation
CBotTypResult cfwrite (CBotVar* pThis, CBotVar* &pVar)
{
- // il doit y avoir un paramètre
+ // there must be a parameter
if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
- // qui doit être une chaîne de caractères
+ // must be a string
if ( pVar->GivType() != CBotTypString ) return CBotTypResult( CBotErrBadString );
- // pas d'autre paramètre
+ // no other parameter
if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat void
+ // function returns "void" result
return CBotTypResult( 0 );
}
-// méthode FILE :: readln
+// FILE :: readln method
-// exécution
+// execution
bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il ne doit pas y avoir de paramètre
+ // there shouldn't be any parameter
if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
- // récupère l'élément "handle"
+ //retrieves the element "handle"
pVar = pThis->GivItem("handle");
if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
@@ -339,7 +341,7 @@ bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
for ( i = 0 ; i < 2000 ; i++ ) if (chaine[i] == '\n') chaine[i] = 0;
- // en cas d'erreur génère une exception
+ // on error throws an exception
if ( ferror(pFile) ) { Exception = CBotErrRead; return FALSE; }
pResult->SetValString( chaine );
@@ -350,22 +352,22 @@ bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
// compilation
CBotTypResult cfread (CBotVar* pThis, CBotVar* &pVar)
{
- // il ne doit pas y avoir de paramètre
+ // there shouldn't be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat "string"
+ // function return "string" result
return CBotTypResult( CBotTypString );
}
-// méthode FILE :: readln
+// FILE :: readln method
-// exécution
+// execution
bool rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il ne doit pas y avoir de paramètre
+ // there shouldn't be any parameter
if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
- // récupère l'élément "handle"
+ // retrieves the element "handle"
pVar = pThis->GivItem("handle");
if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
@@ -380,10 +382,10 @@ bool rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
// compilation
CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar)
{
- // il ne doit pas y avoir de paramètre
+ // there shouldn't be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat booleen
+ // function return boolean result
return CBotTypResult( CBotTypBoolean );
}
@@ -393,25 +395,25 @@ CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar)
void InitClassFILE()
{
-// crée une classe pour la gestion des fichiers
-// l'utilisation en est la suivante:
+// creates a class for file management
+// the usage is as follows:
// file canal( "NomFichier.txt" )
-// canal.open( "r" ); // ouvre en lecture
-// s = canal.readln( ); // lit une ligne
-// canal.close(); // referme le fichier
+// canal.open( "r" ); // open reading
+// s = canal.readln( ); // reads a line
+// canal.close(); // closes the file
- // crée la classe FILE
+ // create class FILE
m_pClassFILE = new CBotClass("file", NULL);
- // ajoute le composant ".filename"
+ // add the component ".filename"
m_pClassFILE->AddItem("filename", CBotTypString);
- // ajoute le composant ".handle"
+ // add the component ".handle"
m_pClassFILE->AddItem("handle", CBotTypInt, PR_PRIVATE);
- // défini un constructeur et un destructeur
+ // define a constructor and destructor
m_pClassFILE->AddFunction("file", rfconstruct, cfconstruct );
m_pClassFILE->AddFunction("~file", rfdestruct, NULL );
- // défini les méthodes associées
+ // defined associated methods
m_pClassFILE->AddFunction("open", rfopen, cfopen );
m_pClassFILE->AddFunction("close", rfclose, cfclose );
m_pClassFILE->AddFunction("writeln", rfwrite, cfwrite );
@@ -421,6 +423,6 @@ void InitClassFILE()
m_pFuncFile = new CBotProgram( );
CBotStringArray ListFonctions;
m_pFuncFile->Compile( "public file openfile(string name, string mode) {return new file(name, mode);}", ListFonctions);
- m_pFuncFile->SetIdent(-2); // identificateur spécial pour RestoreState dans cette fonction
+ m_pFuncFile->SetIdent(-2); // restoreState as a special identifier for this function
}