Merged PR #737: Fix for various issues with initializing variables in CBOT

dev-time-step
krzys-h 2016-04-03 20:57:31 +02:00
commit 14721001e5
10 changed files with 175 additions and 83 deletions

View File

@ -19,6 +19,7 @@
#include "CBot/CBotClass.h"
#include "CBot/CBotInstr/CBotInstrUtils.h"
#include "CBot/CBotInstr/CBotNew.h"
#include "CBot/CBotInstr/CBotLeftExprVar.h"
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
@ -32,6 +33,7 @@
#include "CBot/CBotExternalCall.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotDefParam.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotFileUtils.h"
#include "CBot/CBotCallMethode.h"
@ -549,6 +551,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
while (pStack->IsOk())
{
CBotTypResult type2 = CBotTypResult(type); // reset type after comma
std::string pp = p->GetString();
if ( IsOfType(p, ID_NOT) )
{
@ -561,29 +564,27 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
while ( IsOfType( p, ID_OPBRK ) ) // a table?
{
CBotInstr* i = nullptr;
pStack->SetStartError( p->GetStart() );
if ( p->GetType() != ID_CLBRK )
{
i = CBotExpression::Compile( p, pStack ); // expression for the value
if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number
{
pStack->SetError(CBotErrBadIndex, p->GetStart());
return false;
}
}
else
i = new CBotEmpty(); // special if not a formula
type = CBotTypResult(CBotTypArrayPointer, type);
if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) )
{
pStack->SetError(CBotErrCloseIndex, p->GetStart());
return false;
}
/* CBotVar* pv = pStack->GetVar();
if ( pv->GetType()>= CBotTypBoolean )
{
pStack->SetError(CBotErrBadType1, p->GetStart());
return false;
}*/
type2 = CBotTypResult(CBotTypArrayPointer, type2);
if (limites == nullptr) limites = i;
else limites->AddNext3(i);
if (IsOfType(p, ID_CLBRK)) continue;
pStack->SetError(CBotErrCloseIndex, p->GetStart());
return false;
}
if ( p->GetType() == ID_OPENPAR )
@ -604,9 +605,14 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
// return a method precompiled in pass 1
CBotFunction* pf = m_pMethod;
CBotFunction* prev = nullptr;
while ( pf != nullptr )
CBotToken* ppp = p;
CBotCStack* pStk = pStack->TokenStack(nullptr, true);
CBotDefParam* params = CBotDefParam::Compile(p, pStk );
delete pStk;
p = ppp;
while ( pf != nullptr ) // search by name and parameters
{
if (pf->GetName() == pp) break;
if (pf->GetName() == pp && pf->CheckParam( params )) break;
prev = pf;
pf = pf->Next();
}
@ -672,7 +678,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
}
// definition of an element
if (type.Eq(0))
if (type2.Eq(0))
{
pStack->SetError(CBotErrNoTerminator, p);
return false;
@ -681,14 +687,38 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
CBotInstr* i = nullptr;
if ( IsOfType(p, ID_ASS ) )
{
if ( type.Eq(CBotTypArrayPointer) )
pStack->SetStartError(p->GetStart());
if ( IsOfType(p, ID_SEP) )
{
i = CBotListArray::Compile(p, pStack, type.GetTypElem());
pStack->SetError(CBotErrNoExpression, p->GetStart());
return false;
}
if ( type2.Eq(CBotTypArrayPointer) )
{
if ( nullptr == (i = CBotListArray::Compile(p, pStack, type2.GetTypElem())) )
{
if (pStack->IsOk())
{
i = CBotTwoOpExpr::Compile(p, pStack);
if (i == nullptr || !pStack->GetTypResult().Compare(type2))
{
pStack->SetError(CBotErrBadType1, p->GetStart());
return false;
}
}
}
}
else
{
// it has an assignmet to calculate
i = CBotTwoOpExpr::Compile(p, pStack);
if ( !(type.Eq(CBotTypPointer) && pStack->GetTypResult().Eq(CBotTypNullPointer)) &&
!TypesCompatibles( type2, pStack->GetTypResult()) )
{
pStack->SetError(CBotErrBadType1, p->GetStart());
return false;
}
}
if ( !pStack->IsOk() ) return false;
}
@ -696,7 +726,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
if ( !bSecond )
{
CBotVar* pv = CBotVar::Create(pp, type);
CBotVar* pv = CBotVar::Create(pp, type2);
pv -> SetStatic( bStatic );
pv -> SetPrivate( mProtect );

View File

@ -235,6 +235,7 @@ enum CBotError : int
CBotErrBadIndex = 5040, //!< wrong index type "[ false ]"
CBotErrPrivate = 5041, //!< protected item
CBotErrNoPublic = 5042, //!< missing word "public"
CBotErrNoExpression = 5043, //!< expression expected after =
// Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero

View File

@ -72,19 +72,26 @@ CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResul
CBotInstr* i;
while (IsOfType(p, ID_OPBRK))
{
pStk->SetStartError(p->GetStart());
if (p->GetType() != ID_CLBRK)
i = CBotExpression::Compile(p, pStk); // expression for the value
{
i = CBotExpression::Compile(p, pStk); // expression for the value
if (i == nullptr || pStk->GetType() != CBotTypInt) // must be a number
{
pStk->SetError(CBotErrBadIndex, p->GetStart());
goto error;
}
}
else
i = new CBotEmpty(); // if no special formula
inst->AddNext3b(i); // construct a list
type = CBotTypResult(CBotTypArrayPointer, type);
if (!pStk->IsOk() || !IsOfType(p, ID_CLBRK ))
{
pStk->SetError(CBotErrCloseIndex, p->GetStart());
goto error;
}
if (IsOfType(p, ID_CLBRK)) continue;
pStk->SetError(CBotErrCloseIndex, p->GetStart());
goto error;
}
CBotVar* var = CBotVar::Create(*vartoken, type); // create an instance
@ -96,17 +103,23 @@ CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResul
if (IsOfType(p, ID_ASS)) // with an assignment
{
if ((inst->m_listass = CBotTwoOpExpr::Compile(p, pStk)) != nullptr)
pStk->SetStartError(p->GetStart());
if ( IsOfType(p, ID_SEP) )
{
if (!pStk->GetTypResult().Compare(type)) // compatible type ?
{
pStk->SetError(CBotErrBadType1, p->GetStart());
goto error;
}
pStk->SetError(CBotErrNoExpression, p->GetPrev());
goto error;
}
else
if ( nullptr == (inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem())) )
{
inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem());
if (pStk->IsOk())
{
inst->m_listass = CBotTwoOpExpr::Compile(p, pStk);
if (inst->m_listass == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ?
{
pStk->SetError(CBotErrBadType1, p->GetStart());
goto error;
}
}
}
}

View File

@ -82,16 +82,17 @@ CBotInstr* CBotDefBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont,
inst = static_cast<CBotDefBoolean*>(CBotDefArray::Compile(p, pStk, CBotTypBoolean));
if (!pStk->IsOk() )
{
pStk->SetError(CBotErrCloseIndex, p->GetStart());
goto error;
}
goto suite; // no assignment, variable already created
}
if (IsOfType(p, ID_ASS))
{
pStk->SetStartError(p->GetStart());
if ( IsOfType(p, ID_SEP) )
{
pStk->SetError(CBotErrNoExpression, p->GetStart());
goto error;
}
if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
{
goto error;
@ -109,7 +110,7 @@ CBotInstr* CBotDefBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont,
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
pStack->AddVar(var);
suite:
if (IsOfType(p, ID_COMMA))
if (pStk->IsOk() && IsOfType(p, ID_COMMA))
{
if (nullptr != ( inst->m_next2b = CBotDefBoolean::Compile(p, pStk, true, noskip)))
{

View File

@ -101,11 +101,6 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
inst = static_cast<CBotDefClass*>(CBotDefArray::Compile(p, pStk, type ));
if (!pStk->IsOk() )
{
pStk->SetError(CBotErrCloseIndex, p->GetStart());
goto error;
}
goto suite; // no assignment, variable already created
}
@ -159,12 +154,19 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
if (IsOfType(p, ID_ASS)) // with a assignment?
{
pStk->SetStartError(p->GetStart());
if (inst->m_hasParams)
{
pStk->SetError(CBotErrNoTerminator, p->GetStart());
goto error;
}
if ( IsOfType(p, ID_SEP) )
{
pStk->SetError(CBotErrNoExpression, p->GetStart());
goto error;
}
if ( nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
{
goto error;
@ -200,7 +202,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
var->SetInit(CBotVar::InitType::IS_POINTER); // marks the pointer as init
}
suite:
if (IsOfType(p, ID_COMMA)) // several chained definitions
if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // several chained definitions
{
if ( nullptr != ( inst->m_next = CBotDefClass::Compile(p, pStk, pClass) )) // compiles the following
{
@ -208,7 +210,7 @@ suite:
}
}
if (IsOfType(p, ID_SEP)) // complete instruction
if (!pStk->IsOk() || IsOfType(p, ID_SEP)) // complete instruction
{
return pStack->Return(inst, pStk);
}

View File

@ -81,16 +81,17 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b
p = vartoken;
inst = static_cast<CBotDefFloat*>(CBotDefArray::Compile(p, pStk, CBotTypFloat));
if (!pStk->IsOk() )
{
pStk->SetError(CBotErrCloseIndex, p->GetStart());
goto error;
}
goto suite; // no assignment, variable already created
}
if (IsOfType(p, ID_ASS))
{
pStk->SetStartError(p->GetStart());
if ( IsOfType(p, ID_SEP) )
{
pStk->SetError(CBotErrNoExpression, p->GetStart());
goto error;
}
if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
{
goto error;
@ -108,7 +109,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
pStack->AddVar(var);
suite:
if (IsOfType(p, ID_COMMA))
if (pStk->IsOk() && IsOfType(p, ID_COMMA))
{
if (nullptr != ( inst->m_next2b = CBotDefFloat::Compile(p, pStk, true, noskip)))
{

View File

@ -84,25 +84,18 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo
CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypInt);
if (!pStk->IsOk() )
{
pStk->SetError(CBotErrCloseIndex, p->GetStart());
goto error;
}
if (IsOfType(p, ID_COMMA)) // several definition chained
{
if (nullptr != ( inst2->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip))) // compile the next one
{
return pStack->Return(inst2, pStk);
}
}
inst = static_cast<CBotDefInt*>(inst2);
goto suite; // no assignment, variable already created
}
if (IsOfType(p, ID_ASS)) // with an assignment?
{
pStk->SetStartError(p->GetStart());
if ( IsOfType(p, ID_SEP) )
{
pStk->SetError(CBotErrNoExpression, p->GetStart());
goto error;
}
if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
{
goto error;
@ -121,15 +114,15 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
pStack->AddVar(var); // place it on the stack
}
if (IsOfType(p, ID_COMMA)) // chained several definitions
suite:
if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // chained several definitions
{
if (nullptr != ( inst->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip))) // compile next one
{
return pStack->Return(inst, pStk);
}
}
suite:
if (noskip || IsOfType(p, ID_SEP)) // instruction is completed
{
return pStack->Return(inst, pStk);

View File

@ -20,6 +20,7 @@
#include "CBot/CBotInstr/CBotDefString.h"
#include "CBot/CBotInstr/CBotLeftExprVar.h"
#include "CBot/CBotInstr/CBotDefArray.h"
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
#include "CBot/CBotStack.h"
@ -61,6 +62,7 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont,
inst->m_expr = nullptr;
CBotToken* vartoken = p;
CBotVar* var = nullptr;
inst->SetToken(vartoken);
if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
@ -73,8 +75,27 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont,
goto error;
}
if (IsOfType(p, ID_OPBRK))
{
delete inst; // type is not CBotDefString
p = vartoken; // returns the variable name
// compiles an array declaration
CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypString);
inst = static_cast<CBotDefString*>(inst2);
goto suite; // no assignment, variable already created
}
if (IsOfType(p, ID_ASS))
{
pStk->SetStartError(p->GetStart());
if ( IsOfType(p, ID_SEP) )
{
pStk->SetError(CBotErrNoExpression, p->GetStart());
goto error;
}
if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
{
goto error;
@ -86,13 +107,13 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont,
}*/
}
CBotVar* var = CBotVar::Create(*vartoken, CBotTypString);
var = CBotVar::Create(*vartoken, CBotTypString);
var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF);
var->SetUniqNum(
(static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
pStack->AddVar(var);
if (IsOfType(p, ID_COMMA))
suite:
if (pStk->IsOk() && IsOfType(p, ID_COMMA))
{
if (nullptr != ( inst->m_next2b = CBotDefString::Compile(p, pStk, true, noskip)))
{

View File

@ -51,12 +51,13 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu
CBotToken* pp = p;
if (IsOfType( p, ID_NULL ))
if (IsOfType( p, ID_NULL ) || (IsOfType(p, ID_OPBLK) && IsOfType(p, ID_CLBLK)))
{
CBotInstr* inst = new CBotExprLitNull();
inst->SetToken(pp);
return pStack->Return(inst, pStk); // ok with empty element
}
p = pp;
CBotListArray* inst = new CBotListArray();
@ -65,25 +66,45 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu
// each element takes the one after the other
if (type.Eq( CBotTypArrayPointer ))
{
type = type.GetTypElem();
pStk->SetStartError(p->GetStart());
if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) ))
if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type.GetTypElem() ) ))
{
goto error;
if (pStk->IsOk())
{
inst->m_expr = CBotTwoOpExpr::Compile(p, pStk);
if (inst->m_expr == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ?
{
pStk->SetError(CBotErrBadType1, p->GetStart());
goto error;
}
}
}
while (IsOfType( p, ID_COMMA )) // other elements?
{
pStk->SetStartError(p->GetStart());
CBotInstr* i = CBotListArray::Compile(p, pStk, type);
if (nullptr == i)
CBotInstr* i = nullptr;
if (nullptr == ( i = CBotListArray::Compile(p, pStk, type.GetTypElem() ) ))
{
goto error;
if (pStk->IsOk())
{
i = CBotTwoOpExpr::Compile(p, pStk);
if (i == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ?
{
pStk->SetError(CBotErrBadType1, p->GetStart());
goto error;
}
}
}
inst->m_expr->AddNext3(i);
if ( p->GetType() == ID_COMMA ) continue;
if ( p->GetType() == ID_CLBLK ) break;
pStk->SetError(CBotErrClosePar, p);
goto error;
}
}
else
@ -95,7 +116,8 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu
}
CBotVar* pv = pStk->GetVar(); // result of the expression
if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type?
if (pv == nullptr || (!TypesCompatibles( type, pv->GetTypResult()) &&
!(type.Eq(CBotTypPointer) && pv->GetTypResult().Eq(CBotTypNullPointer)) ))
{
pStk->SetError(CBotErrBadType1, p->GetStart());
goto error;
@ -113,12 +135,19 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu
CBotVar* pv = pStk->GetVar(); // result of the expression
if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type?
if (pv == nullptr || (!TypesCompatibles( type, pv->GetTypResult()) &&
!(type.Eq(CBotTypPointer) && pv->GetTypResult().Eq(CBotTypNullPointer)) ))
{
pStk->SetError(CBotErrBadType1, p->GetStart());
goto error;
}
inst->m_expr->AddNext3(i);
if (p->GetType() == ID_COMMA) continue;
if (p->GetType() == ID_CLBLK) break;
pStk->SetError(CBotErrClosePar, p);
goto error;
}
}

View File

@ -715,6 +715,7 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrBadIndex] = TR("Incorrect index type");
stringsCbot[CBot::CBotErrPrivate] = TR("Private element");
stringsCbot[CBot::CBotErrNoPublic] = TR("Public required");
stringsCbot[CBot::CBotErrNoExpression] = TR("expression expected after =");
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");