Moving CBotExpression class in its own header and source files.

dev-time-step
Grunaka 2015-11-11 21:43:56 +01:00
parent d44df45d26
commit 3c1296b4b9
14 changed files with 386 additions and 289 deletions

View File

@ -58,6 +58,7 @@
#include "CBotInstr/CBotExprUnaire.h"
#include "CBotInstr/CBotBoolExpr.h"
#include "CBotInstr/CBotTwoOpExpr.h"
#include "CBotInstr/CBotExpression.h"
// Local include
@ -1345,276 +1346,6 @@ void CBotIString::RestoreState(CBotStack* &pj, bool bMain)
m_next2b->RestoreState(pile, bMain);
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
// compiles a statement such as " x = 123 " ou " z * 5 + 4 "
// with or without assignment
CBotExpression::CBotExpression()
{
m_leftop = nullptr;
m_rightop = nullptr;
name = "CBotExpression";
}
CBotExpression::~CBotExpression()
{
delete m_leftop;
delete m_rightop;
}
CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotToken* pp = p;
CBotExpression* inst = new CBotExpression();
inst->m_leftop = CBotLeftExpr::Compile(p, pStack);
inst->SetToken(p);
int OpType = p->GetType();
if ( pStack->IsOk() &&
IsOfTypeList(p, ID_ASS, ID_ASSADD, ID_ASSSUB, ID_ASSMUL, ID_ASSDIV, ID_ASSMODULO,
ID_ASSAND, ID_ASSXOR, ID_ASSOR,
ID_ASSSL , ID_ASSSR, ID_ASSASR, 0 ))
{
if (inst->m_leftop == nullptr)
{
pStack->SetError(TX_BADLEFT, p->GetEnd());
delete inst;
return nullptr;
}
inst->m_rightop = CBotExpression::Compile(p, pStack);
if (inst->m_rightop == nullptr)
{
delete inst;
return nullptr;
}
CBotTypResult type1 = pStack->GetTypResult();
// get the variable assigned to mark
CBotVar* var = nullptr;
inst->m_leftop->ExecuteVar(var, pStack);
if (var == nullptr)
{
delete inst;
return nullptr;
}
if (OpType != ID_ASS && !var->IsDefined())
{
pStack->SetError(TX_NOTINIT, pp);
delete inst;
return nullptr;
}
CBotTypResult type2 = var->GetTypResult();
// what types are acceptable?
switch (OpType)
{
case ID_ASS:
// if (type2 == CBotTypClass) type2 = -1;
if ((type1.Eq(CBotTypPointer) && type2.Eq(CBotTypPointer)) ||
(type1.Eq(CBotTypClass) && type2.Eq(CBotTypClass) ) )
{
/* CBotClass* c1 = type1.GetClass();
CBotClass* c2 = type2.GetClass();
if (!c1->IsChildOf(c2)) type2.SetType(-1);
//- if (!type1.Eq(CBotTypClass)) var->SetPointer(pStack->GetVar()->GetPointer());*/
var->SetInit(CBotVar::InitType::IS_POINTER);
}
else
var->SetInit(CBotVar::InitType::DEF);
break;
case ID_ASSADD:
if (type2.Eq(CBotTypBoolean) ||
type2.Eq(CBotTypPointer) ) type2 = -1; // numbers and strings
break;
case ID_ASSSUB:
case ID_ASSMUL:
case ID_ASSDIV:
case ID_ASSMODULO:
if (type2.GetType() >= CBotTypBoolean) type2 = -1; // numbers only
break;
}
if (!TypeCompatible(type1, type2, OpType))
{
pStack->SetError(TX_BADTYPE, &inst->m_token);
delete inst;
return nullptr;
}
return inst; // compatible type?
}
delete inst;
int start, end, error = pStack->GetError(start, end);
p = pp; // returns to the top
pStack->SetError(0,0); // forget the error
CBotInstr* i = CBotTwoOpExpr::Compile(p, pStack); // tries without assignment
if (i != nullptr && error == TX_PRIVATE && p->GetType() == ID_ASS)
pStack->ResetError(error, start, end);
return i;
}
// executes an expression with assignment
bool CBotExpression::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this);
// CBotToken* pToken = m_leftop->GetToken();
CBotVar* pVar = nullptr;
CBotStack* pile1 = pile;
CBotVar::InitType initKind = CBotVar::InitType::DEF;
CBotVar* result = nullptr;
// must be done before any indexes (stack can be changed)
if (!m_leftop->ExecuteVar(pVar, pile, nullptr, false)) return false; // variable before accessing the value on the right
if ( pile1->GetState()==0)
{
pile1->SetCopyVar(pVar); // keeps the copy on the stack (if interrupted)
pile1->IncState();
}
CBotStack* pile2 = pile->AddStack();
if ( pile2->GetState()==0)
{
if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted?
pile2->IncState();
}
if (pile1->GetState() == 1)
{
if (m_token.GetType() != ID_ASS)
{
pVar = pile1->GetVar(); // recovers if interrupted
initKind = pVar->GetInit();
if (initKind == CBotVar::InitType::IS_NAN)
{
pile2->SetError(TX_OPNAN, m_leftop->GetToken());
return pj->Return(pile2);
}
result = CBotVar::Create("", pVar->GetTypResult(2));
}
switch (m_token.GetType())
{
case ID_ASS:
break;
case ID_ASSADD:
result->Add(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSSUB:
result->Sub(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSMUL:
result->Mul(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSDIV:
if (initKind != CBotVar::InitType::UNDEF &&
result->Div(pile1->GetVar(), pile2->GetVar()))
pile2->SetError(TX_DIVZERO, &m_token);
pile2->SetVar(result);
break;
case ID_ASSMODULO:
if (initKind != CBotVar::InitType::UNDEF &&
result->Modulo(pile1->GetVar(), pile2->GetVar()))
pile2->SetError(TX_DIVZERO, &m_token);
pile2->SetVar(result);
break;
case ID_ASSAND:
result->And(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSXOR:
result->XOr(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSOR:
result->Or(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSSL:
result->SL(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSSR:
result->SR(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSASR:
result->ASR(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
default:
assert(0);
}
if (initKind == CBotVar::InitType::UNDEF)
pile2->SetError(TX_NOTINIT, m_leftop->GetToken());
pile1->IncState();
}
if (!m_leftop->Execute( pile2, pile1 ))
return false;
return pj->Return(pile2);
}
void CBotExpression::RestoreState(CBotStack* &pj, bool bMain)
{
if (bMain)
{
// CBotToken* pToken = m_leftop->GetToken();
// CBotVar* pVar = nullptr;
CBotStack* pile = pj->RestoreStack(this);
if (pile == nullptr) return;
CBotStack* pile1 = pile;
if ( pile1->GetState()==0)
{
m_leftop->RestoreStateVar(pile, true);
return;
}
m_leftop->RestoreStateVar(pile, false);
CBotStack* pile2 = pile->RestoreStack();
if (pile2 == nullptr) return;
if ( pile2->GetState()==0)
{
if (m_rightop) m_rightop->RestoreState(pile2, bMain);
return;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
// compile a statement such as "(condition)"

View File

@ -708,25 +708,6 @@ public:
void RestoreStateVar(CBotStack* &pj, bool bMain) override;
};
// expressions like
// x = a;
// x * y + 3;
class CBotExpression : public CBotInstr
{
private:
CBotLeftExpr* m_leftop; // left operand
CBotInstr* m_rightop; // right operant
public:
CBotExpression();
~CBotExpression();
static
CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
bool Execute(CBotStack* &pStack) override;
void RestoreState(CBotStack* &pj, bool bMain) override;
};
#define MAX(a,b) ((a>b) ? a : b)

View File

@ -25,6 +25,7 @@
#include "CBotInstr/CBotBlock.h"
#include "CBotInstr/CBotTwoOpExpr.h"
#include "CBotInstr/CBotExpression.h"
#include <cassert>

View File

@ -20,6 +20,7 @@
// Modules inlcude
#include "CBotCatch.h"
#include "CBotBlock.h"
#include "CBotExpression.h"
// Local include

View File

@ -20,6 +20,7 @@
// Modules inlcude
#include "CBotExprVar.h"
#include "CBotInstrMethode.h"
#include "CBotExpression.h"
// Local include

View File

@ -0,0 +1,290 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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://gnu.org/licenses
*/
// Modules inlcude
#include "CBotExpression.h"
#include "CBotTwoOpExpr.h"
// Local include
// Global include
#include <cassert>
//////////////////////////////////////////////////////////////////////////////////////
CBotExpression::CBotExpression()
{
m_leftop = nullptr;
m_rightop = nullptr;
name = "CBotExpression";
}
////////////////////////////////////////////////////////////////////////////////
CBotExpression::~CBotExpression()
{
delete m_leftop;
delete m_rightop;
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotToken* pp = p;
CBotExpression* inst = new CBotExpression();
inst->m_leftop = CBotLeftExpr::Compile(p, pStack);
inst->SetToken(p);
int OpType = p->GetType();
if ( pStack->IsOk() &&
IsOfTypeList(p, ID_ASS, ID_ASSADD, ID_ASSSUB, ID_ASSMUL, ID_ASSDIV, ID_ASSMODULO,
ID_ASSAND, ID_ASSXOR, ID_ASSOR,
ID_ASSSL , ID_ASSSR, ID_ASSASR, 0 ))
{
if (inst->m_leftop == nullptr)
{
pStack->SetError(TX_BADLEFT, p->GetEnd());
delete inst;
return nullptr;
}
inst->m_rightop = CBotExpression::Compile(p, pStack);
if (inst->m_rightop == nullptr)
{
delete inst;
return nullptr;
}
CBotTypResult type1 = pStack->GetTypResult();
// get the variable assigned to mark
CBotVar* var = nullptr;
inst->m_leftop->ExecuteVar(var, pStack);
if (var == nullptr)
{
delete inst;
return nullptr;
}
if (OpType != ID_ASS && !var->IsDefined())
{
pStack->SetError(TX_NOTINIT, pp);
delete inst;
return nullptr;
}
CBotTypResult type2 = var->GetTypResult();
// what types are acceptable?
switch (OpType)
{
case ID_ASS:
// if (type2 == CBotTypClass) type2 = -1;
if ((type1.Eq(CBotTypPointer) && type2.Eq(CBotTypPointer)) ||
(type1.Eq(CBotTypClass) && type2.Eq(CBotTypClass) ) )
{
/* CBotClass* c1 = type1.GetClass();
CBotClass* c2 = type2.GetClass();
if (!c1->IsChildOf(c2)) type2.SetType(-1);
//- if (!type1.Eq(CBotTypClass)) var->SetPointer(pStack->GetVar()->GetPointer());*/
var->SetInit(CBotVar::InitType::IS_POINTER);
}
else
var->SetInit(CBotVar::InitType::DEF);
break;
case ID_ASSADD:
if (type2.Eq(CBotTypBoolean) ||
type2.Eq(CBotTypPointer) ) type2 = -1; // numbers and strings
break;
case ID_ASSSUB:
case ID_ASSMUL:
case ID_ASSDIV:
case ID_ASSMODULO:
if (type2.GetType() >= CBotTypBoolean) type2 = -1; // numbers only
break;
}
if (!TypeCompatible(type1, type2, OpType))
{
pStack->SetError(TX_BADTYPE, &inst->m_token);
delete inst;
return nullptr;
}
return inst; // compatible type?
}
delete inst;
int start, end, error = pStack->GetError(start, end);
p = pp; // returns to the top
pStack->SetError(0,0); // forget the error
CBotInstr* i = CBotTwoOpExpr::Compile(p, pStack); // tries without assignment
if (i != nullptr && error == TX_PRIVATE && p->GetType() == ID_ASS)
pStack->ResetError(error, start, end);
return i;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotExpression::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this);
// CBotToken* pToken = m_leftop->GetToken();
CBotVar* pVar = nullptr;
CBotStack* pile1 = pile;
CBotVar::InitType initKind = CBotVar::InitType::DEF;
CBotVar* result = nullptr;
// must be done before any indexes (stack can be changed)
if (!m_leftop->ExecuteVar(pVar, pile, nullptr, false)) return false; // variable before accessing the value on the right
if ( pile1->GetState()==0)
{
pile1->SetCopyVar(pVar); // keeps the copy on the stack (if interrupted)
pile1->IncState();
}
CBotStack* pile2 = pile->AddStack();
if ( pile2->GetState()==0)
{
if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted?
pile2->IncState();
}
if (pile1->GetState() == 1)
{
if (m_token.GetType() != ID_ASS)
{
pVar = pile1->GetVar(); // recovers if interrupted
initKind = pVar->GetInit();
if (initKind == CBotVar::InitType::IS_NAN)
{
pile2->SetError(TX_OPNAN, m_leftop->GetToken());
return pj->Return(pile2);
}
result = CBotVar::Create("", pVar->GetTypResult(2));
}
switch (m_token.GetType())
{
case ID_ASS:
break;
case ID_ASSADD:
result->Add(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSSUB:
result->Sub(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSMUL:
result->Mul(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSDIV:
if (initKind != CBotVar::InitType::UNDEF &&
result->Div(pile1->GetVar(), pile2->GetVar()))
pile2->SetError(TX_DIVZERO, &m_token);
pile2->SetVar(result);
break;
case ID_ASSMODULO:
if (initKind != CBotVar::InitType::UNDEF &&
result->Modulo(pile1->GetVar(), pile2->GetVar()))
pile2->SetError(TX_DIVZERO, &m_token);
pile2->SetVar(result);
break;
case ID_ASSAND:
result->And(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSXOR:
result->XOr(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSOR:
result->Or(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSSL:
result->SL(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSSR:
result->SR(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
case ID_ASSASR:
result->ASR(pile1->GetVar(), pile2->GetVar());
pile2->SetVar(result);
break;
default:
assert(0);
}
if (initKind == CBotVar::InitType::UNDEF)
pile2->SetError(TX_NOTINIT, m_leftop->GetToken());
pile1->IncState();
}
if (!m_leftop->Execute( pile2, pile1 ))
return false;
return pj->Return(pile2);
}
////////////////////////////////////////////////////////////////////////////////
void CBotExpression::RestoreState(CBotStack* &pj, bool bMain)
{
if (bMain)
{
// CBotToken* pToken = m_leftop->GetToken();
// CBotVar* pVar = nullptr;
CBotStack* pile = pj->RestoreStack(this);
if (pile == nullptr) return;
CBotStack* pile1 = pile;
if ( pile1->GetState()==0)
{
m_leftop->RestoreStateVar(pile, true);
return;
}
m_leftop->RestoreStateVar(pile, false);
CBotStack* pile2 = pile->RestoreStack();
if (pile2 == nullptr) return;
if ( pile2->GetState()==0)
{
if (m_rightop) m_rightop->RestoreState(pile2, bMain);
return;
}
}
}

View File

@ -0,0 +1,85 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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://gnu.org/licenses
*/
#pragma once
// Modules inlcude
#include "CBot.h"
// Local include
// Global include
/*!
* \brief The CBotExpression class Compiles a statement with or without
* assignment.
* eg :
* - x = a;
* - x * y + 3;
* - x = 123
* - z * 5 + 4
*/
// compiles a statement such as " " ou " z * 5 + 4 "
//
class CBotExpression : public CBotInstr
{
public:
/*!
* \brief CBotExpression
*/
CBotExpression();
/*!
* \brief ~CBotExpression
*/
~CBotExpression();
/*!
* \brief Compile
* \param p
* \param pStack
* \return
*/
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
/*!
* \brief Execute Executes an expression with assignment.
* \param pStack
* \return
*/
bool Execute(CBotStack* &pStack) override;
/*!
* \brief RestoreState
* \param pj
* \param bMain
*/
void RestoreState(CBotStack* &pj, bool bMain) override;
private:
//! Left operand
CBotLeftExpr* m_leftop;
//! Right operand
CBotInstr* m_rightop;
};

View File

@ -19,6 +19,7 @@
// Modules inlcude
#include "CBotInstrCall.h"
#include "CBotExpression.h"
// Local include

View File

@ -19,6 +19,7 @@
// Modules inlcude
#include "CBotListExpression.h"
#include "CBotExpression.h"
// Local include

View File

@ -30,6 +30,7 @@
#include "CBotNew.h"
#include "CBotExprNull.h"
#include "CBotExprNan.h"
#include "CBotExpression.h"
// Local include

View File

@ -23,6 +23,7 @@
#include "CBotSwitch.h"
#include "CBotCase.h"
#include "CBotBlock.h"
#include "CBotExpression.h"
// Local include

View File

@ -19,6 +19,7 @@
// Modules inlcude
#include "CBotThrow.h"
#include "CBotExpression.h"
// Local include

View File

@ -21,6 +21,7 @@
#include "CBotTwoOpExpr.h"
#include "CBotParExpr.h"
#include "CBotLogicExpr.h"
#include "CBotExpression.h"
#include "CBot.h"
// Local include

View File

@ -37,6 +37,7 @@ set(SOURCES
CBotInstr/CBotBoolExpr.cpp
CBotInstr/CBotLogicExpr.cpp
CBotInstr/CBotTwoOpExpr.cpp
CBotInstr/CBotExpression.cpp
)
# Includes