// * 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/./////////////////////////////////////////////////////////////////////// // instruction if (condition) opération1 else opération2; #include "CBot.h" // les divers constructeurs / destructeurs CBotIf::CBotIf() { m_Condition = m_Block = m_BlockElse = NULL; // NULL pour pouvoir faire delete directement name = "CBotIf"; // debug } CBotIf::~CBotIf() { delete m_Condition; // libère la condition delete m_Block; // libère le bloc d'instruction1 delete m_BlockElse; // libère le bloc d'instruction2 } // compilation (routine statique) // appelé lorsque le token "if" a été trouvé CBotInstr* CBotIf::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; // conserve le ^au token (début instruction) if (!IsOfType(p, ID_IF)) return NULL; // ne doit jamais arriver CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp CBotIf* inst = new CBotIf(); // crée l'object inst->SetToken( pp ); if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) ) { // la condition existe bel et bien inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); if ( pStk->IsOk() ) { // le bloc d'instruction est ok (peut être vide) // regarde si l'instruction suivante est le token "else" if (IsOfType(p, ID_ELSE)) { // si oui, compile le bloc d'instruction qui suit inst->m_BlockElse = CBotBlock::CompileBlkOrInst( p, pStk, true ); if (!pStk->IsOk()) { // il n'y a pas de bloc correct après le else // libère l'objet, et transmet l'erreur qui est sur la pile delete inst; return pStack->Return(NULL, pStk); } } // rend l'object correct à qui le demande. return pStack->Return(inst, pStk); } } // erreur, libère l'objet delete inst; // et transmet l'erreur qui se trouve sur la pile. return pStack->Return(NULL, pStk); } // exécution de l'instruction bool CBotIf :: 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; // selon la reprise, on peut être dans l'un des 2 états if( pile->GivState() == 0 ) { // évalue la condition if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ? // termine s'il y a une erreur if ( !pile->IsOk() ) { return pj->Return(pile); // transmet le résultat et libère la pile } // passe dans le second état if (!pile->SetState(1)) return false; // prêt pour la suite } // second état, évalue les instructions associées // le résultat de la condition est sur la pile if ( pile->GivVal() == true ) // condition était vraie ? { if ( m_Block != NULL && // bloc peut être absent !m_Block->Execute(pile) ) return false; // interrompu ici ? } else { if ( m_BlockElse != NULL && // s'il existe un bloc alternatif !m_BlockElse->Execute(pile) ) return false; // interrompu ici } // transmet le résultat et libère la pile return pj->Return(pile); } void CBotIf :: RestoreState(CBotStack* &pj, bool bMain) { if ( !bMain ) return; CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile if ( pile == NULL ) return; // selon la reprise, on peut être dans l'un des 2 états if( pile->GivState() == 0 ) { // évalue la condition m_Condition->RestoreState(pile, bMain); // interrompu ici ! return; } // second état, évalue les instructions associées // le résultat de la condition est sur la pile if ( pile->GivVal() == true ) // condition était vraie ? { if ( m_Block != NULL ) // bloc peut être absent m_Block->RestoreState(pile, bMain); // interrompu ici ! } else { if ( m_BlockElse != NULL ) // s'il existe un bloc alternatif m_BlockElse->RestoreState(pile, bMain); // interrompu ici ! } }