2012-03-19 11:44:39 +00:00
|
|
|
|
// * This file is part of the COLOBOT source code
|
2012-03-09 16:08:05 +00:00
|
|
|
|
// * 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
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// * 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"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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()
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_Condition; // lib<69>re la condition
|
|
|
|
|
delete m_Block; // lib<69>re le bloc d'instruction
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotWhile* inst = new CBotWhile(); // cr<63>e l'objet
|
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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);
|
2012-07-04 20:14:28 +00:00
|
|
|
|
inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
|
2012-03-08 18:32:05 +00:00
|
|
|
|
DecLvl();
|
|
|
|
|
|
|
|
|
|
if ( pStk->IsOk() )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// le bloc d'instruction est ok (il peut <20>tre vide !
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pStack->Return(inst, pStk); // rend l'objet <20> qui le demande
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute une instruction "while"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotWhile :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile = pj->AddStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
// ou le retrouve en cas de reprise
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
while( true ) switch( pile->GivState() ) // ex<65>cute la boucle
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 2 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value la condition
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// le r<>sultat de la condition est sur la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur ou si la condition est fausse
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !pile->IsOk() || pile->GivVal() != true )
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// la condition est vrai, passe dans le second mode
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(1)) return false; // pr<70>t pour la suite
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
case 1:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le bloc d'instruction associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( m_Block != NULL &&
|
|
|
|
|
!m_Block->Execute(pile) )
|
|
|
|
|
{
|
|
|
|
|
if (pile->IfContinue(0, m_label)) continue; // si continue, repasse au test
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->BreakReturn(pile, m_label); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur
|
|
|
|
|
if ( !pile->IsOk() )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// repasse au test pour recommencer
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(0, 0)) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotWhile :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
if ( !bMain ) return;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile = pj->RestoreStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( pile == NULL ) return;
|
|
|
|
|
|
|
|
|
|
switch( pile->GivState() )
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 2 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value la condition
|
2012-03-08 18:32:05 +00:00
|
|
|
|
m_Condition->RestoreState(pile, bMain);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 1:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le bloc d'instruction associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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()
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_NbIter; // lib<69>re la condition
|
|
|
|
|
delete m_Block; // lib<69>re le bloc d'instruction
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotRepeat* inst = new CBotRepeat(); // cr<63>e l'objet
|
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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 ) )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotToken* ppp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( NULL != (inst->m_NbIter = CBotExpression::Compile( p, pStk )) )
|
|
|
|
|
{
|
|
|
|
|
if ( pStk->GivType() < CBotTypLong )
|
|
|
|
|
{
|
|
|
|
|
if ( IsOfType(p, ID_CLOSEPAR ) )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
IncLvl(inst->m_label);
|
2012-07-04 20:14:28 +00:00
|
|
|
|
inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
|
2012-03-08 18:32:05 +00:00
|
|
|
|
DecLvl();
|
|
|
|
|
|
|
|
|
|
if ( pStk->IsOk() )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// le bloc d'instruction est ok (il peut <20>tre vide !
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pStack->Return(inst, pStk); // rend l'objet <20> qui le demande
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pStack->SetError(TX_CLOSEPAR, p->GivStart());
|
|
|
|
|
}
|
|
|
|
|
pStk->SetStartError(ppp->GivStart());
|
|
|
|
|
pStk->SetError( TX_BADTYPE, p->GivStart() );
|
|
|
|
|
}
|
|
|
|
|
pStack->SetError(TX_ENDOF, p);
|
|
|
|
|
}
|
2012-03-19 11:44:39 +00:00
|
|
|
|
pStack->SetError(TX_OPENPAR, p->GivStart()); // manque la parenth<74>se
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute une instruction "repeat"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotRepeat :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile = pj->AddStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
// ou le retrouve en cas de reprise
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
while( true ) switch( pile->GivState() ) // ex<65>cute la boucle
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 2 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le nombre d'it<69>ration
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !m_NbIter->Execute(pile) ) return false; // interrompu ici ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// le r<>sultat de la condition est sur la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur ou si la condition est fausse
|
|
|
|
|
int n;
|
|
|
|
|
if ( !pile->IsOk() || ( n = pile->GivVal() ) < 1 )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// met le nombre d'it<69>ration +1 dans le "state"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(n+1)) return false; // pr<70>t pour la suite
|
2012-03-19 11:44:39 +00:00
|
|
|
|
continue; // passe <20> la suite
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
// fin normale de la boucle
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
default:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le bloc d'instruction associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( m_Block != NULL &&
|
|
|
|
|
!m_Block->Execute(pile) )
|
|
|
|
|
{
|
|
|
|
|
if (pile->IfContinue(pile->GivState()-1, m_label)) continue; // si continue, repasse au test
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->BreakReturn(pile, m_label); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur
|
|
|
|
|
if ( !pile->IsOk() )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// repasse au test pour recommencer
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(pile->GivState()-1, 0)) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotRepeat :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
if ( !bMain ) return;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile = pj->RestoreStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( pile == NULL ) return;
|
|
|
|
|
|
|
|
|
|
switch( pile->GivState() )
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 2 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value la condition
|
2012-03-08 18:32:05 +00:00
|
|
|
|
m_NbIter->RestoreState(pile, bMain);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 1:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le bloc d'instruction associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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()
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_Condition; // lib<69>re la condition
|
|
|
|
|
delete m_Block; // lib<69>re le bloc d'instruction
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotDo* inst = new CBotDo(); // cr<63>e l'objet
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// cherche un bloc d'instruction apr<70>s le do
|
2012-03-08 18:32:05 +00:00
|
|
|
|
IncLvl(inst->m_label);
|
2012-07-04 20:14:28 +00:00
|
|
|
|
inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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))
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pStack->Return(inst, pStk); // rend l'objet <20> qui le demande
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
pStk->SetError(TX_ENDOF, p->GivStart());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pStk->SetError(TX_WHILE, p->GivStart());
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute une instruction "do"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotDo :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile = pj->AddStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
// ou le retrouve en cas de reprise
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
while( true ) switch( pile->GivState() ) // ex<65>cute la boucle
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 2 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le bloc d'instruction associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( m_Block != NULL &&
|
|
|
|
|
!m_Block->Execute(pile) )
|
|
|
|
|
{
|
|
|
|
|
if (pile->IfContinue(1, m_label)) continue; // si continue, repasse au test
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->BreakReturn(pile, m_label); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur
|
|
|
|
|
if ( !pile->IsOk() )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(1)) return false; // pr<70>t pour la suite
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
case 1:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value la condition
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// le r<>sultat de la condition est sur la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur ou si la condition est fausse
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !pile->IsOk() || pile->GivVal() != true )
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// repasse au bloc d'instruction pour recommencer
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(0, 0)) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotDo :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
if ( !bMain ) return;
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile = pj->RestoreStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( pile == NULL ) return;
|
|
|
|
|
|
|
|
|
|
switch( pile->GivState() )
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 2 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// restitue le bloc d'instruction associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_Block; // lib<69>re le bloc d'instruction
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotFor* inst = new CBotFor(); // cr<63>e l'objet
|
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
if ( !IsOfType(p, ID_OPENPAR)) // manque la parenth<74>se ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
pStack->SetError(TX_OPENPAR, p->GivStart());
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
// 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() )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
if ( IsOfType(p, ID_CLOSEPAR)) // manque la parenth<74>se ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
IncLvl(inst->m_label);
|
2012-07-04 20:14:28 +00:00
|
|
|
|
inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
|
2012-03-08 18:32:05 +00:00
|
|
|
|
DecLvl();
|
|
|
|
|
if ( pStk->IsOk() )
|
|
|
|
|
return pStack->Return(inst, pStk);;
|
|
|
|
|
}
|
|
|
|
|
pStack->SetError(TX_CLOSEPAR, p->GivStart());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute l'instruction "for"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotFor :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
CBotStack* pile = pj->AddStack(this, true); // ajoute un <20>l<EFBFBD>ment <20> la pile (variables locales)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
// ou le retrouve en cas de reprise
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
while( true ) switch( pile->GivState() ) // ex<65>cute la boucle
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 4 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value l'initialisation
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( m_Init != NULL &&
|
2012-07-04 20:14:28 +00:00
|
|
|
|
!m_Init->Execute(pile) ) return false; // interrompu ici ?
|
|
|
|
|
if (!pile->SetState(1)) return false; // pr<70>t pour la suite
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
case 1:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value la condition
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( m_Test != NULL ) // pas de condition ? -> vrai !
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!m_Test->Execute(pile) ) return false; // interrompu ici ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// le r<>sultat de la condition est sur la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur ou si la condition est fausse
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !pile->IsOk() || pile->GivVal() != true )
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// la condition est vrai, passe <20> la suite
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(2)) return false; // pr<70>t pour la suite
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
case 2:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le bloc d'instruction associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( m_Block != NULL &&
|
|
|
|
|
!m_Block->Execute(pile) )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
if (pile->IfContinue(3, m_label)) continue; // si continue, passe <20> l'incr<63>mentation
|
|
|
|
|
return pj->BreakReturn(pile, m_label); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// termine s'il y a une erreur
|
|
|
|
|
if ( !pile->IsOk() )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pj->Return(pile); // transmet le r<>sultat et lib<69>re la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(3)) return false; // pr<70>t pour la suite
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
case 3:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value l'incr<63>mentation
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( m_Incr != NULL &&
|
2012-07-04 20:14:28 +00:00
|
|
|
|
!m_Incr->Execute(pile) ) return false; // interrompu ici ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
// repasse au test pour recommencer
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->SetState(1, 0)) return false; // revient au test
|
2012-03-08 18:32:05 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotFor :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
if ( !bMain ) return;
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile = pj->RestoreStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile (variables locales)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( pile == NULL ) return;
|
|
|
|
|
|
|
|
|
|
switch( pile->GivState() )
|
2012-03-19 11:44:39 +00:00
|
|
|
|
{ // il y a 4 <20>tats possibles (selon reprise)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
case 0:
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value l'initialisation
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Init != NULL ) m_Init->RestoreState(pile, true); // interrompu ici !
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 1:
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // d<>finitions variables
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value la condition
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Test != NULL ) m_Test->RestoreState(pile, true); // interrompu ici !
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 2:
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // d<>finitions variables
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value le bloc d'instruction associ<63>
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Block != NULL ) m_Block->RestoreState(pile, true);
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 3:
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // d<>finitions variables
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// <20>value l'incr<63>mentation
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Incr != NULL ) m_Incr->RestoreState(pile, true); // interrompu ici !
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// compile une liste d'expression
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// n'est utilis<69> que pour l'instruction for
|
|
|
|
|
// dans l'intitialisation et dans l'incr<63>mentation
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
CBotListExpression::CBotListExpression()
|
|
|
|
|
{
|
|
|
|
|
m_Expr = NULL;
|
|
|
|
|
name = "CBotListExpression";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotListExpression::~CBotListExpression()
|
|
|
|
|
{
|
|
|
|
|
delete m_Expr;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// cherche une d<>claration de variable ou une expression
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
static CBotInstr* CompileInstrOrDefVar(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
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<6F>en ?
|
|
|
|
|
if ( i== NULL ) i = CBotIString::Compile( p, pStack, false, true ); // ou d'une cha<68>ne ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( i== NULL ) i = CBotExpression::Compile( p, pStack ); // compile une expression
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotListExpression::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
|
|
|
|
CBotListExpression* inst = new CBotListExpression();
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
inst->m_Expr = CompileInstrOrDefVar( p, pStack ); // compile la premi<6D>re expression de la liste
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if (pStack->IsOk())
|
|
|
|
|
{
|
|
|
|
|
while ( IsOfType(p, ID_COMMA) ) // plusieurs instructions ?
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotInstr* i = CompileInstrOrDefVar( p, pStack ); // est-ce une d<>claration d'un entier ?
|
|
|
|
|
inst->m_Expr->AddNext(i); // ajoute <20> la suite
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( !pStack->IsOk() )
|
|
|
|
|
{
|
|
|
|
|
delete inst;
|
|
|
|
|
return NULL; // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return inst;
|
|
|
|
|
}
|
|
|
|
|
delete inst;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotListExpression::Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
CBotStack* pile = pj->AddStack();// indispensable
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotInstr* p = m_Expr; // la premi<6D>re expression
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
int state = pile->GivState();
|
2012-03-19 11:44:39 +00:00
|
|
|
|
while (state-->0) p = p->GivNext(); // revient sur l'op<6F>ration interrompue
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( p != NULL ) while (true)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !p->Execute(pile) ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
p = p->GivNext();
|
|
|
|
|
if ( p == NULL ) break;
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!pile->IncState()) return false; // pr<70>t pour la suivante
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
return pj->Return(pile);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotListExpression::RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
CBotStack* pile = pj;
|
|
|
|
|
int state = 0x7000;
|
|
|
|
|
|
|
|
|
|
if ( bMain )
|
|
|
|
|
{
|
|
|
|
|
pile = pj->RestoreStack();
|
|
|
|
|
if ( pile == NULL ) return;
|
|
|
|
|
state = pile->GivState();
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotInstr* p = m_Expr; // la premi<6D>re expression
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
while (p != NULL && state-->0)
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
p->RestoreState(pile, false);
|
2012-03-19 11:44:39 +00:00
|
|
|
|
p = p->GivNext(); // revient sur l'op<6F>ration interrompue
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_Value; // lib<69>re la valeur
|
|
|
|
|
delete m_Block; // lib<69>re le bloc d'instruction
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotSwitch* inst = new CBotSwitch(); // cr<63>e l'objet
|
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true );
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pStack->Return(inst, pStk); // rend l'objet <20> qui le demande
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
pStk->SetError( TX_OPENBLK, p->GivStart() );
|
|
|
|
|
}
|
|
|
|
|
pStk->SetError( TX_CLOSEPAR, p->GivStart() );
|
|
|
|
|
}
|
|
|
|
|
pStk->SetError( TX_BADTYPE, p->GivStart() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pStk->SetError( TX_OPENPAR, p->GivStart());
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute une instruction "switch"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotSwitch :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile1 = pj->AddStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile1 == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotInstr* p = m_Block; // la premi<6D>re expression
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
int state = pile1->GivState();
|
|
|
|
|
if (state == 0)
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !m_Value->Execute(pile1) ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
pile1->SetState(state = -1);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile1->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
if ( state == -1 )
|
|
|
|
|
{
|
|
|
|
|
state = 0;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
int val = pile1->GivVal(); // r<>sultat de la valeur
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
CBotStack* pile2 = pile1->AddStack();
|
|
|
|
|
while ( p != NULL ) // recherche le case correspondant dans la liste
|
|
|
|
|
{
|
|
|
|
|
state++;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
if ( p->CompCase( pile2, val ) ) break; // trouv<75> le case
|
2012-03-08 18:32:05 +00:00
|
|
|
|
p = p->GivNext();
|
|
|
|
|
}
|
|
|
|
|
pile2->Delete();
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
if ( p == NULL ) return pj->Return(pile1); // termin<69> si plus rien
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !pile1->SetState(state) ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
p = m_Block; // revient au d<>but
|
2012-03-08 18:32:05 +00:00
|
|
|
|
while (state-->0) p = p->GivNext(); // avance dans la liste
|
|
|
|
|
|
|
|
|
|
while( p != NULL )
|
|
|
|
|
{
|
|
|
|
|
if ( !p->Execute(pile1) ) return pj->BreakReturn(pile1);
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !pile1->IncState() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
p = p->GivNext();
|
|
|
|
|
}
|
|
|
|
|
return pj->Return(pile1);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
if ( !bMain ) return;
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile1 = pj->RestoreStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( pile1 == NULL ) return;
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotInstr* p = m_Block; // la premi<6D>re expression
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
int state = pile1->GivState();
|
|
|
|
|
if (state == 0)
|
|
|
|
|
{
|
|
|
|
|
m_Value->RestoreState(pile1, bMain);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( state == -1 )
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// p = m_Block; // revient au d<>but
|
2012-03-08 18:32:05 +00:00
|
|
|
|
while ( p != NULL && state-- > 0 )
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
p->RestoreState(pile1, false);
|
2012-03-08 18:32:05 +00:00
|
|
|
|
p = p->GivNext(); // avance dans la liste
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( p != NULL )
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
p->RestoreState(pile1, true);
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// compile une instruction "case"
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// on est forc<72>ment dans un bloc d'instruction "switch"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
CBotCase::CBotCase()
|
|
|
|
|
{
|
|
|
|
|
m_Value = NULL; // NULL pour que delete soit possible sans autre
|
|
|
|
|
name = "CBotCase"; // debug
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotCase::~CBotCase()
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_Value; // lib<69>re la valeur
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotCase* inst = new CBotCase(); // cr<63>e l'objet
|
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cution de l'instruction "case"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotCase::Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
return true; // l'instruction "case" ne fait rien !
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// routine permettant de trouver le point d'entr<74>e "case"
|
|
|
|
|
// correspondant <20> la valeur cherch<63>e
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotCase::CompCase(CBotStack* &pile, int val)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Value == NULL ) return true; // cas pour "default"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
while (!m_Value->Execute(pile)); // met sur la pile la valeur correpondant (sans interruption)
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return (pile->GivVal() == val); // compare avec la valeur cherch<63>e
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// compile une instruction "break" ou "continu"
|
|
|
|
|
|
|
|
|
|
CBotBreak::CBotBreak()
|
|
|
|
|
{
|
|
|
|
|
name = "CBotBreak"; // debug
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotBreak::~CBotBreak()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotBreak* inst = new CBotBreak(); // cr<63>e l'objet
|
|
|
|
|
inst->SetToken(pp); // garde l'op<6F>ration
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return inst; // et le donne <20> qui veux
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
delete inst;
|
|
|
|
|
|
|
|
|
|
pStack->SetError(TX_ENDOF, p->GivStart());
|
|
|
|
|
return NULL; // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cution l'instructino "break" ou "continu"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotBreak :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
CBotStack* pile = pj->AddStack(this);
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
pile->SetBreak(m_token.GivType()==ID_BREAK ? 1 : 2, m_label);
|
|
|
|
|
return pj->Return(pile);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotBreak :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
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()
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_ListCatch; // lib<69>re la liste
|
|
|
|
|
delete m_Block; // lib<69>re le bloc d'instruction
|
2012-03-08 18:32:05 +00:00
|
|
|
|
delete m_FinalInst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotTry* inst = new CBotTry(); // cr<63>e l'objet
|
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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())
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return pStack->Return(inst, pStk); // rend l'objet <20> qui le demande
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute l'instruction Try
|
|
|
|
|
// g<>re le retour d'exceptions
|
|
|
|
|
// les arr<72>ts par suspension
|
2012-03-08 18:32:05 +00:00
|
|
|
|
// et les "finaly"
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotTry :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
int val;
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile1 = pj->AddStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile1 == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile1->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
// ou le retrouve en cas de reprise
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile0 = pj->AddStack2(); // ajoute un <20>l<EFBFBD>ment <20> la pile secondaire
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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 ?
|
2012-07-04 20:14:28 +00:00
|
|
|
|
return false; // ne fait pas le catch
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
pile1->IncState();
|
2012-03-19 11:44:39 +00:00
|
|
|
|
pile2->SetState(val); // m<>morise le num<75>ro de l'erreur
|
2012-03-08 18:32:05 +00:00
|
|
|
|
pile1->SetError(0); // pour l'instant il n'y a plus d'erreur !
|
|
|
|
|
|
|
|
|
|
if ( val == 0 && CBotStack::m_initimer < 0 ) // en mode de step ?
|
2012-07-04 20:14:28 +00:00
|
|
|
|
return false; // ne fait pas le catch
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// il y a eu une interruption
|
|
|
|
|
// voir de quoi il en retourne
|
|
|
|
|
|
|
|
|
|
CBotCatch* pc = m_ListCatch;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
int state = (short)pile1->GivState(); // o<> en <20>tions-nous ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
val = pile2->GivState(); // pour quelle erreur ?
|
|
|
|
|
pile0->SetState(1); // marquage pour GetRunPos
|
|
|
|
|
|
|
|
|
|
if ( val >= 0 && state > 0 ) while ( pc != NULL )
|
|
|
|
|
{
|
|
|
|
|
if ( --state <= 0 )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// demande au bloc catch s'il se sent concern<72>
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !pc->TestCatch(pile2, val) ) return false; // suspendu !
|
2012-03-08 18:32:05 +00:00
|
|
|
|
pile1->IncState();
|
|
|
|
|
}
|
|
|
|
|
if ( --state <= 0 )
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile2->GivVal() == true )
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
// pile0->SetState(1);
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !pc->Execute(pile2) ) return false; // ex<65>cute l'op<6F>ration
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
pile1->SetState(0); // revient <20> l'<27>valuation
|
|
|
|
|
pile0->SetState(0); // revient <20> l'<27>valuation
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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
|
2012-07-04 20:14:28 +00:00
|
|
|
|
return false; // ce n'est pas pour nous
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotTry :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
if ( !bMain ) return;
|
|
|
|
|
|
|
|
|
|
int val;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile1 = pj->RestoreStack(this); // ajoute un <20>l<EFBFBD>ment <20> la pile
|
2012-03-08 18:32:05 +00:00
|
|
|
|
if ( pile1 == NULL ) return;
|
|
|
|
|
// ou le retrouve en cas de reprise
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotStack* pile0 = pj->AddStack2(); // ajoute un <20>l<EFBFBD>ment <20> la pile secondaire
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
int state = pile1->GivState(); // o<> en <20>tions-nous ?
|
2012-03-08 18:32:05 +00:00
|
|
|
|
val = pile2->GivState(); // pour quelle erreur ?
|
|
|
|
|
|
|
|
|
|
if ( val >= 0 && state > 0 ) while ( pc != NULL )
|
|
|
|
|
{
|
|
|
|
|
if ( --state <= 0 )
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// demande au bloc catch s'il se sent concern<72>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
pc->RestoreCondState(pile2, bMain); // suspendu !
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( --state <= 0 )
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile2->GivVal() == true )
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
pc->RestoreState(pile2, bMain); // ex<65>cute l'op<6F>ration
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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()
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete m_Cond; // lib<69>re la liste
|
|
|
|
|
delete m_Block; // lib<69>re le bloc d'instruction
|
2012-03-08 18:32:05 +00:00
|
|
|
|
delete m_next; // et la suite
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBotCatch* CBotCatch::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotCatch* inst = new CBotCatch(); // cr<63>e l'objet
|
2012-03-08 18:32:05 +00:00
|
|
|
|
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() )
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return inst; // rend l'objet <20> qui le demande
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
pStack->SetError(TX_CLOSEPAR, p->GivStart());
|
|
|
|
|
}
|
|
|
|
|
pStack->SetError(TX_BADTYPE, p->GivStart());
|
|
|
|
|
}
|
|
|
|
|
pStack->SetError(TX_OPENPAR, p->GivStart());
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return NULL; // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cution de "catch"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotCatch :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( m_Block == NULL ) return true;
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return m_Block->Execute(pj); // ex<65>cute le bloc associ<63>
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotCatch :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
if ( bMain && m_Block != NULL ) m_Block->RestoreState(pj, bMain);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotCatch :: RestoreCondState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
m_Cond->RestoreState(pj, bMain);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// routine pour savoir si le catch est <20> faire ou non
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotCatch :: TestCatch(CBotStack* &pile, int val)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !m_Cond->Execute(pile) ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// 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());
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotThrow* inst = new CBotThrow(); // cr<63>e l'objet
|
2012-03-08 18:32:05 +00:00
|
|
|
|
inst->SetToken(p);
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
CBotToken* pp = p; // conserve le ^au token (position d<>but)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
if (!IsOfType(p, ID_THROW)) return NULL; // ne devrait jamais arriver
|
|
|
|
|
|
|
|
|
|
inst->m_Value = CBotExpression::Compile( p, pStack );
|
|
|
|
|
|
|
|
|
|
if (pStack->GivType() < CBotTypLong && pStack->IsOk())
|
|
|
|
|
{
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return inst; // rend l'objet <20> qui le demande
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
pStack->SetError(TX_BADTYPE, pp);
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
delete inst; // erreur, lib<69>re la place
|
2012-03-08 18:32:05 +00:00
|
|
|
|
return NULL; // pas d'objet, l'erreur est sur la pile
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute l'instruction "throw"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotThrow :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
CBotStack* pile = pj->AddStack(this);
|
2012-07-04 20:14:28 +00:00
|
|
|
|
// if ( pile == EOX ) return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
if ( pile->GivState() == 0 )
|
|
|
|
|
{
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( !m_Value->Execute(pile) ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
pile->IncState();
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
if ( pile->IfStep() ) return false;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
int val = pile->GivVal();
|
|
|
|
|
if ( val < 0 ) val = TX_BADTHROW;
|
|
|
|
|
pile->SetError( val, &m_token );
|
|
|
|
|
return pj->Return( pile );
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
void CBotThrow :: RestoreState(CBotStack* &pj, bool bMain)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
return new CBotStartDebugDD(); // cr<63>e l'objet
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-19 11:44:39 +00:00
|
|
|
|
// ex<65>cute l'instruction "throw"
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
bool CBotStartDebugDD :: Execute(CBotStack* &pj)
|
2012-03-08 18:32:05 +00:00
|
|
|
|
{
|
|
|
|
|
CBotProgram* p = pj->GivBotCall();
|
2012-07-04 20:14:28 +00:00
|
|
|
|
p->m_bDebugDD = true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
|
2012-07-04 20:14:28 +00:00
|
|
|
|
return true;
|
2012-03-08 18:32:05 +00:00
|
|
|
|
}
|
|
|
|
|
|