From bf3f9e1860a768b0e96a07fe4f138e332a9918ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Konopacki?= Date: Fri, 3 Aug 2012 00:50:25 +0200 Subject: Commentary translation --- src/CBot/CBotProgram.cpp | 2230 ++++++++++++++++++------------------ src/CBot/CBotWhile.cpp | 2860 +++++++++++++++++++++++----------------------- src/CBot/ClassFILE.cpp | 180 +-- 3 files changed, 2637 insertions(+), 2633 deletions(-) (limited to 'src/CBot') 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 - -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 + +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 } -- cgit v1.2.3-1-g7c22