Fix and improve switch...case (#1008)
parent
1058a326ad
commit
5f089f4a9b
|
@ -1798,6 +1798,9 @@ msgstr ""
|
|||
msgid "Empty character constant"
|
||||
msgstr ""
|
||||
|
||||
msgid "Duplicate label in switch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dividing by zero"
|
||||
msgstr ""
|
||||
|
||||
|
|
3
po/cs.po
3
po/cs.po
|
@ -489,6 +489,9 @@ msgstr "Dolů (\\key gdown;)"
|
|||
msgid "Drawer bot"
|
||||
msgstr "Tužkobot"
|
||||
|
||||
msgid "Duplicate label in switch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||
msgstr "Prach\\Prach a špína na robotech a budovách"
|
||||
|
||||
|
|
3
po/de.po
3
po/de.po
|
@ -490,6 +490,9 @@ msgstr "Sinkt (\\key gdown;)"
|
|||
msgid "Drawer bot"
|
||||
msgstr "Zeichner"
|
||||
|
||||
msgid "Duplicate label in switch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||
msgstr "Schmutz\\Schmutz auf Robotern und Bauten"
|
||||
|
||||
|
|
3
po/fr.po
3
po/fr.po
|
@ -492,6 +492,9 @@ msgstr "Descend (\\key gdown;)"
|
|||
msgid "Drawer bot"
|
||||
msgstr "Robot dessinateur"
|
||||
|
||||
msgid "Duplicate label in switch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||
msgstr "Salissures\\Salissures des robots et bâtiments"
|
||||
|
||||
|
|
3
po/pl.po
3
po/pl.po
|
@ -488,6 +488,9 @@ msgstr "Dół (\\key gdown;)"
|
|||
msgid "Drawer bot"
|
||||
msgstr "Robot rysownik"
|
||||
|
||||
msgid "Duplicate label in switch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||
msgstr "Kurz\\Kurz i bród na robotach i budynkach"
|
||||
|
||||
|
|
3
po/pt.po
3
po/pt.po
|
@ -487,6 +487,9 @@ msgstr "Baixo (\\key gdown;)"
|
|||
msgid "Drawer bot"
|
||||
msgstr "Robô cartoonista"
|
||||
|
||||
msgid "Duplicate label in switch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||
msgstr "Poeira\\Poeira e sujeira nos robôs e prédios"
|
||||
|
||||
|
|
3
po/ru.po
3
po/ru.po
|
@ -496,6 +496,9 @@ msgstr "Вниз (\\key gdown;)"
|
|||
msgid "Drawer bot"
|
||||
msgstr "Рисовальщик"
|
||||
|
||||
msgid "Duplicate label in switch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dust\\Dust and dirt on bots and buildings"
|
||||
msgstr "Пыль\\Пыль и грязь на ботах и зданиях"
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ enum CBotError : int
|
|||
CBotErrHexRange = 5053, //!< hex value out of range
|
||||
CBotErrUnicodeName = 5054, //!< invalid universal character name
|
||||
CBotErrCharEmpty = 5055, //!< empty character constant
|
||||
CBotErrRedefCase = 5056, //!< duplicate label in switch
|
||||
|
||||
// Runtime errors
|
||||
CBotErrZeroDiv = 6000, //!< division by zero
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "CBot/CBotInstr/CBotCase.h"
|
||||
|
||||
#include "CBot/CBotInstr/CBotExprLitNum.h"
|
||||
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
|
||||
|
||||
#include "CBot/CBotStack.h"
|
||||
#include "CBot/CBotCStack.h"
|
||||
|
@ -30,69 +30,107 @@ namespace CBot
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotCase::CBotCase()
|
||||
{
|
||||
m_value = nullptr;
|
||||
m_instr = nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotCase::~CBotCase()
|
||||
{
|
||||
delete m_value;
|
||||
delete m_instr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||
CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map<long, CBotInstr*>& labels)
|
||||
{
|
||||
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 nullptr; // should never happen
|
||||
pStack->SetStartError(pp->GetStart());
|
||||
|
||||
if ( pp->GetType() == ID_CASE )
|
||||
long labelValue = 0;
|
||||
|
||||
if (pp->GetType() == ID_CASE)
|
||||
{
|
||||
pp = p;
|
||||
inst->m_value = CBot::CompileExprLitNum(p, pStack);
|
||||
if (inst->m_value == nullptr )
|
||||
CBotInstr* i = nullptr;
|
||||
if (nullptr != (i = CBotTwoOpExpr::Compile(p, pStack, nullptr, true)))
|
||||
{
|
||||
pStack->SetError( CBotErrBadNum, pp );
|
||||
delete inst;
|
||||
return nullptr;
|
||||
if (pStack->GetType() <= CBotTypLong)
|
||||
{
|
||||
CBotStack* pile = CBotStack::AllocateStack();
|
||||
while ( !i->Execute(pile) );
|
||||
labelValue = pile->GetVar()->GetValLong();
|
||||
pile->Delete();
|
||||
|
||||
if (labels.count(labelValue) > 0)
|
||||
{
|
||||
pStack->SetError(CBotErrRedefCase, p->GetStart());
|
||||
}
|
||||
}
|
||||
else
|
||||
pStack->SetError(CBotErrBadNum, p->GetStart());
|
||||
delete i;
|
||||
}
|
||||
}
|
||||
if ( !IsOfType( p, ID_DOTS ))
|
||||
{
|
||||
pStack->SetError( CBotErrNoDoubleDots, p->GetStart() );
|
||||
delete inst;
|
||||
return nullptr;
|
||||
else
|
||||
pStack->SetError(CBotErrBadNum, p->GetStart());
|
||||
}
|
||||
|
||||
return inst;
|
||||
if (pStack->IsOk() && IsOfType(p, ID_DOTS))
|
||||
{
|
||||
CBotCase* newCase = new CBotCase();
|
||||
newCase->SetToken(pp);
|
||||
if (pp->GetType() == ID_CASE)
|
||||
labels[labelValue] = newCase;
|
||||
return newCase;
|
||||
}
|
||||
|
||||
pStack->SetError(CBotErrNoDoubleDots, p->GetStart());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotCase::Execute(CBotStack* &pj)
|
||||
{
|
||||
return true; // the "case" statement does nothing!
|
||||
if (m_instr == nullptr) return true;
|
||||
CBotStack* pile = pj->AddStack(this, CBotStack::BlockVisibilityType::BLOCK);
|
||||
|
||||
int state = pile->GetState();
|
||||
CBotInstr* p = m_instr;
|
||||
while (state-- > 0) p = p->GetNext();
|
||||
|
||||
while (p != nullptr)
|
||||
{
|
||||
if (!p->Execute(pile)) return false;
|
||||
pile->IncState();
|
||||
p = p->GetNext();
|
||||
}
|
||||
|
||||
pile->Delete();
|
||||
return pj->IsOk();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
|
||||
{
|
||||
}
|
||||
if (!bMain) return;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotCase::CompCase(CBotStack* &pile, int val)
|
||||
{
|
||||
if (m_value == nullptr ) return true; // "default" case
|
||||
CBotStack* pile = pj->RestoreStack(this);
|
||||
if (pile == nullptr) return;
|
||||
|
||||
while (!m_value->Execute(pile)); // puts the value on the correspondent stack (without interruption)
|
||||
return (pile->GetVal() == val); // compared with the given value
|
||||
CBotInstr* p = m_instr;
|
||||
|
||||
int state = pile->GetState();
|
||||
while (p != nullptr && state-- > 0)
|
||||
{
|
||||
p->RestoreState(pile, bMain);
|
||||
p = p->GetNext();
|
||||
}
|
||||
|
||||
if (p != nullptr) p->RestoreState(pile, bMain);
|
||||
}
|
||||
|
||||
std::map<std::string, CBotInstr*> CBotCase::GetDebugLinks()
|
||||
{
|
||||
auto links = CBotInstr::GetDebugLinks();
|
||||
links["m_value"] = m_value;
|
||||
links["m_instr"] = m_instr;
|
||||
return links;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include "CBot/CBotInstr/CBotInstr.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace CBot
|
||||
{
|
||||
|
||||
|
@ -42,7 +44,7 @@ public:
|
|||
* \param pStack
|
||||
* \return
|
||||
*/
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map<long, CBotInstr*>& labels);
|
||||
|
||||
/*!
|
||||
* \brief Execute Execution of instruction "case".
|
||||
|
@ -58,22 +60,15 @@ public:
|
|||
*/
|
||||
void RestoreState(CBotStack* &pj, bool bMain) override;
|
||||
|
||||
/*!
|
||||
* \brief CompCase Routine to find the entry point of "case" corresponding
|
||||
* to the value seen.
|
||||
* \param pj
|
||||
* \param val
|
||||
* \return
|
||||
*/
|
||||
bool CompCase(CBotStack* &pj, int val) override;
|
||||
|
||||
protected:
|
||||
virtual const std::string GetDebugName() override { return "CBotCase"; }
|
||||
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;
|
||||
|
||||
private:
|
||||
//! Value to compare.
|
||||
CBotInstr* m_value;
|
||||
//! List of instructions after case label
|
||||
CBotInstr* m_instr;
|
||||
|
||||
friend class CBotSwitch;
|
||||
};
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -40,8 +40,7 @@ CBotExprUnaire::~CBotExprUnaire()
|
|||
delete m_expr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral)
|
||||
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral, bool bConstExpr)
|
||||
{
|
||||
int op = p->GetType();
|
||||
CBotToken* pp = p;
|
||||
|
@ -52,8 +51,10 @@ CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLite
|
|||
CBotExprUnaire* inst = new CBotExprUnaire();
|
||||
inst->SetToken(pp);
|
||||
|
||||
if (!bLiteral) inst->m_expr = CBotParExpr::Compile(p, pStk);
|
||||
else inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk);
|
||||
if (bConstExpr || !bLiteral)
|
||||
inst->m_expr = CBotParExpr::Compile(p, pStk, bConstExpr);
|
||||
else
|
||||
inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk);
|
||||
|
||||
if (inst->m_expr != nullptr)
|
||||
{
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
* \param bLiteral If true, compiles only literal expressions Ex: ~11, -4.0, !false, not true
|
||||
* \return The compiled instruction or nullptr
|
||||
*/
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false);
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false, bool bConstExpr = false);
|
||||
|
||||
/*!
|
||||
* \brief Execute
|
||||
|
|
|
@ -317,13 +317,6 @@ void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain)
|
|||
assert(0); // dad do not know, see the girls
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotInstr::CompCase(CBotStack* &pj, int val)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first)
|
||||
{
|
||||
if (IsOfType(p, ID_OPBRK))
|
||||
|
|
|
@ -191,17 +191,6 @@ public:
|
|||
virtual void RestoreStateVar(CBotStack* &pile,
|
||||
bool bMain);
|
||||
|
||||
/**
|
||||
* \brief CompCase This routine is defined only for the subclass CBotCase
|
||||
* this allows to make the call on all instructions CompCase to see if it's
|
||||
* a case to the desired value..
|
||||
* \param pj
|
||||
* \param val
|
||||
* \return
|
||||
*/
|
||||
virtual bool CompCase(CBotStack* &pj,
|
||||
int val);
|
||||
|
||||
/**
|
||||
* \brief SetToken Set the token corresponding to the instruction.
|
||||
* \param p
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "CBot/CBotInstr/CBotNew.h"
|
||||
#include "CBot/CBotInstr/CBotPostIncExpr.h"
|
||||
#include "CBot/CBotInstr/CBotPreIncExpr.h"
|
||||
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
|
||||
|
||||
#include "CBot/CBotVar/CBotVar.h"
|
||||
|
||||
|
@ -40,13 +41,15 @@
|
|||
namespace CBot
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||
CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack, bool bConstExpr)
|
||||
{
|
||||
CBotCStack* pStk = pStack->TokenStack();
|
||||
|
||||
pStk->SetStartError(p->GetStart());
|
||||
|
||||
if (bConstExpr)
|
||||
return CBotParExpr::CompileConstExpr(p, pStack);
|
||||
|
||||
// is it an expression in parentheses?
|
||||
if (IsOfType(p, ID_OPENPAR))
|
||||
{
|
||||
|
@ -224,4 +227,55 @@ CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack)
|
|||
return pStack->Return(nullptr, pStk);
|
||||
}
|
||||
|
||||
CBotInstr* CBotParExpr::CompileConstExpr(CBotToken* &p, CBotCStack* pStack)
|
||||
{
|
||||
CBotCStack* pStk = pStack->TokenStack();
|
||||
|
||||
// is it an expression in parentheses?
|
||||
if (IsOfType(p, ID_OPENPAR))
|
||||
{
|
||||
CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStk, nullptr, true);
|
||||
|
||||
if (nullptr != inst)
|
||||
{
|
||||
if (IsOfType(p, ID_CLOSEPAR))
|
||||
{
|
||||
return pStack->Return(inst, pStk);
|
||||
}
|
||||
pStk->SetError(CBotErrClosePar, p->GetStart());
|
||||
}
|
||||
delete inst;
|
||||
return pStack->Return(nullptr, pStk);
|
||||
}
|
||||
|
||||
// is this a unary operation?
|
||||
CBotInstr* inst = CBotExprUnaire::Compile(p, pStk, true, true);
|
||||
if (inst != nullptr || !pStk->IsOk())
|
||||
return pStack->Return(inst, pStk);
|
||||
|
||||
// is it a number or DefineNum?
|
||||
if (p->GetType() == TokenTypNum ||
|
||||
p->GetType() == TokenTypDef )
|
||||
{
|
||||
CBotInstr* inst = CBot::CompileExprLitNum(p, pStk);
|
||||
return pStack->Return(inst, pStk);
|
||||
}
|
||||
|
||||
// is this a character?
|
||||
if (p->GetType() == TokenTypChar)
|
||||
{
|
||||
CBotInstr* inst = CBotExprLitChar::Compile(p, pStk);
|
||||
return pStack->Return(inst, pStk);
|
||||
}
|
||||
|
||||
// is it sizeof operator ?
|
||||
inst = CBot::CompileSizeOf(p, pStk);
|
||||
if (inst != nullptr || !pStk->IsOk())
|
||||
{
|
||||
return pStack->Return(inst, pStk);
|
||||
}
|
||||
|
||||
return pStack->Return(nullptr, pStk);
|
||||
}
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
* \param pStack
|
||||
* \return
|
||||
*/
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bConstExpr = false);
|
||||
|
||||
/*!
|
||||
* \brief Compile a literal expression ("string", number, true, false, null, nan, new)
|
||||
|
@ -62,6 +62,8 @@ public:
|
|||
*/
|
||||
static CBotInstr* CompileLitExpr(CBotToken* &p, CBotCStack* pStack);
|
||||
|
||||
static CBotInstr* CompileConstExpr(CBotToken* &p, CBotCStack* pStack);
|
||||
|
||||
private:
|
||||
CBotParExpr() = delete;
|
||||
CBotParExpr(const CBotParExpr&) = delete;
|
||||
|
|
|
@ -57,7 +57,7 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
{
|
||||
if ( nullptr != (inst->m_value = CBotExpression::Compile(p, pStk )) )
|
||||
{
|
||||
if ( pStk->GetType() < CBotTypLong )
|
||||
if ( pStk->GetType() <= CBotTypLong )
|
||||
{
|
||||
if ( IsOfType(p, ID_CLOSEPAR ) )
|
||||
{
|
||||
|
@ -65,21 +65,35 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
{
|
||||
IncLvl();
|
||||
|
||||
CBotCase* caseInst = nullptr;
|
||||
CBotCStack* pStk2 = nullptr;
|
||||
while( !IsOfType( p, ID_CLBLK ) )
|
||||
{
|
||||
if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT)
|
||||
{
|
||||
CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp
|
||||
delete pStk2;
|
||||
pStk2 = pStk->TokenStack(p, true); // un petit bout de pile svp
|
||||
|
||||
CBotInstr* i = CBotCase::Compile( p, pStk2 );
|
||||
if (i == nullptr)
|
||||
caseInst = static_cast<CBotCase*>(CBotCase::Compile(p, pStk2, inst->m_labels));
|
||||
if (caseInst == nullptr)
|
||||
{
|
||||
delete inst;
|
||||
return pStack->Return(nullptr, pStk2);
|
||||
}
|
||||
delete pStk2;
|
||||
if (inst->m_block == nullptr ) inst->m_block = i;
|
||||
else inst->m_block->AddNext(i);
|
||||
|
||||
if (inst->m_block == nullptr ) inst->m_block = caseInst;
|
||||
else inst->m_block->AddNext(caseInst);
|
||||
|
||||
if (ID_DEFAULT == caseInst->GetTokenType())
|
||||
{
|
||||
if (inst->m_default != nullptr)
|
||||
{
|
||||
pStk->SetError(CBotErrRedefCase, caseInst->GetToken());
|
||||
delete inst;
|
||||
return pStack->Return(nullptr, pStk);
|
||||
}
|
||||
inst->m_default = caseInst;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -90,13 +104,14 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
return pStack->Return(nullptr, pStk);
|
||||
}
|
||||
|
||||
CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true );
|
||||
if ( !pStk->IsOk() )
|
||||
CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk2);
|
||||
if ( !pStk2->IsOk() )
|
||||
{
|
||||
delete inst;
|
||||
return pStack->Return(nullptr, pStk);
|
||||
return pStack->Return(nullptr, pStk2);
|
||||
}
|
||||
inst->m_block->AddNext(i);
|
||||
if (caseInst->m_instr == nullptr ) caseInst->m_instr = i;
|
||||
else caseInst->m_instr->AddNext(i);
|
||||
|
||||
if ( p == nullptr )
|
||||
{
|
||||
|
@ -133,40 +148,21 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
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->GetState();
|
||||
if (state == 0)
|
||||
{
|
||||
if ( !m_value->Execute(pile1) ) return false;
|
||||
pile1->SetState(state = -1);
|
||||
pile1->SetState(state = 1);
|
||||
}
|
||||
|
||||
if ( pile1->IfStep() ) return false;
|
||||
|
||||
if ( state == -1 )
|
||||
{
|
||||
state = 0;
|
||||
int val = pile1->GetVal(); // result of the value
|
||||
auto it = m_labels.find(pile1->GetVar()->GetValLong());
|
||||
|
||||
CBotStack* pile2 = pile1->AddStack();
|
||||
while ( p != nullptr ) // search for the corresponding case in a list
|
||||
{
|
||||
state++;
|
||||
if ( p->CompCase( pile2, val ) ) break; // found the case
|
||||
p = p->GetNext();
|
||||
}
|
||||
pile2->Delete();
|
||||
CBotInstr* p = (it != m_labels.end()) ? it->second : m_default;
|
||||
|
||||
if ( p == nullptr ) 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->GetNext(); // advance in the list
|
||||
while (--state > 0) p = p->GetNext();
|
||||
|
||||
while( p != nullptr )
|
||||
{
|
||||
|
@ -185,8 +181,6 @@ void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
|
|||
CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack
|
||||
if ( pile1 == nullptr ) return;
|
||||
|
||||
CBotInstr* p = m_block; // first expression
|
||||
|
||||
int state = pile1->GetState();
|
||||
if (state == 0)
|
||||
{
|
||||
|
@ -194,13 +188,11 @@ void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
|
|||
return;
|
||||
}
|
||||
|
||||
if ( state == -1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto it = m_labels.find(pile1->GetVar()->GetValLong());
|
||||
|
||||
// p = m_block; // returns to the beginning
|
||||
while ( p != nullptr && state-- > 0 )
|
||||
CBotInstr* p = (it != m_labels.end()) ? it->second : m_default;
|
||||
|
||||
while (p != nullptr && --state > 0)
|
||||
{
|
||||
p->RestoreState(pile1, false);
|
||||
p = p->GetNext(); // advance in the list
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include "CBot/CBotInstr/CBotInstr.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace CBot
|
||||
{
|
||||
|
||||
|
@ -64,8 +66,12 @@ protected:
|
|||
private:
|
||||
//! Value to seek
|
||||
CBotInstr* m_value;
|
||||
//! Instructions
|
||||
CBotInstr* m_block;
|
||||
//! List of case instructions
|
||||
CBotInstr* m_block = nullptr;
|
||||
//! Pointer to default label
|
||||
CBotInstr* m_default = nullptr;
|
||||
//! Map of case labels
|
||||
std::unordered_map<long, CBotInstr*> m_labels;
|
||||
};
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -133,8 +133,7 @@ static bool TypeOk(int type, int test)
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations)
|
||||
CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations, bool bConstExpr)
|
||||
{
|
||||
int typeMask;
|
||||
|
||||
|
@ -146,8 +145,8 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
|||
|
||||
// search the intructions that may be suitable to the left of the operation
|
||||
CBotInstr* left = (*pOp == 0) ?
|
||||
CBotParExpr::Compile( p, pStk ) : // expression (...) left
|
||||
CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B left
|
||||
CBotParExpr::Compile(p, pStk, bConstExpr) : // expression (...) left
|
||||
CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr); // expression A * B left
|
||||
|
||||
if (left == nullptr) return pStack->Return(nullptr, pStk); // if error, transmit
|
||||
|
||||
|
@ -158,7 +157,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
|||
CBotTypResult type1, type2;
|
||||
type1 = pStk->GetTypResult(); // what kind of the first operand?
|
||||
|
||||
if (typeOp == ID_LOGIC) // special case provided for: ? op1: op2;
|
||||
if (!bConstExpr && typeOp == ID_LOGIC) // special case provided for: ? op1: op2;
|
||||
{
|
||||
if ( !type1.Eq(CBotTypBoolean) )
|
||||
{
|
||||
|
@ -207,7 +206,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
|||
|
||||
// looking statements that may be suitable for right
|
||||
|
||||
if ( nullptr != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) )
|
||||
if ( nullptr != (inst->m_rightop = CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr)) )
|
||||
// expression (...) right
|
||||
{
|
||||
// there is an second operand acceptable
|
||||
|
@ -264,7 +263,7 @@ CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOpera
|
|||
type1 = TypeRes;
|
||||
|
||||
p = p->GetNext(); // advance after
|
||||
i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp );
|
||||
i->m_rightop = CBotTwoOpExpr::Compile(p, pStk, pOp, bConstExpr);
|
||||
type2 = pStk->GetTypResult();
|
||||
|
||||
if ( !TypeCompatible (type1, type2, typeOp) ) // the results are compatible
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
* \param pOperations
|
||||
* \return
|
||||
*/
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = nullptr);
|
||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = nullptr, bool bConstExpr = false);
|
||||
|
||||
/*!
|
||||
* \brief Execute Performes the operation on two operands.
|
||||
|
|
|
@ -743,6 +743,7 @@ void InitializeRestext()
|
|||
stringsCbot[CBot::CBotErrHexRange] = TR("Hex value out of range");
|
||||
stringsCbot[CBot::CBotErrUnicodeName] = TR("Invalid universal character name");
|
||||
stringsCbot[CBot::CBotErrCharEmpty] = TR("Empty character constant");
|
||||
stringsCbot[CBot::CBotErrRedefCase] = TR("Duplicate label in switch");
|
||||
|
||||
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
|
||||
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");
|
||||
|
|
|
@ -640,6 +640,92 @@ TEST_F(CBotUT, BinaryLiterals)
|
|||
);
|
||||
}
|
||||
|
||||
TEST_F(CBotUT, TestSwitchCase)
|
||||
{
|
||||
ExecuteTest(
|
||||
"extern void Test_Switch_Case() {\n"
|
||||
" int n = 0, c = 0;\n"
|
||||
" for (int i = -9; i < 11; ++i) {\n"
|
||||
" switch (i) {\n"
|
||||
" case -9: n = -9; ++c; break;\n"
|
||||
" case -8: n = -8; ++c; break;\n"
|
||||
" case -7: n = -7; ++c; break;\n"
|
||||
" case -6: n = -6; ++c; break;\n"
|
||||
" case -5: n = -5; ++c; break;\n"
|
||||
" case -4: n = -4; ++c; break;\n"
|
||||
" case -3: n = -3; ++c; break;\n"
|
||||
" case -2: n = -2; ++c; break;\n"
|
||||
" case -1: n = -1; ++c; break;\n"
|
||||
" case 0: n = 0; ++c; break;\n"
|
||||
" case 1: n = 1; ++c; break;\n"
|
||||
" case 2: n = 2; ++c; break;\n"
|
||||
" case 3: n = 3; ++c; break;\n"
|
||||
" case 4: n = 4; ++c; break;\n"
|
||||
" case 5: n = 5; ++c; break;\n"
|
||||
" case 6: n = 6; ++c; break;\n"
|
||||
" case 7: n = 7; ++c; break;\n"
|
||||
" case 8: n = 8; ++c; break;\n"
|
||||
" case 9: n = 9; ++c; break;\n"
|
||||
" default: n = 10; ++c; break;\n"
|
||||
" }\n"
|
||||
" ASSERT(n == i);\n"
|
||||
" }\n"
|
||||
" ASSERT(n == 10);\n"
|
||||
" ASSERT(c == 20);\n"
|
||||
"}\n"
|
||||
"extern void Test_Case_With_Math() {\n"
|
||||
" int n = 0, c = 0;\n"
|
||||
" for (int i = -9; i < 11; ++i) {\n"
|
||||
" switch (i * 10) {\n"
|
||||
" case -9*10: n = -90; ++c; break;\n"
|
||||
" case -8*10: n = -80; ++c; break;\n"
|
||||
" case -7*10: n = -70; ++c; break;\n"
|
||||
" case -6*10: n = -60; ++c; break;\n"
|
||||
" case -5*10: n = -50; ++c; break;\n"
|
||||
" case -4*10: n = -40; ++c; break;\n"
|
||||
" case -3*10: n = -30; ++c; break;\n"
|
||||
" case -2*10: n = -20; ++c; break;\n"
|
||||
" case -1*10: n = -10; ++c; break;\n"
|
||||
" case 0*10: n = 0; ++c; break;\n"
|
||||
" case 1*10: n = 10; ++c; break;\n"
|
||||
" case 2*10: n = 20; ++c; break;\n"
|
||||
" case 3*10: n = 30; ++c; break;\n"
|
||||
" case 4*10: n = 40; ++c; break;\n"
|
||||
" case 5*10: n = 50; ++c; break;\n"
|
||||
" case 6*10: n = 60; ++c; break;\n"
|
||||
" case 7*10: n = 70; ++c; break;\n"
|
||||
" case 8*10: n = 80; ++c; break;\n"
|
||||
" case 9*10: n = 90; ++c; break;\n"
|
||||
" default: n = 100; ++c; break;\n"
|
||||
" }\n"
|
||||
" ASSERT(n == i * 10);\n"
|
||||
" }\n"
|
||||
" ASSERT(n == 100);\n"
|
||||
" ASSERT(c == 20);\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
ExecuteTest(
|
||||
"extern void Duplicate_Case() {\n"
|
||||
" switch(0) {\n"
|
||||
" case 1000:\n"
|
||||
" case 10*100:\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
CBotErrRedefCase
|
||||
);
|
||||
|
||||
ExecuteTest(
|
||||
"extern void Duplicate_Default() {\n"
|
||||
" switch(0) {\n"
|
||||
" default:\n"
|
||||
" default:\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
CBotErrRedefCase
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(CBotUT, ToString)
|
||||
{
|
||||
ExecuteTest(
|
||||
|
|
Loading…
Reference in New Issue