colobot/src/CBot/CBotStack.cpp

995 lines
30 KiB
C++
Raw Normal View History

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
2015-08-22 14:40:02 +00:00
* 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
*/
2012-08-08 00:01:06 +00:00
#include "CBot/CBotStack.h"
2012-08-08 00:01:06 +00:00
#include "CBot/CBotClass.h"
#include "CBot/CBotInstr/CBotFunction.h"
#include "CBot/CBotVar/CBotVarPointer.h"
#include "CBot/CBotVar/CBotVarClass.h"
#include "CBot/CBotUtils.h"
2015-12-31 13:44:19 +00:00
#include "CBot/CBotExternalCall.h"
2013-11-25 19:03:06 +00:00
#include <cassert>
2012-08-08 00:01:06 +00:00
#include <cstdlib>
#include <cstring>
2015-12-26 13:19:24 +00:00
namespace CBot
{
2015-12-31 16:59:48 +00:00
const int DEFAULT_TIMER = 100;
2012-08-08 00:01:06 +00:00
2015-12-31 16:59:48 +00:00
int CBotStack::m_initimer = DEFAULT_TIMER;
2012-08-08 00:01:06 +00:00
int CBotStack::m_timer = 0;
2015-08-16 10:43:42 +00:00
CBotVar* CBotStack::m_retvar = nullptr;
CBotError CBotStack::m_error = CBotNoErr;
2012-08-08 00:01:06 +00:00
int CBotStack::m_start = 0;
int CBotStack::m_end = 0;
std::string CBotStack::m_labelBreak="";
2015-08-16 10:43:42 +00:00
void* CBotStack::m_pUser = nullptr;
2012-08-08 00:01:06 +00:00
////////////////////////////////////////////////////////////////////////////////
2015-12-24 13:39:38 +00:00
CBotStack* CBotStack::AllocateStack()
2012-08-08 00:01:06 +00:00
{
CBotStack* p;
long size = sizeof(CBotStack);
size *= (MAXSTACK+10);
// request a slice of memory for the stack
p = static_cast<CBotStack*>(malloc(size));
2012-08-08 00:01:06 +00:00
// completely empty
memset(p, 0, size);
2015-12-31 16:59:48 +00:00
p->m_block = BlockVisibilityType::BLOCK;
2012-08-08 00:01:06 +00:00
CBotStack* pp = p;
pp += MAXSTACK;
int i;
for ( i = 0 ; i< 10 ; i++ )
{
pp->m_bOver = true;
pp ++;
}
m_error = CBotNoErr; // avoids deadlocks because m_error is static
2012-08-08 00:01:06 +00:00
return p;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotStack::Delete()
{
if (m_next != nullptr) m_next->Delete();
if (m_next2 != nullptr) m_next2->Delete();
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
if (m_prev != nullptr)
2012-08-08 00:01:06 +00:00
{
if ( m_prev->m_next == this )
2015-08-16 10:43:42 +00:00
m_prev->m_next = nullptr; // removes chain
2012-08-08 00:01:06 +00:00
if ( m_prev->m_next2 == this )
2015-08-16 10:43:42 +00:00
m_prev->m_next2 = nullptr; // removes chain
2012-08-08 00:01:06 +00:00
}
delete m_var;
delete m_listVar;
CBotStack* p = m_prev;
bool bOver = m_bOver;
// clears the freed block
memset(this, 0, sizeof(CBotStack));
m_bOver = bOver;
2015-08-16 10:43:42 +00:00
if ( p == nullptr )
2012-08-08 00:01:06 +00:00
free( this );
}
// routine improved
////////////////////////////////////////////////////////////////////////////////
2015-12-25 21:03:23 +00:00
CBotStack* CBotStack::AddStack(CBotInstr* instr, BlockVisibilityType bBlock)
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
if (m_next != nullptr)
2012-08-08 00:01:06 +00:00
{
return m_next; // included in an existing stack
}
CBotStack* p = this;
do
{
p ++;
}
2015-08-16 10:43:42 +00:00
while ( p->m_prev != nullptr );
2012-08-08 00:01:06 +00:00
m_next = p; // chain an element
2015-12-31 16:59:48 +00:00
p->m_block = bBlock;
p->m_instr = instr;
p->m_prog = m_prog;
p->m_step = 0;
p->m_prev = this;
p->m_state = 0;
p->m_call = nullptr;
p->m_func = IsFunction::NO;
p->m_callFinished = false;
return p;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2015-12-31 16:59:48 +00:00
CBotStack* CBotStack::AddStackExternalCall(CBotExternalCall* instr, BlockVisibilityType bBlock)
2012-08-08 00:01:06 +00:00
{
2015-12-31 16:59:48 +00:00
assert(!m_callFinished);
2015-08-16 10:43:42 +00:00
if (m_next != nullptr)
2012-08-08 00:01:06 +00:00
{
return m_next; // included in an existing stack
}
2015-08-16 10:43:42 +00:00
CBotStack* p = AddStack(nullptr, bBlock);
2012-08-08 00:01:06 +00:00
p->m_call = instr;
2015-12-31 16:59:48 +00:00
p->m_func = IsFunction::EXTERNAL_CALL;
2012-08-08 00:01:06 +00:00
return p;
}
////////////////////////////////////////////////////////////////////////////////
2015-12-25 21:03:23 +00:00
CBotStack* CBotStack::AddStack2(BlockVisibilityType bBlock)
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
if (m_next2 != nullptr)
2012-08-08 00:01:06 +00:00
{
m_next2->m_prog = m_prog; // special avoids RestoreStack2
return m_next2; // included in an existing stack
}
CBotStack* p = this;
do
{
p ++;
}
2015-08-16 10:43:42 +00:00
while ( p->m_prev != nullptr );
2012-08-08 00:01:06 +00:00
m_next2 = p; // chain an element
p->m_prev = this;
2015-12-31 16:59:48 +00:00
p->m_block = bBlock;
2012-08-08 00:01:06 +00:00
p->m_prog = m_prog;
p->m_step = 0;
return p;
}
////////////////////////////////////////////////////////////////////////////////
2015-12-25 21:03:23 +00:00
CBotStack::BlockVisibilityType CBotStack::GetBlock()
2012-08-08 00:01:06 +00:00
{
2015-12-31 16:59:48 +00:00
return m_block;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotStack::Return(CBotStack* pfils)
{
if ( pfils == this ) return true; // special
2015-08-16 10:43:42 +00:00
if (m_var != nullptr) delete m_var; // value replaced?
2012-08-08 00:01:06 +00:00
m_var = pfils->m_var; // result transmitted
2015-08-16 10:43:42 +00:00
pfils->m_var = nullptr; // not to destroy the variable
2012-08-08 00:01:06 +00:00
if (m_next != nullptr)
{
// releases the stack above
m_next->Delete();
m_next = nullptr;
}
if (m_next2 != nullptr)
{
// also the second stack (catch)
m_next2->Delete();
m_next2 = nullptr;
}
2012-08-08 00:01:06 +00:00
2015-12-25 19:47:30 +00:00
return IsOk(); // interrupted if error
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotStack::ReturnKeep(CBotStack* pfils)
{
if ( pfils == this ) return true; // special
2015-08-16 10:43:42 +00:00
if (m_var != nullptr) delete m_var; // value replaced?
2012-08-08 00:01:06 +00:00
m_var = pfils->m_var; // result transmitted
2015-08-16 10:43:42 +00:00
pfils->m_var = nullptr; // not to destroy the variable
2012-08-08 00:01:06 +00:00
2015-12-25 19:47:30 +00:00
return IsOk(); // interrupted if error
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotStack::StackOver()
{
if (!m_bOver) return false;
2015-12-20 18:01:03 +00:00
m_error = CBotErrStackOver;
2012-08-08 00:01:06 +00:00
return true;
}
////////////////////////////////////////////////////////////////////////////////
2015-12-24 13:39:38 +00:00
void CBotStack::Reset()
2012-08-08 00:01:06 +00:00
{
2015-12-24 13:39:38 +00:00
m_timer = m_initimer; // resets the timer
m_error = CBotNoErr;
2012-08-08 00:01:06 +00:00
// m_start = 0;
// m_end = 0;
m_labelBreak.clear();
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotStack* CBotStack::RestoreStack(CBotInstr* instr)
{
2015-08-16 10:43:42 +00:00
if (m_next != nullptr)
2012-08-08 00:01:06 +00:00
{
m_next->m_instr = instr; // reset (if recovery after )
m_next->m_prog = m_prog;
return m_next; // included in an existing stack
}
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
CBotStack* CBotStack::RestoreStackEOX(CBotExternalCall* instr)
2012-08-08 00:01:06 +00:00
{
CBotStack* p = RestoreStack();
p->m_call = instr;
return p;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
// routine for execution step by step
bool CBotStack::IfStep()
{
if ( m_initimer > 0 || m_step++ > 0 ) return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name)
2012-08-08 00:01:06 +00:00
{
if ( m_error>=0 ) return false; // normal output
if ( m_error==CBotError(-3) ) return false; // normal output (return current)
2012-08-08 00:01:06 +00:00
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
2012-08-08 00:01:06 +00:00
return false; // it's not for me
m_error = CBotNoErr;
m_labelBreak.clear();
2012-08-08 00:01:06 +00:00
return Return(pfils);
}
////////////////////////////////////////////////////////////////////////////////
bool CBotStack::IfContinue(int state, const std::string& name)
2012-08-08 00:01:06 +00:00
{
if ( m_error != CBotError(-2) ) return false;
2012-08-08 00:01:06 +00:00
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
2012-08-08 00:01:06 +00:00
return false; // it's not for me
m_state = state; // where again?
m_error = CBotNoErr;
m_labelBreak.clear();
if (m_next != nullptr) m_next->Delete(); // purge above stack
2012-08-08 00:01:06 +00:00
return true;
}
////////////////////////////////////////////////////////////////////////////////
void CBotStack::SetBreak(int val, const std::string& name)
2012-08-08 00:01:06 +00:00
{
m_error = static_cast<CBotError>(-val); // reacts as an Exception
2012-08-08 00:01:06 +00:00
m_labelBreak = name;
if (val == 3) // for a return
{
m_retvar = m_var;
2015-08-16 10:43:42 +00:00
m_var = nullptr;
2012-08-08 00:01:06 +00:00
}
}
// gives on the stack value calculated by the last CBotReturn
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
bool CBotStack::GetRetVar(bool bRet)
2012-08-08 00:01:06 +00:00
{
if (m_error == CBotError(-3))
2012-08-08 00:01:06 +00:00
{
if ( m_var ) delete m_var;
m_var = m_retvar;
2015-08-16 10:43:42 +00:00
m_retvar = nullptr;
m_error = CBotNoErr;
2012-08-08 00:01:06 +00:00
return true;
}
return bRet; // interrupted by something other than return
}
////////////////////////////////////////////////////////////////////////////////
2015-12-24 13:39:38 +00:00
CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate)
2012-08-08 00:01:06 +00:00
{
CBotStack* p = this;
std::string name = pToken->GetString();
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
while (p != nullptr)
2012-08-08 00:01:06 +00:00
{
CBotVar* pp = p->m_listVar;
2015-08-16 10:43:42 +00:00
while ( pp != nullptr)
2012-08-08 00:01:06 +00:00
{
2012-08-11 18:59:35 +00:00
if (pp->GetName() == name)
2012-08-08 00:01:06 +00:00
{
if ( bUpdate )
2015-12-31 16:59:48 +00:00
pp->Update(m_pUser);
2012-08-08 00:01:06 +00:00
return pp;
}
pp = pp->m_next;
}
p = p->m_prev;
}
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
CBotVar* CBotStack::FindVar(const std::string& name)
2012-08-08 00:01:06 +00:00
{
CBotStack* p = this;
2015-08-16 10:43:42 +00:00
while (p != nullptr)
2012-08-08 00:01:06 +00:00
{
CBotVar* pp = p->m_listVar;
2015-08-16 10:43:42 +00:00
while ( pp != nullptr)
2012-08-08 00:01:06 +00:00
{
2012-08-11 18:59:35 +00:00
if (pp->GetName() == name)
2012-08-08 00:01:06 +00:00
{
return pp;
}
pp = pp->m_next;
}
p = p->m_prev;
}
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2015-12-24 13:39:38 +00:00
CBotVar* CBotStack::FindVar(long ident, bool bUpdate)
2012-08-08 00:01:06 +00:00
{
CBotStack* p = this;
2015-08-16 10:43:42 +00:00
while (p != nullptr)
2012-08-08 00:01:06 +00:00
{
CBotVar* pp = p->m_listVar;
2015-08-16 10:43:42 +00:00
while ( pp != nullptr)
2012-08-08 00:01:06 +00:00
{
2012-08-11 18:59:35 +00:00
if (pp->GetUniqNum() == ident)
2012-08-08 00:01:06 +00:00
{
if ( bUpdate )
2015-12-31 16:59:48 +00:00
pp->Update(m_pUser);
2012-08-08 00:01:06 +00:00
return pp;
}
pp = pp->m_next;
}
p = p->m_prev;
}
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2015-12-24 13:39:38 +00:00
CBotVar* CBotStack::FindVar(CBotToken& pToken, bool bUpdate)
2012-08-08 00:01:06 +00:00
{
CBotToken* pt = &pToken;
2015-12-24 13:39:38 +00:00
return FindVar(pt, bUpdate);
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
CBotVar* CBotStack::CopyVar(CBotToken& pToken, bool bUpdate)
2012-08-08 00:01:06 +00:00
{
CBotVar* pVar = FindVar(pToken, bUpdate);
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
if ( pVar == nullptr) return nullptr;
2012-08-08 00:01:06 +00:00
CBotVar* pCopy = CBotVar::Create(pVar);
pCopy->Copy(pVar);
return pCopy;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotStack::SetState(int n, int limite)
{
m_state = n;
2015-12-31 15:10:47 +00:00
m_timer--; // decrement the timer
2012-08-08 00:01:06 +00:00
return ( m_timer > limite ); // interrupted if timer pass
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotStack::IncState(int limite)
{
m_state++;
2015-12-31 15:10:47 +00:00
m_timer--; // decrement the timer
2012-08-08 00:01:06 +00:00
return ( m_timer > limite ); // interrupted if timer pass
}
////////////////////////////////////////////////////////////////////////////////
void CBotStack::SetError(CBotError n, CBotToken* token)
2012-08-08 00:01:06 +00:00
{
2015-12-25 21:03:23 +00:00
if (n != CBotNoErr && m_error != CBotNoErr) return; // does not change existing error
2012-08-08 00:01:06 +00:00
m_error = n;
2015-08-16 10:43:42 +00:00
if (token != nullptr)
2012-08-08 00:01:06 +00:00
{
2012-08-11 18:59:35 +00:00
m_start = token->GetStart();
m_end = token->GetEnd();
2012-08-08 00:01:06 +00:00
}
}
////////////////////////////////////////////////////////////////////////////////
void CBotStack::ResetError(CBotError n, int start, int end)
2012-08-08 00:01:06 +00:00
{
m_error = n;
m_start = start;
m_end = end;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotStack::SetPosError(CBotToken* token)
{
2012-08-11 18:59:35 +00:00
m_start = token->GetStart();
m_end = token->GetEnd();
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotStack::SetTimer(int n)
{
m_initimer = n;
}
2015-12-31 16:59:48 +00:00
int CBotStack::GetTimer()
{
return m_initimer;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotStack::Execute()
{
CBotExternalCall* instr = nullptr; // the most highest instruction
2012-08-08 00:01:06 +00:00
CBotStack* pile;
CBotStack* p = this;
2015-08-16 10:43:42 +00:00
while (p != nullptr)
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
if ( p->m_next2 != nullptr ) break;
if ( p->m_call != nullptr )
2012-08-08 00:01:06 +00:00
{
instr = p->m_call;
pile = p->m_prev ;
}
p = p->m_next;
}
2015-08-16 10:43:42 +00:00
if ( instr == nullptr ) return true; // normal execution request
2012-08-08 00:01:06 +00:00
2015-12-31 15:10:47 +00:00
if (!instr->Run(nullptr, pile)) return false; // resume interrupted execution
2012-08-08 00:01:06 +00:00
if (pile->m_next != nullptr) pile->m_next->Delete();
2012-08-08 00:01:06 +00:00
2015-12-31 16:59:48 +00:00
pile->m_callFinished = true;
2012-08-08 00:01:06 +00:00
return true;
}
// puts on the stack pointer to a variable
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotStack::SetVar( CBotVar* var )
{
if (m_var) delete m_var; // replacement of a variable
m_var = var;
}
// puts on the stack a copy of a variable
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotStack::SetCopyVar( CBotVar* var )
{
if (m_var) delete m_var; // replacement of a variable
2015-12-25 18:16:54 +00:00
m_var = CBotVar::Create("", var->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC));
2012-08-08 00:01:06 +00:00
m_var->Copy( var );
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotVar* CBotStack::GetVar()
2012-08-08 00:01:06 +00:00
{
return m_var;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
long CBotStack::GetVal()
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
if (m_var == nullptr) return 0;
2012-08-11 18:59:35 +00:00
return m_var->GetValInt();
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotStack::AddVar(CBotVar* pVar)
{
CBotStack* p = this;
// returns to the father element
2015-12-31 16:59:48 +00:00
while (p != nullptr && p->m_block == BlockVisibilityType::INSTRUCTION) p = p->m_prev;
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
if ( p == nullptr ) return;
2012-08-08 00:01:06 +00:00
CBotVar** pp = &p->m_listVar;
2015-08-16 10:43:42 +00:00
while ( *pp != nullptr ) pp = &(*pp)->m_next;
2012-08-08 00:01:06 +00:00
*pp = pVar; // added after
}
////////////////////////////////////////////////////////////////////////////////
2015-12-24 13:39:38 +00:00
void CBotStack::SetProgram(CBotProgram* p)
2012-08-08 00:01:06 +00:00
{
2015-12-31 16:59:48 +00:00
m_prog = p;
m_func = IsFunction::YES;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2015-12-25 19:47:30 +00:00
CBotProgram* CBotStack::GetProgram(bool bFirst)
2012-08-08 00:01:06 +00:00
{
if ( ! bFirst ) return m_prog;
CBotStack* p = this;
2015-08-16 10:43:42 +00:00
while ( p->m_prev != nullptr ) p = p->m_prev;
2012-08-08 00:01:06 +00:00
return p->m_prog;
}
////////////////////////////////////////////////////////////////////////////////
2015-12-24 13:39:38 +00:00
void* CBotStack::GetUserPtr()
2012-08-08 00:01:06 +00:00
{
return m_pUser;
}
2015-12-24 13:39:38 +00:00
void CBotStack::SetUserPtr(void* user)
{
m_pUser = user;
}
////////////////////////////////////////////////////////////////////////////////
2015-12-25 21:03:23 +00:00
bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, const CBotTypResult& rettype)
2012-08-08 00:01:06 +00:00
{
2015-12-26 13:37:36 +00:00
int res;
2012-08-08 00:01:06 +00:00
// first looks by the identifier
res = m_prog->GetExternalCalls()->DoCall(nullptr, nullptr, ppVar, this, rettype);
2015-12-26 13:37:36 +00:00
if (res >= 0) return res;
2012-08-08 00:01:06 +00:00
res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, "", ppVar, this, token);
2015-12-26 13:37:36 +00:00
if (res >= 0) return res;
2012-08-08 00:01:06 +00:00
// if not found (recompile?) seeks by name
nIdent = 0;
res = m_prog->GetExternalCalls()->DoCall(token, nullptr, ppVar, this, rettype);
2015-12-26 13:37:36 +00:00
if (res >= 0) return res;
2012-08-08 00:01:06 +00:00
res = CBotFunction::DoCall(m_prog, m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this, token);
2015-12-26 13:37:36 +00:00
if (res >= 0) return res;
2012-08-08 00:01:06 +00:00
2015-12-20 18:01:03 +00:00
SetError(CBotErrUndefFunc, token);
2012-08-08 00:01:06 +00:00
return true;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
{
2015-12-24 11:36:09 +00:00
if (m_next == nullptr) return;
2012-08-08 00:01:06 +00:00
if (m_prog->GetExternalCalls()->RestoreCall(token, nullptr, ppVar, this))
2015-12-24 11:36:09 +00:00
return;
CBotFunction::RestoreCall(m_prog->GetFunctions(), nIdent, token->GetString(), ppVar, this);
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2015-12-25 21:03:23 +00:00
void CBotStack::GetRunPos(std::string& functionName, int& start, int& end)
2012-08-08 00:01:06 +00:00
{
CBotProgram* prog = m_prog; // Current program
2015-08-16 10:43:42 +00:00
CBotInstr* funct = nullptr; // function found
CBotInstr* instr = nullptr; // the highest intruction
2012-08-08 00:01:06 +00:00
CBotStack* p = this;
2015-08-16 10:43:42 +00:00
while (p->m_next != nullptr)
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
if ( p->m_instr != nullptr ) instr = p->m_instr;
2015-12-31 16:59:48 +00:00
if (p->m_func == IsFunction::YES && p->m_instr != nullptr ) funct = p->m_instr;
if ( p->m_next->m_prog != prog ) break ;
2012-08-08 00:01:06 +00:00
if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
else p = p->m_next;
}
2015-08-16 10:43:42 +00:00
if ( p->m_instr != nullptr ) instr = p->m_instr;
2015-12-31 16:59:48 +00:00
if (p->m_func == IsFunction::YES && p->m_instr != nullptr ) funct = p->m_instr;
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
if ( funct == nullptr ) return;
2012-08-08 00:01:06 +00:00
2012-08-11 18:59:35 +00:00
CBotToken* t = funct->GetToken();
2015-12-25 21:03:23 +00:00
functionName = t->GetString();
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
// if ( p->m_instr != nullptr ) instr = p->m_instr;
2012-08-08 00:01:06 +00:00
2012-08-11 18:59:35 +00:00
t = instr->GetToken();
start = t->GetStart();
2014-10-07 20:28:32 +00:00
end = t->GetEnd();
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2015-12-25 21:03:23 +00:00
CBotVar* CBotStack::GetStackVars(std::string& functionName, int level)
2012-08-08 00:01:06 +00:00
{
CBotProgram* prog = m_prog; // current program
2015-12-25 21:03:23 +00:00
functionName = "";
2012-08-08 00:01:06 +00:00
// back the stack in the current module
CBotStack* p = this;
2015-08-16 10:43:42 +00:00
while (p->m_next != nullptr)
2012-08-08 00:01:06 +00:00
{
if ( p->m_next->m_prog != prog ) break ;
2012-08-08 00:01:06 +00:00
if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
else p = p->m_next;
}
// Now p is the highest element on the stack
2012-08-08 00:01:06 +00:00
// descends upon the elements of block
2015-12-31 16:59:48 +00:00
while ( p != nullptr && p->m_block == BlockVisibilityType::INSTRUCTION) p = p->m_prev;
// Now p is on the beggining of the top block (with local variables)
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
while ( p != nullptr && level++ < 0 )
2012-08-08 00:01:06 +00:00
{
p = p->m_prev;
2015-12-31 16:59:48 +00:00
while ( p != nullptr && p->m_block == BlockVisibilityType::INSTRUCTION) p = p->m_prev;
2012-08-08 00:01:06 +00:00
}
// Now p is on the block "level"
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
if ( p == nullptr ) return nullptr;
2012-08-08 00:01:06 +00:00
// search the name of the current function
CBotStack* pp = p;
2015-08-16 10:43:42 +00:00
while ( pp != nullptr )
2012-08-08 00:01:06 +00:00
{
2015-12-31 16:59:48 +00:00
if (pp->m_func == IsFunction::YES) break;
2012-08-08 00:01:06 +00:00
pp = pp->m_prev;
}
2015-08-16 10:43:42 +00:00
if ( pp == nullptr || pp->m_instr == nullptr ) return nullptr;
2012-08-08 00:01:06 +00:00
2012-08-11 18:59:35 +00:00
CBotToken* t = pp->m_instr->GetToken();
2015-12-25 21:03:23 +00:00
functionName = t->GetString();
2012-08-08 00:01:06 +00:00
return p->m_listVar;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotStack::SaveState(std::ostream &ostr)
2012-08-08 00:01:06 +00:00
{
2015-12-31 16:59:48 +00:00
if (m_next2 != nullptr)
{
if (!WriteWord(ostr, 2)) return false; // a marker of type (m_next2)
if (!m_next2->SaveState(ostr)) return false; // saves the next element
2015-12-31 16:59:48 +00:00
}
else
2012-08-08 00:01:06 +00:00
{
if (!WriteWord(ostr, 1)) return false; // a marker of type (m_next)
2012-08-08 00:01:06 +00:00
}
if (!WriteWord(ostr, static_cast<unsigned short>(m_block))) return false;
if (!WriteInt(ostr, m_state)) return false;
if (!WriteWord(ostr, 0)) return false; // for backwards combatibility (m_bDontDelete)
if (!WriteInt(ostr, m_step)) return false;
2015-12-31 16:59:48 +00:00
if (!SaveVars(ostr, m_var)) return false; // current result
if (!SaveVars(ostr, m_listVar)) return false; // local variables
2015-12-31 16:59:48 +00:00
if (m_next != nullptr)
2012-08-08 00:01:06 +00:00
{
if (!m_next->SaveState(ostr)) return false; // saves the next element
2012-08-08 00:01:06 +00:00
}
else
{
if (!WriteWord(ostr, 0)) return false; // 0 - CBotStack::SaveState terminator
2012-08-08 00:01:06 +00:00
}
2015-12-31 16:59:48 +00:00
return true;
}
bool SaveVars(std::ostream &ostr, CBotVar* pVar)
2015-12-31 16:59:48 +00:00
{
while (pVar != nullptr)
{
if (!pVar->Save0State(ostr)) return false; // common header
if (!pVar->Save1State(ostr)) return false; // saves the data
2012-08-08 00:01:06 +00:00
2015-12-31 16:59:48 +00:00
pVar = pVar->GetNext();
}
return WriteWord(ostr, 0); // 0 - CBot::SaveVars terminator
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
bool CBotStack::RestoreState(std::istream &istr, CBotStack* &pStack)
2012-08-08 00:01:06 +00:00
{
2015-12-31 16:59:48 +00:00
unsigned short w;
2012-08-08 00:01:06 +00:00
2017-01-16 18:00:01 +00:00
if (pStack != this) pStack = nullptr;
if (!ReadWord(istr, w)) return false;
if ( w == 0 ) return true; // 0 - CBotStack::SaveState terminator
2012-08-08 00:01:06 +00:00
2017-01-16 18:00:01 +00:00
if (pStack == nullptr) pStack = AddStack();
2012-08-08 00:01:06 +00:00
2015-12-31 16:59:48 +00:00
if ( w == 2 ) // 2 - m_next2
2012-08-08 00:01:06 +00:00
{
if (!pStack->RestoreState(istr, pStack->m_next2)) return false;
2012-08-08 00:01:06 +00:00
}
if (!ReadWord(istr, w)) return false;
2015-12-31 16:59:48 +00:00
pStack->m_block = static_cast<BlockVisibilityType>(w);
2012-08-08 00:01:06 +00:00
int state;
if (!ReadInt(istr, state)) return false;
pStack->SetState(state);
2012-08-08 00:01:06 +00:00
if (!ReadWord(istr, w)) return false; // backwards compatibility (m_bDontDelete)
2012-08-08 00:01:06 +00:00
if (!ReadInt(istr, state)) return false;
pStack->m_step = state;
2012-08-08 00:01:06 +00:00
if (!CBotVar::RestoreState(istr, pStack->m_var)) return false; // temp variable
if (!CBotVar::RestoreState(istr, pStack->m_listVar)) return false; // local variables
2012-08-08 00:01:06 +00:00
return pStack->RestoreState(istr, pStack->m_next);
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
bool CBotVar::Save0State(std::ostream &ostr)
{
if (!WriteWord(ostr, 100+static_cast<int>(m_mPrivate)))return false; // private variable?
if (!WriteWord(ostr, m_bStatic))return false; // static variable?
if (!WriteWord(ostr, m_type.GetType()))return false; // saves the type (always non-zero)
if (m_type.Eq(CBotTypPointer) && GetPointer() != nullptr)
{
if (GetPointer()->m_bConstructor) // constructor was called?
{
if (!WriteWord(ostr, (2000 + static_cast<unsigned short>(m_binit)) )) return false;
return WriteString(ostr, m_token->GetString()); // and variable name
}
}
if (!WriteWord(ostr, static_cast<unsigned short>(m_binit))) return false; // variable defined?
return WriteString(ostr, m_token->GetString()); // and variable name
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
bool CBotVar::RestoreState(std::istream &istr, CBotVar* &pVar)
2012-08-08 00:01:06 +00:00
{
unsigned short w, wi, prv, st;
delete pVar;
2015-08-16 10:43:42 +00:00
pVar = nullptr;
CBotVar* pNew = nullptr;
CBotVar* pPrev = nullptr;
2012-08-08 00:01:06 +00:00
while ( true ) // retrieves a list
{
if (!ReadWord(istr, w)) return false; // private or type?
if ( w == 0 ) return true; // 0 - CBot::SaveVars terminator
2012-08-08 00:01:06 +00:00
std::string defnum;
2012-08-08 00:01:06 +00:00
if ( w == 200 )
{
if (!ReadString(istr, defnum)) return false; // number with identifier
if (!ReadWord(istr, w)) return false; // type
2012-08-08 00:01:06 +00:00
}
prv = 100; st = 0;
if ( w >= 100 )
{
prv = w;
if (!ReadWord(istr, st)) return false; // static
if (!ReadWord(istr, w)) return false; // type
2012-08-08 00:01:06 +00:00
}
if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic
if (!ReadWord(istr, wi)) return false; // init ?
bool bConstructor = false;
if (w == CBotTypPointer && wi >= 2000)
{
wi -= 2000;
bConstructor = true;
}
2015-12-31 16:59:48 +00:00
CBotVar::InitType initType = static_cast<CBotVar::InitType>(wi);
std::string varname;
if (!ReadString(istr, varname)) return false; // variable name
CBotToken token(varname, std::string());
2012-08-08 00:01:06 +00:00
bool isClass = false;
2012-08-08 00:01:06 +00:00
switch (w)
{
case CBotTypBoolean:
char valBool;
if (!ReadByte(istr, valBool)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValInt(valBool);
break;
case CBotTypByte:
char valByte;
if (!ReadByte(istr, valByte)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValByte(valByte);
break;
case CBotTypShort:
short valShort;
if (!ReadShort(istr, valShort)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValShort(valShort);
break;
case CBotTypChar:
uint32_t valChar;
if (!ReadUInt32(istr, valChar)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValChar(valChar);
2012-08-08 00:01:06 +00:00
break;
case CBotTypInt:
int valInt;
if (!ReadInt(istr, valInt)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValInt(valInt, defnum);
2012-08-08 00:01:06 +00:00
break;
case CBotTypLong:
long valLong;
if (!ReadLong(istr, valLong)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValInt(valLong);
break;
case CBotTypFloat:
float valFloat;
if (!ReadFloat(istr, valFloat)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValFloat(valFloat);
2012-08-08 00:01:06 +00:00
break;
case CBotTypDouble:
double valDouble;
if (!ReadDouble(istr, valDouble)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValDouble(valDouble);
break;
case CBotTypString:
{
std::string valString;
if (!ReadString(istr, valString)) return false;
pNew = CBotVar::Create(token, w); // creates a variable
pNew->SetValString(valString);
break;
}
2012-08-08 00:01:06 +00:00
// returns an intrinsic object or element of an array
case CBotTypIntrinsic:
isClass = true;
2012-08-08 00:01:06 +00:00
case CBotTypArrayBody:
{
CBotTypResult r;
long id;
if (!ReadType(istr, r)) return false; // complete type
if (!ReadLong(istr, id)) return false;
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
CBotVar* p = nullptr;
2012-08-08 00:01:06 +00:00
if ( id ) p = CBotVarClass::Find(id) ;
pNew = new CBotVarClass(token, r); // directly creates an instance
2012-08-08 00:01:06 +00:00
// attention cptuse = 0
if (!RestoreState(istr, (static_cast<CBotVarClass*>(pNew))->m_pVar)) return false;
2012-08-08 00:01:06 +00:00
pNew->SetIdent(id);
if (isClass && p == nullptr) // set id for each item in this instance
{
CBotClass* pClass = pNew->GetClass();
CBotVar* pVars = (static_cast<CBotVarClass*>(pNew))->m_pVar;
while (pClass != nullptr && pVars != nullptr)
{
CBotVar* pv = pClass->GetVar();
while (pVars != nullptr && pv != nullptr)
{
pVars->m_ident = pv->m_ident;
pVars = pVars->m_next;
pv = pv->m_next;
}
pClass = pClass->GetParent();
}
}
2015-08-16 10:43:42 +00:00
if ( p != nullptr )
2012-08-08 00:01:06 +00:00
{
delete pNew;
pNew = p; // resume known element
2012-08-08 00:01:06 +00:00
}
}
}
break;
case CBotTypPointer:
case CBotTypNullPointer:
{
std::string className;
if (!ReadString(istr, className)) return false; // name of the class
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
// CBotVarClass* p = nullptr;
2012-08-08 00:01:06 +00:00
long id;
if (!ReadLong(istr, id)) return false;
2012-08-08 00:01:06 +00:00
// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance)
CBotTypResult ptrType(w, className);
pNew = CBotVar::Create(token, ptrType); // creates a variable
2012-08-08 00:01:06 +00:00
// returns a copy of the original instance
2015-08-16 10:43:42 +00:00
CBotVar* pInstance = nullptr;
if (!CBotVar::RestoreState(istr, pInstance)) return false;
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
2012-08-08 00:01:06 +00:00
if (bConstructor) pNew->ConstructorSet(); // constructor was called
if (ptrType.Eq(CBotTypPointer)) pNew->SetType(ptrType); // keep pointer type
2015-08-16 10:43:42 +00:00
// if ( p != nullptr ) (static_cast<CBotVarPointer*>(pNew))->SetPointer( p ); // rather this one
2012-08-08 00:01:06 +00:00
}
break;
}
2012-08-08 00:01:06 +00:00
case CBotTypArrayPointer:
{
CBotTypResult r;
if (!ReadType(istr, r)) return false;
2012-08-08 00:01:06 +00:00
pNew = CBotVar::Create(token, r); // creates a variable
2012-08-08 00:01:06 +00:00
// returns a copy of the original instance
2015-08-16 10:43:42 +00:00
CBotVar* pInstance = nullptr;
if (!CBotVar::RestoreState(istr, pInstance)) return false;
(static_cast<CBotVarPointer*>(pNew))->SetPointer( pInstance ); // and point over
2012-08-08 00:01:06 +00:00
}
break;
default:
return false; // signal error
2012-08-08 00:01:06 +00:00
}
2015-08-16 10:43:42 +00:00
if ( pPrev != nullptr ) pPrev->m_next = pNew;
if ( pVar == nullptr ) pVar = pNew;
2012-08-08 00:01:06 +00:00
pNew->m_binit = initType; // pNew->SetInit(wi);
2012-08-08 00:01:06 +00:00
pNew->SetStatic(st);
2015-12-21 22:07:40 +00:00
pNew->SetPrivate(static_cast<ProtectionLevel>(prv-100));
2012-08-08 00:01:06 +00:00
pPrev = pNew;
}
return true;
}
2015-12-26 13:19:24 +00:00
2015-12-31 16:59:48 +00:00
bool CBotStack::IsCallFinished()
{
return m_callFinished;
}
2015-12-26 13:19:24 +00:00
} // namespace CBot