From 0844a0f7bdcd3184ee60aaf0e943b65c73c8c283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Konopacki?= Date: Tue, 7 Aug 2012 15:46:04 +0200 Subject: Further CBot translations --- src/CBot/CBot.cpp | 7927 +++++++++++++++++++++++++++-------------------------- 1 file changed, 3964 insertions(+), 3963 deletions(-) (limited to 'src/CBot/CBot.cpp') diff --git a/src/CBot/CBot.cpp b/src/CBot/CBot.cpp index fb25049..62d9fb7 100644 --- a/src/CBot/CBot.cpp +++ b/src/CBot/CBot.cpp @@ -1,3963 +1,3964 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/./////////////////////////////////////////////////////////////////////// - -// compilation of various instructions -// compile all routines are static -// and return an object according to what was found as instruction - -// compiler principle: -// compile the routines return an object of the class corresponding to the operation found -// this is always a subclass of CBotInstr. -// (CBotInstr objects are never used directly) - - -// compiles if the routine returns NULL is that the statement is false -// or misunderstood. -// the error is then on the stack CBotCStack :: Isok () is false - - - -#include "CBot.h" - -CBotInstr::CBotInstr() -{ - name = "CBotInstr"; - m_next = NULL; - m_next2b = NULL; - m_next3 = NULL; - m_next3b = NULL; -} - -CBotInstr::~CBotInstr() -{ - delete m_next; - delete m_next2b; - delete m_next3; - delete m_next3b; -} - -// counter of nested loops, -// to determine the break and continue valid -// list of labels used - - -int CBotInstr::m_LoopLvl = 0; -CBotStringArray CBotInstr::m_labelLvl = CBotStringArray(); - -// adds a level with a label -void CBotInstr::IncLvl(CBotString& label) -{ - m_labelLvl.SetSize(m_LoopLvl+1); - m_labelLvl[m_LoopLvl] = label; - m_LoopLvl++; -} - -// adds a level (switch statement) -void CBotInstr::IncLvl() -{ - m_labelLvl.SetSize(m_LoopLvl+1); - m_labelLvl[m_LoopLvl] = "#SWITCH"; - m_LoopLvl++; -} - -// free a level -void CBotInstr::DecLvl() -{ - m_LoopLvl--; - m_labelLvl[m_LoopLvl].Empty(); -} - -// control validity of break and continue -bool CBotInstr::ChkLvl(const CBotString& label, int type) -{ - int i = m_LoopLvl; - while (--i>=0) - { - if ( type == ID_CONTINUE && m_labelLvl[i] == "#SWITCH") continue; - if (label.IsEmpty()) return true; - if (m_labelLvl[i] == label) return true; - } - return false; -} - -bool CBotInstr::IsOfClass(CBotString n) -{ - return name == n; -} - - -//////////////////////////////////////////////////////////////////////////// -// database management class CBotInstr - -// set the token corresponding to the instruction - -void CBotInstr::SetToken(CBotToken* p) -{ - m_token = *p; -} - -// return the type of the token assicated with the instruction - -int CBotInstr::GivTokenType() -{ - return m_token.GivType(); -} - -// return associated token - -CBotToken* CBotInstr::GivToken() -{ - return &m_token; -} - -// adds the statement following the other - -void CBotInstr::AddNext(CBotInstr* n) -{ - CBotInstr* p = this; - while (p->m_next != NULL) p = p->m_next; - p->m_next = n; -} - -void CBotInstr::AddNext3(CBotInstr* n) -{ - CBotInstr* p = this; - while (p->m_next3 != NULL) p = p->m_next3; - p->m_next3 = n; -} - -void CBotInstr::AddNext3b(CBotInstr* n) -{ - CBotInstr* p = this; - while (p->m_next3b != NULL) p = p->m_next3b; - p->m_next3b = n; -} - -// returns next statement - -CBotInstr* CBotInstr::GivNext() -{ - return m_next; -} - -CBotInstr* CBotInstr::GivNext3() -{ - return m_next3; -} - -CBotInstr* CBotInstr::GivNext3b() -{ - return m_next3b; -} - -/////////////////////////////////////////////////////////////////////////// -// compile an instruction which can be -// while, do, try, throw, if, for, switch, break, continue, return -// int, float, boolean, string, -// declaration of an instance of a class -// arbitrary expression - - -CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotToken* pp = p; - - if (p == NULL) return NULL; - - int type = p->GivType(); // what is the next token - - // is it a lable? - if (IsOfType(pp, TokenTypVar) && - IsOfType(pp, ID_DOTS)) - { - type = pp->GivType(); - // these instructions accept only lable - if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0)) - { - pStack->SetError(TX_LABEL, pp->GivStart()); - return NULL; - } - } - - // call routine corresponding to the compilation token found - switch (type) - { - case ID_WHILE: - return CBotWhile::Compile(p, pStack); - - case ID_FOR: - return CBotFor::Compile(p, pStack); - - case ID_DO: - return CBotDo::Compile(p, pStack); - - case ID_REPEAT: - return CBotRepeat::Compile(p, pStack); - - case ID_BREAK: - case ID_CONTINUE: - return CBotBreak::Compile(p, pStack); - - case ID_SWITCH: - return CBotSwitch::Compile(p, pStack); - - case ID_TRY: - return CBotTry::Compile(p, pStack); - - case ID_THROW: - return CBotThrow::Compile(p, pStack); - - case ID_DEBUGDD: - return CBotStartDebugDD::Compile(p, pStack); - - case ID_INT: - return CBotInt::Compile(p, pStack); - - case ID_FLOAT: - return CBotFloat::Compile(p, pStack); - - case ID_STRING: - return CBotIString::Compile(p, pStack); - - case ID_BOOLEAN: - case ID_BOOL: - return CBotBoolean::Compile(p, pStack); - - case ID_IF: - return CBotIf::Compile(p, pStack); - - case ID_RETURN: - return CBotReturn::Compile(p, pStack); - - case ID_ELSE: - pStack->SetStartError(p->GivStart()); - pStack->SetError(TX_ELSEWITHOUTIF, p->GivEnd()); - return NULL; - - case ID_CASE: - pStack->SetStartError(p->GivStart()); - pStack->SetError(TX_OUTCASE, p->GivEnd()); - return NULL; - } - - pStack->SetStartError(p->GivStart()); - - // should not be a reserved word DefineNum - if (p->GivType() == TokenTypDef) - { - pStack->SetError(TX_RESERVED, p); - return NULL; - } - - // this might be an instance of class definnition - CBotToken* ppp = p; - if (IsOfType(ppp, TokenTypVar)) - { - if (CBotClass::Find(p) != NULL) - { - // yes, compiles the declaration of the instance - return CBotClassInst::Compile(p, pStack); - } - } - - // this can be an arythmetic instruction - CBotInstr* inst = CBotExpression::Compile(p, pStack); - if (IsOfType(p, ID_SEP)) - { - return inst; - } - pStack->SetError(TX_ENDOF, p->GivStart()); - delete inst; - return NULL; -} - -bool CBotInstr::Execute(CBotStack* &pj) -{ - CBotString ClassManquante = name; - ASM_TRAP(); // should never go through this routine - // but use the routines of the subclasses - return false; -} - -bool CBotInstr::Execute(CBotStack* &pj, CBotVar* pVar) -{ - if (!Execute(pj)) return false; - pVar->SetVal(pj->GivVar()); - return true; -} - -void CBotInstr::RestoreState(CBotStack* &pj, bool bMain) -{ - CBotString ClassManquante = name; - ASM_TRAP(); // should never go through this routine - // but use the routines of the subclasses -} - - -bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) -{ - ASM_TRAP(); // dad do not know, see the girls - return false; -} - -bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) -{ - ASM_TRAP(); // dad do not know, see the girls - return false; -} - -void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain) -{ - ASM_TRAP(); // dad do not know, see the girls -} - -// 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. - -bool CBotInstr::CompCase(CBotStack* &pj, int val) -{ - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compiles a statement block " { i ; i ; } " - -// this class have no constructor because there is never an instance of this -// class (TODO what about default constructor?) -// the object returned by Compile is usually of type CBotListInstr - - -CBotInstr* CBotBlock::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal) -{ - pStack->SetStartError(p->GivStart()); - - if (IsOfType(p, ID_OPBLK)) - { - CBotInstr* inst = CBotListInstr::Compile(p, pStack, bLocal); - - if (IsOfType(p, ID_CLBLK)) - { - return inst; - } - - pStack->SetError(TX_CLOSEBLK, p->GivStart()); // missing parenthesis - delete inst; - return NULL; - } - - pStack->SetError(TX_OPENBLK, p->GivStart()); - return NULL; -} - -CBotInstr* CBotBlock::CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal) -{ - // is this a new block - if (p->GivType() == ID_OPBLK) return CBotBlock::Compile(p, pStack); - - // otherwise, look for a single statement instead - - // to handle the case with local definition instruction (*) - CBotCStack* pStk = pStack->TokenStack(p, bLocal); - - return pStack->Return( CBotInstr::Compile(p, pStk), // a single instruction - pStk); -} - -// (*) is the case in the following statement -// if (1 == 1) int x = 0; -// where the variable x is known only in the block following the if - - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compiles a list of instructions separated by semicolons - -CBotListInstr::CBotListInstr() -{ - m_Instr = NULL; - name = "CBotListInstr"; -} - -CBotListInstr::~CBotListInstr() -{ - delete m_Instr; -} - -CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal) -{ - CBotCStack* pStk = pStack->TokenStack(p, bLocal); // variables are local - - CBotListInstr* inst = new CBotListInstr(); - - while (true) - { - if (p == NULL) break; - - if (IsOfType(p, ID_SEP)) continue; // empty statement ignored - if (p->GivType() == ID_CLBLK) break; - - if (IsOfType(p, 0)) - { - pStack->SetError(TX_CLOSEBLK, p->GivStart()); - delete inst; - return pStack->Return(NULL, pStk); - } - - CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk); // compiles next - - if (!pStk->IsOk()) - { - delete inst; - return pStack->Return(NULL, pStk); - } - - if (inst->m_Instr == NULL) inst->m_Instr = i; - else inst->m_Instr->AddNext(i); // added a result - } - return pStack->Return(inst, pStk); -} - -// executes a set of instructions - -bool CBotListInstr::Execute(CBotStack* &pj) -{ - - CBotStack* pile = pj->AddStack(this, true); //needed for SetState() - if (pile->StackOver() ) return pj->Return( pile); - - - CBotInstr* p = m_Instr; // the first expression - - int state = pile->GivState(); - while (state-->0) p = p->GivNext(); // returns to the interrupted operation - - if (p != NULL) while (true) - { - if (!p->Execute(pile)) return false; - p = p->GivNext(); - if (p == NULL) break; - if (!pile->IncState()) ;//return false; // ready for next - } - - return pj->Return(pile); -} - -void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain) -{ - if (!bMain) return; - - CBotStack* pile = pj->RestoreStack(this); - if (pile == NULL) return; - - CBotInstr* p = m_Instr; // the first expression - - int state = pile->GivState(); - while ( p != NULL && state-- > 0) - { - p->RestoreState(pile, false); - p = p->GivNext(); // returns to the interrupted operation - } - - if (p != NULL) p->RestoreState(pile, true); -} - -////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// -// compilation of an element to the left of an assignment - -CBotLeftExprVar::CBotLeftExprVar() -{ - name = "CBotLeftExprVar"; - m_typevar = -1; - m_nIdent = 0; -} - -CBotLeftExprVar::~CBotLeftExprVar() -{ -} - -CBotInstr* CBotLeftExprVar::Compile(CBotToken* &p, CBotCStack* pStack) -{ - // verifies that the token is a variable name - if (p->GivType() != TokenTypVar) - { - pStack->SetError( TX_NOVAR, p->GivStart()); - return NULL; - } - - CBotLeftExprVar* inst = new CBotLeftExprVar(); - inst->SetToken(p); - p = p->GivNext(); - - return inst; -} - -// creates a variable and assigns the result to the stack -bool CBotLeftExprVar::Execute(CBotStack* &pj) -{ - CBotVar* var1; - CBotVar* var2; - - var1 = CBotVar::Create(m_token.GivString(), m_typevar); - var1->SetUniqNum(m_nIdent); // with the unique identifier - pj->AddVar(var1); // place it on the stack - - var2 = pj->GivVar(); // result on the stack - if (var2) var1->SetVal(var2); // do the assignment - - return true; -} - -void CBotLeftExprVar::RestoreState(CBotStack* &pj, bool bMain) -{ - CBotVar* var1; - - var1 = pj->FindVar(m_token.GivString()); - if (var1 == NULL) ASM_TRAP(); - - var1->SetUniqNum(m_nIdent); // with the unique identifier -} - -////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// -// defining an array of any type -// int a[12]; -// point x[]; - -CBotInstArray::CBotInstArray() -{ - m_var = NULL; - m_listass = NULL; - name = "CBotInstArray"; -} - -CBotInstArray::~CBotInstArray() -{ - delete m_var; - delete m_listass; -} - - -CBotInstr* CBotInstArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) -{ - CBotCStack* pStk = pStack->TokenStack(p); - - CBotInstArray* inst = new CBotInstArray(); - - CBotToken* vartoken = p; - inst->SetToken(vartoken); - - // determinse the expression is valid for the item on the left side - if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) - { - if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable? - { - pStk->SetError(TX_REDEFVAR, vartoken); - goto error; - } - - CBotInstr* i; - while (IsOfType(p, ID_OPBRK)) - { - if (p->GivType() != ID_CLBRK) - i = CBotExpression::Compile(p, pStk); // expression for the value - 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(TX_CLBRK, p->GivStart()); - goto error; - } - } - - CBotVar* var = CBotVar::Create(vartoken, type); // create an instance - inst->m_typevar = type; - - var->SetUniqNum( - ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); - pStack->AddVar(var); // place it on the stack - - if (IsOfType(p, ID_ASS)) // with an assignment - { - inst->m_listass = CBotListArray::Compile(p, pStk, type.GivTypElem()); - } - - if (pStk->IsOk()) return pStack->Return(inst, pStk); - } - -error: - delete inst; - return pStack->Return(NULL, pStk); -} - - -// executes the definition of an array - -bool CBotInstArray::Execute(CBotStack* &pj) -{ - CBotStack* pile1 = pj->AddStack(this); - - CBotStack* pile = pile1; - - if (pile1->GivState() == 0) - { - // seek the maximum dimension of the table - CBotInstr* p = GivNext3b(); // the different formulas - int nb = 0; - - while (p != NULL) - { - pile = pile->AddStack(); // little room to work - nb++; - if (pile->GivState() == 0) - { - if (!p->Execute(pile)) return false; // size calculation //interrupted? - pile->IncState(); - } - p = p->GivNext3b(); - } - - p = GivNext3b(); - pile = pile1; // returns to the stack - int n = 0; - int max[100]; - - while (p != NULL) - { - pile = pile->AddStack(); - CBotVar* v = pile->GivVar(); // result - max[n] = v->GivValInt(); // value - if (max[n]>MAXARRAYSIZE) - { - pile->SetError(TX_OUTARRAY, &m_token); - return pj->Return (pile); - } - n++; - p = p->GivNext3b(); - } - while (n<100) max[n++] = 0; - - m_typevar.SetArray(max); // store the limitations - - // crée simplement un pointeur null - CBotVar* var = CBotVar::Create(m_var->GivToken(), m_typevar); - var->SetPointer(NULL); - var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); - pj->AddVar(var); - -#if STACKMEM - pile1->AddStack()->Delete(); -#else - delete pile1->AddStack(); // need more indices -#endif - pile1->IncState(); - } - - if (pile1->GivState() == 1) - { - if (m_listass != NULL) // there is the assignment for this table - { - CBotVar* pVar = pj->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent); - - if (!m_listass->Execute(pile1, pVar)) return false; - } - pile1->IncState(); - } - - if (pile1->IfStep()) return false; - - if ( m_next2b && - !m_next2b->Execute(pile1 )) return false; - - return pj->Return(pile1); -} - -void CBotInstArray::RestoreState(CBotStack* &pj, bool bMain) -{ - CBotStack* pile1 = pj; - - CBotVar* var = pj->FindVar(m_var->GivToken()->GivString()); - if (var != NULL) var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); - - if (bMain) - { - pile1 = pj->RestoreStack(this); - CBotStack* pile = pile1; - if (pile == NULL) return; - - if (pile1->GivState() == 0) - { - // seek the maximum dimension of the table - CBotInstr* p = GivNext3b(); - - while (p != NULL) - { - pile = pile->RestoreStack(); - if (pile == NULL) return; - if (pile->GivState() == 0) - { - p->RestoreState(pile, bMain); - return; - } - p = p->GivNext3b(); - } - } - if (pile1->GivState() == 1 && m_listass != NULL) - { - m_listass->RestoreState(pile1, bMain); - } - - } - - if (m_next2b ) m_next2b->RestoreState( pile1, bMain); -} - -// special case for empty indexes -bool CBotEmpty :: Execute(CBotStack* &pj) -{ - CBotVar* pVar = CBotVar::Create("", CBotTypInt); - pVar->SetValInt(-1); - pj->SetVar(pVar); - return true; -} - -void CBotEmpty :: RestoreState(CBotStack* &pj, bool bMain) -{ -} - -////////////////////////////////////////////////////////////////////////////////////// -// defining a list table initialization -// int [ ] a [ ] = (( 1, 2, 3 ) , ( 3, 2, 1 )) ; - - -CBotListArray::CBotListArray() -{ - m_expr = NULL; - name = "CBotListArray"; -} - -CBotListArray::~CBotListArray() -{ - delete m_expr; -} - - -CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) -{ - CBotCStack* pStk = pStack->TokenStack(p); - - CBotToken* pp = p; - - if (IsOfType( p, ID_NULL )) - { - CBotInstr* inst = new CBotExprNull (); - inst->SetToken(pp); - return pStack->Return(inst, pStk); // ok with empty element - } - - CBotListArray* inst = new CBotListArray(); - - if (IsOfType( p, ID_OPENPAR )) - { - // each element takes the one after the other - if (type.Eq( CBotTypArrayPointer )) - { - type = type.GivTypElem(); - - pStk->SetStartError(p->GivStart()); - if (NULL == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) )) - { - goto error; - } - - while (IsOfType( p, ID_COMMA )) // other elements? - { - pStk->SetStartError(p->GivStart()); - - CBotInstr* i = CBotListArray::Compile(p, pStk, type); - if (NULL == i) - { - goto error; - } - - inst->m_expr->AddNext3(i); - } - } - else - { - pStk->SetStartError(p->GivStart()); - if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) - { - goto error; - } - CBotVar* pv = pStk->GivVar(); // result of the expression - - if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type? - { - pStk->SetError(TX_BADTYPE, p->GivStart()); - goto error; - } - - while (IsOfType( p, ID_COMMA )) // other elements? - { - pStk->SetStartError(p->GivStart()); - - CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ; - if (NULL == i) - { - goto error; - } - - CBotVar* pv = pStk->GivVar(); // result of the expression - - if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type? - { - pStk->SetError(TX_BADTYPE, p->GivStart()); - goto error; - } - inst->m_expr->AddNext3(i); - } - } - - if (!IsOfType(p, ID_CLOSEPAR) ) - { - pStk->SetError(TX_CLOSEPAR, p->GivStart()); - goto error; - } - - return pStack->Return(inst, pStk); - } - -error: - delete inst; - return pStack->Return(NULL, pStk); -} - - -// executes the definition of an array - -bool CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar) -{ - CBotStack* pile1 = pj->AddStack(); - CBotVar* pVar2; - - CBotInstr* p = m_expr; - - int n = 0; - - for (; p != NULL ; n++, p = p->GivNext3()) - { - if (pile1->GivState() > n) continue; - - pVar2 = pVar->GivItem(n, true); - - if (!p->Execute(pile1, pVar2)) return false; // evaluate expression - - pile1->IncState(); - } - - return pj->Return(pile1); -} - -void CBotListArray::RestoreState(CBotStack* &pj, bool bMain) -{ - if (bMain) - { - CBotStack* pile = pj->RestoreStack(this); - if (pile == NULL) return; - - CBotInstr* p = m_expr; - - int state = pile->GivState(); - - while(state-- > 0) p = p->GivNext3() ; - - p->RestoreState(pile, bMain); // size calculation //interrupted! - } -} - -////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// -// definition of an integer variable -// int a, b = 12; - -CBotInt::CBotInt() -{ - m_next = NULL; // for multiple definitions - m_var = - m_expr = NULL; - name = "CBotInt"; -} - -CBotInt::~CBotInt() -{ - delete m_var; - delete m_expr; -} - -CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first) -{ - if (IsOfType(p, ID_OPBRK)) - { - if (!IsOfType(p, ID_CLBRK)) - { - pStack->SetError(TX_CLBRK, p->GivStart()); - return NULL; - } - - CBotInstr* inst = CompileArray(p, pStack, CBotTypResult(CBotTypArrayPointer, type), false); - if (inst != NULL || !pStack->IsOk()) return inst; - } - - // compiles an array declaration - if (first) return NULL ; - - CBotInstr* inst = CBotInstArray::Compile(p, pStack, type); - if (inst == NULL) return NULL; - - if (IsOfType(p, ID_COMMA)) // several definitions - { - if (NULL != ( inst->m_next2b = CBotInstArray::CompileArray(p, pStack, type, false))) // compiles next one - { - return inst; - } - delete inst; - return NULL; - } - - if (IsOfType(p, ID_SEP)) // end of instruction - { - return inst; - } - - delete inst; - pStack->SetError(TX_ENDOF, p->GivStart()); - return NULL; -} - -CBotInstr* CBotInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) -{ - CBotToken* pp = cont ? NULL : p; // no repetition of the token "int" - - if (!cont && !IsOfType(p, ID_INT)) return NULL; - - CBotInt* inst = (CBotInt*)CompileArray(p, pStack, CBotTypInt); - if (inst != NULL || !pStack->IsOk()) return inst; - - CBotCStack* pStk = pStack->TokenStack(pp); - - inst = new CBotInt(); - - inst->m_expr = NULL; - - CBotToken* vartoken = p; - inst->SetToken(vartoken); - - // determines the expression is valid for the item on the left side - if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) - { - ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypInt; - if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable - { - pStk->SetError(TX_REDEFVAR, vartoken); - goto error; - } - - if (IsOfType(p, ID_OPBRK)) - { - delete inst; // type is not CBotInt - p = vartoken; // returns the variable name - - // compiles an array declaration - - CBotInstr* inst2 = CBotInstArray::Compile(p, pStk, CBotTypInt); - - if (!pStk->IsOk() ) - { - pStk->SetError(TX_CLBRK, p->GivStart()); - goto error; - } - - if (IsOfType(p, ID_COMMA)) // several definition chained - { - if (NULL != ( inst2->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile the next one - { - return pStack->Return(inst2, pStk); - } - } - inst = (CBotInt*)inst2; - goto suite; // no assignment, variable already created - } - - if (IsOfType(p, ID_ASS)) // with an assignment? - { - if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) - { - goto error; - } - if (pStk->GivType() >= CBotTypBoolean) // compatible type ? - { - pStk->SetError(TX_BADTYPE, p->GivStart()); - goto error; - } - } - - { - CBotVar* var = CBotVar::Create(vartoken, CBotTypInt);// create the variable (evaluated after the assignment) - var->SetInit(inst->m_expr != NULL); // if initialized with assignment - var->SetUniqNum( //set it with a unique number - ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); - pStack->AddVar(var); // place it on the stack - } - - if (IsOfType(p, ID_COMMA)) // chained several definitions - { - if (NULL != ( inst->m_next2b = CBotInt::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); - } - - pStk->SetError(TX_ENDOF, p->GivStart()); - } - -error: - delete inst; - return pStack->Return(NULL, pStk); -} - -// execute the definition of the integer variable - -bool CBotInt::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); // essential for SetState() - - if ( pile->GivState()==0) - { - if (m_expr && !m_expr->Execute(pile)) return false; // initial value // interrupted? - m_var->Execute(pile); // creates and assign the result - - if (!pile->SetState(1)) return false; - } - - if (pile->IfStep()) return false; - - if ( m_next2b && - !m_next2b->Execute(pile)) return false; // other(s) definition(s) - - return pj->Return(pile); // forward below -} - -void CBotInt::RestoreState(CBotStack* &pj, bool bMain) -{ - CBotStack* pile = pj; - if (bMain) - { - pile = pj->RestoreStack(this); - if (pile == NULL) return; - - if ( pile->GivState()==0) - { - if (m_expr) m_expr->RestoreState(pile, bMain); // initial value // interrupted? - return; - } - } - - m_var->RestoreState(pile, bMain); - - if (m_next2b) m_next2b->RestoreState(pile, bMain); // other(s) definition(s) -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// defining a boolean variable -// int a, b = false; - -CBotBoolean::CBotBoolean() -{ - m_var = - m_expr = NULL; - name = "CBotBoolean"; -} - -CBotBoolean::~CBotBoolean() -{ - delete m_var; - delete m_expr; -} - -CBotInstr* CBotBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) -{ - CBotToken* pp = cont ? NULL : p; - - if (!cont && !IsOfType(p, ID_BOOLEAN, ID_BOOL)) return NULL; - - CBotBoolean* inst = (CBotBoolean*)CompileArray(p, pStack, CBotTypBoolean); - if (inst != NULL || !pStack->IsOk()) return inst; - - CBotCStack* pStk = pStack->TokenStack(pp); - - inst = new CBotBoolean(); - - inst->m_expr = NULL; - - CBotToken* vartoken = p; - inst->SetToken(vartoken); - CBotVar* var = NULL; - - if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) - { - ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypBoolean; - if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable - { - pStk->SetError(TX_REDEFVAR, vartoken); - goto error; - } - - if (IsOfType(p, ID_OPBRK)) - { - delete inst; // type is not CBotInt - p = vartoken; // resutns to the variable name - - // compiles an array declaration - - inst = (CBotBoolean*)CBotInstArray::Compile(p, pStk, CBotTypBoolean); - - if (!pStk->IsOk() ) - { - pStk->SetError(TX_CLBRK, p->GivStart()); - goto error; - } - goto suite; // no assignment, variable already created - } - - if (IsOfType(p, ID_ASS)) - { - if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) - { - goto error; - } - if (!pStk->GivTypResult().Eq(CBotTypBoolean)) - { - pStk->SetError(TX_BADTYPE, p->GivStart()); - goto error; - } - } - - var = CBotVar::Create(vartoken, CBotTypBoolean);// create the variable (evaluated after the assignment) - var->SetInit(inst->m_expr != NULL); - var->SetUniqNum( - ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); - pStack->AddVar(var); -suite: - if (IsOfType(p, ID_COMMA)) - { - if (NULL != ( inst->m_next2b = CBotBoolean::Compile(p, pStk, true, noskip))) - { - return pStack->Return(inst, pStk); - } - } - - if (noskip || IsOfType(p, ID_SEP)) - { - return pStack->Return(inst, pStk); - } - - pStk->SetError(TX_ENDOF, p->GivStart()); - } - -error: - delete inst; - return pStack->Return(NULL, pStk); -} - -// executes a boolean variable definition - -bool CBotBoolean::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this);//essential for SetState() - - if ( pile->GivState()==0) - { - if (m_expr && !m_expr->Execute(pile)) return false; - m_var->Execute(pile); - - if (!pile->SetState(1)) return false; - } - - if (pile->IfStep()) return false; - - if ( m_next2b && - !m_next2b->Execute(pile)) return false; - - return pj->Return(pile); -} - -void CBotBoolean::RestoreState(CBotStack* &pj, bool bMain) -{ - CBotStack* pile = pj; - if (bMain) - { - pile = pj->RestoreStack(this); - if (pile == NULL) return; - - if ( pile->GivState()==0) - { - if (m_expr) m_expr->RestoreState(pile, bMain); // initial value interrupted? - return; - } - } - - m_var->RestoreState(pile, bMain); - - if (m_next2b) - m_next2b->RestoreState(pile, bMain); // other(s) definition(s) -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// definition of a real/float variable -// int a, b = 12.4; - -CBotFloat::CBotFloat() -{ - m_var = - m_expr = NULL; - name = "CBotFloat"; -} - -CBotFloat::~CBotFloat() -{ - delete m_var; - delete m_expr; -} - -CBotInstr* CBotFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) -{ - CBotToken* pp = cont ? NULL : p; - - if (!cont && !IsOfType(p, ID_FLOAT)) return NULL; - - CBotFloat* inst = (CBotFloat*)CompileArray(p, pStack, CBotTypFloat); - if (inst != NULL || !pStack->IsOk()) return inst; - - CBotCStack* pStk = pStack->TokenStack(pp); - - inst = new CBotFloat(); - - inst->m_expr = NULL; - - CBotToken* vartoken = p; - CBotVar* var = NULL; - inst->SetToken(vartoken); - - if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) - { - ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypFloat; - if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable - { - pStk->SetStartError(vartoken->GivStart()); - pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); - goto error; - } - - if (IsOfType(p, ID_OPBRK)) - { - delete inst; - p = vartoken; - inst = (CBotFloat*)CBotInstArray::Compile(p, pStk, CBotTypFloat); - - if (!pStk->IsOk() ) - { - pStk->SetError(TX_CLBRK, p->GivStart()); - goto error; - } - goto suite; // no assignment, variable already created - } - - if (IsOfType(p, ID_ASS)) - { - if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) - { - goto error; - } - if (pStk->GivType() >= CBotTypBoolean) - { - pStk->SetError(TX_BADTYPE, p->GivStart()); - goto error; - } - } - - var = CBotVar::Create(vartoken, CBotTypFloat); - var->SetInit(inst->m_expr != NULL); - var->SetUniqNum( - ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); - pStack->AddVar(var); -suite: - if (IsOfType(p, ID_COMMA)) - { - if (NULL != ( inst->m_next2b = CBotFloat::Compile(p, pStk, true, noskip))) - { - return pStack->Return(inst, pStk); - } - } - - if (noskip || IsOfType(p, ID_SEP)) - { - return pStack->Return(inst, pStk); - } - - pStk->SetError(TX_ENDOF, p->GivStart()); - } - -error: - delete inst; - return pStack->Return(NULL, pStk); -} - -// executes the definition of a real variable - -bool CBotFloat::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if ( pile->GivState()==0) - { - if (m_expr && !m_expr->Execute(pile)) return false; - m_var->Execute(pile); - - if (!pile->SetState(1)) return false; - } - - if (pile->IfStep()) return false; - - if ( m_next2b && - !m_next2b->Execute(pile)) return false; - - return pj->Return(pile); -} - -void CBotFloat::RestoreState(CBotStack* &pj, bool bMain) -{ - CBotStack* pile = pj; - if (bMain) - { - pile = pj->RestoreStack(this); - if (pile == NULL) return; - - if ( pile->GivState()==0) - { - if (m_expr) m_expr->RestoreState(pile, bMain); - return; - } - } - - m_var->RestoreState(pile, bMain); - - if (m_next2b) - m_next2b->RestoreState(pile, bMain); -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// define a string variable -// int a, b = "salut"; - -CBotIString::CBotIString() -{ - m_var = - m_expr = NULL; - name = "CBotIString"; -} - -CBotIString::~CBotIString() -{ - delete m_var; - delete m_expr; -} - -CBotInstr* CBotIString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) -{ - CBotToken* pp = cont ? NULL : p; - - if (!cont && !IsOfType(p, ID_STRING)) return NULL; - - CBotIString* inst = (CBotIString*)CompileArray(p, pStack, CBotTypString); - if (inst != NULL || !pStack->IsOk()) return inst; - - CBotCStack* pStk = pStack->TokenStack(pp); - - inst = new CBotIString(); - - inst->m_expr = NULL; - - CBotToken* vartoken = p; - inst->SetToken(vartoken); - - if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) - { - ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypString; - if (pStk->CheckVarLocal(vartoken)) - { - pStk->SetStartError(vartoken->GivStart()); - pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); - goto error; - } - - if (IsOfType(p, ID_ASS)) - { - if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) - { - goto error; - } -/* if (!pStk->GivTypResult().Eq(CBotTypString)) // type compatible ? - { - pStk->SetError(TX_BADTYPE, p->GivStart()); - goto error; - }*/ - } - - CBotVar* var = CBotVar::Create(vartoken, CBotTypString); - var->SetInit(inst->m_expr != NULL); - var->SetUniqNum( - ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); - pStack->AddVar(var); - - if (IsOfType(p, ID_COMMA)) - { - if (NULL != ( inst->m_next2b = CBotIString::Compile(p, pStk, true, noskip))) - { - return pStack->Return(inst, pStk); - } - } - - if (noskip || IsOfType(p, ID_SEP)) - { - return pStack->Return(inst, pStk); - } - - pStk->SetError(TX_ENDOF, p->GivStart()); - } - -error: - delete inst; - return pStack->Return(NULL, pStk); -} - -// executes the definition of the string variable - -bool CBotIString::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if ( pile->GivState()==0) - { - if (m_expr && !m_expr->Execute(pile)) return false; - m_var->Execute(pile); - - if (!pile->SetState(1)) return false; - } - - if (pile->IfStep()) return false; - - if ( m_next2b && - !m_next2b->Execute(pile)) return false; - - return pj->Return(pile); -} - -void CBotIString::RestoreState(CBotStack* &pj, bool bMain) -{ - CBotStack* pile = pj; - - if (bMain) - { - pile = pj->RestoreStack(this); - if (pile == NULL) return; - - if ( pile->GivState()==0) - { - if (m_expr) m_expr->RestoreState(pile, bMain); - return; - } - } - - m_var->RestoreState(pile, bMain); - - if (m_next2b) - m_next2b->RestoreState(pile, bMain); -} - -////////////////////////////////////////////////////////////////////////////////////////// - - - -////////////////////////////////////////////////////////////////////////////////////// -// compiles a statement such as " x = 123 " ou " z * 5 + 4 " -// with or without assignment - -CBotExpression::CBotExpression() -{ - m_leftop = NULL; - m_rightop = NULL; - 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->GivType(); - - 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 == NULL) - { - pStack->SetError(TX_BADLEFT, p->GivEnd()); - delete inst; - return NULL; - } - - inst->m_rightop = CBotExpression::Compile(p, pStack); - if (inst->m_rightop == NULL) - { - delete inst; - return NULL; - } - - CBotTypResult type1 = pStack->GivTypResult(); - - // get the variable assigned to mark - CBotVar* var = NULL; - inst->m_leftop->ExecuteVar(var, pStack); - if (var == NULL) - { - delete inst; - return NULL; - } - - if (OpType != ID_ASS && var->GivInit() != IS_DEF) - { - pStack->SetError(TX_NOTINIT, pp); - delete inst; - return NULL; - } - - CBotTypResult type2 = var->GivTypResult(); - - // 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.GivClass(); - CBotClass* c2 = type2.GivClass(); - if (!c1->IsChildOf(c2)) type2.SetType(-1); -//- if (!type1.Eq(CBotTypClass)) var->SetPointer(pStack->GivVar()->GivPointer());*/ - var->SetInit(2); - } - else - var->SetInit(true); - - 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.GivType() >= CBotTypBoolean) type2 = -1; // numbers only - break; - } - - if (!TypeCompatible(type1, type2, OpType)) - { - pStack->SetError(TX_BADTYPE, &inst->m_token); - delete inst; - return NULL; - } - - return inst; // compatible type? - } - - delete inst; - int start, end, error = pStack->GivError(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 != NULL && error == TX_PRIVATE && p->GivType() == 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->GivToken(); - CBotVar* pVar = NULL; - - CBotStack* pile1 = pile; - - bool IsInit = true; - CBotVar* result = NULL; - - // must be done before any indexes (stack can be changed) - if (!m_leftop->ExecuteVar(pVar, pile, NULL, false)) return false; // variable before accessing the value on the right - - if ( pile1->GivState()==0) - { - pile1->SetCopyVar(pVar); // keeps the copy on the stack (if interrupted) - pile1->IncState(); - } - - CBotStack* pile2 = pile->AddStack(); - - if ( pile2->GivState()==0) - { - if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted? - pile2->IncState(); - } - - if (pile1->GivState() == 1) - { - if (m_token.GivType() != ID_ASS) - { - pVar = pile1->GivVar(); // recovers if interrupted - IsInit = pVar->GivInit(); - if (IsInit == IS_NAN) - { - pile2->SetError(TX_OPNAN, m_leftop->GivToken()); - return pj->Return(pile2); - } - result = CBotVar::Create("", pVar->GivTypResult(2)); - } - - switch (m_token.GivType()) - { - case ID_ASS: - break; - case ID_ASSADD: - result->Add(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSSUB: - result->Sub(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSMUL: - result->Mul(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSDIV: - if (IsInit && - result->Div(pile1->GivVar(), pile2->GivVar())) - pile2->SetError(TX_DIVZERO, &m_token); - pile2->SetVar(result); - break; - case ID_ASSMODULO: - if (IsInit && - result->Modulo(pile1->GivVar(), pile2->GivVar())) - pile2->SetError(TX_DIVZERO, &m_token); - pile2->SetVar(result); - break; - case ID_ASSAND: - result->And(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSXOR: - result->XOr(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSOR: - result->Or(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSSL: - result->SL(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSSR: - result->SR(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - case ID_ASSASR: - result->ASR(pile1->GivVar(), pile2->GivVar()); - pile2->SetVar(result); - break; - default: - ASM_TRAP(); - } - if (!IsInit) - pile2->SetError(TX_NOTINIT, m_leftop->GivToken()); - - 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->GivToken(); - CBotVar* pVar = NULL; - - CBotStack* pile = pj->RestoreStack(this); - if (pile == NULL) return; - - CBotStack* pile1 = pile; - - if ( pile1->GivState()==0) - { - m_leftop->RestoreStateVar(pile, true); - return; - } - - m_leftop->RestoreStateVar(pile, false); - - CBotStack* pile2 = pile->RestoreStack(); - if (pile2 == NULL) return; - - if ( pile2->GivState()==0) - { - if (m_rightop) m_rightop->RestoreState(pile2, bMain); - return; - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compile a statement such as "(condition)" -// the condition must be Boolean - -// this class has no constructor, because there is never an instance of this class -// the object returned by Compile is usually type CBotExpression - - -CBotInstr* CBotCondition::Compile(CBotToken* &p, CBotCStack* pStack) -{ - pStack->SetStartError(p->GivStart()); - if (IsOfType(p, ID_OPENPAR)) - { - CBotInstr* inst = CBotBoolExpr::Compile(p, pStack); - if (NULL != inst) - { - if (IsOfType(p, ID_CLOSEPAR)) - { - return inst; - } - pStack->SetError(TX_CLOSEPAR, p->GivStart()); // missing parenthesis - } - delete inst; - } - - pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis - - return NULL; -} - - -////////////////////////////////////////////////////////////////////////////////////// -// compile a statement such as "(condition)" -// the condition must be Boolean -// -// this class has no constructor, because there is never an instance of this -// class -// the object returned by Compile is usually type CBotExpression -// - -CBotInstr* CBotBoolExpr::Compile(CBotToken* &p, CBotCStack* pStack) -{ - pStack->SetStartError(p->GivStart()); - - CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStack); - - if (NULL != inst) - { - if (pStack->GivTypResult().Eq(CBotTypBoolean)) - { - return inst; - } - pStack->SetError(TX_NOTBOOL, p->GivStart()); // is not a boolean - } - - delete inst; - return NULL; -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compile either: -// instruction in parentheses (...) -// a unary expression (negative, not) -// variable name -// variables pre and post-incremented or decremented -// a given number DefineNum -// a constant -// procedure call -// new statement -// -// this class has no constructor, because there is never an instance of this class -// the object returned by Compile is the class corresponding to the instruction - - -CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotCStack* pStk = pStack->TokenStack(); - - pStk->SetStartError(p->GivStart()); - - // is it an expression in parentheses? - if (IsOfType(p, ID_OPENPAR)) - { - CBotInstr* inst = CBotExpression::Compile(p, pStk); - - if (NULL != inst) - { - if (IsOfType(p, ID_CLOSEPAR)) - { - return pStack->Return(inst, pStk); - } - pStk->SetError(TX_CLOSEPAR, p->GivStart()); - } - delete inst; - return pStack->Return(NULL, pStk); - } - - // is this a unary operation? - CBotInstr* inst = CBotExprUnaire::Compile(p, pStk); - if (inst != NULL || !pStk->IsOk()) - return pStack->Return(inst, pStk); - - // is it a variable name? - if (p->GivType() == TokenTypVar) - { - // this may be a method call without the "this." before - inst = CBotExprVar::CompileMethode(p, pStk); - if (inst != NULL) return pStack->Return(inst, pStk); - - - // is it a procedure call? - inst = CBotInstrCall::Compile(p, pStk); - if (inst != NULL || !pStk->IsOk()) - return pStack->Return(inst, pStk); - - - CBotToken* pvar = p; - // no, it an "ordinaty" variable - inst = CBotExprVar::Compile(p, pStk); - - CBotToken* pp = p; - // post incremented or decremented? - if (IsOfType(p, ID_INC, ID_DEC)) - { - if (pStk->GivType() >= CBotTypBoolean) - { - pStk->SetError(TX_BADTYPE, pp); - delete inst; - return pStack->Return(NULL, pStk); - } - - // recompile the variable for read-only - delete inst; - p = pvar; - inst = CBotExprVar::Compile(p, pStk, PR_READ); - p = p->GivNext(); - - CBotPostIncExpr* i = new CBotPostIncExpr(); - i->SetToken(pp); - i->m_Instr = inst; // associated statement - return pStack->Return(i, pStk); - } - return pStack->Return(inst, pStk); - } - - // pre increpemted or pre decremented? - CBotToken* pp = p; - if (IsOfType(p, ID_INC, ID_DEC)) - { - CBotPreIncExpr* i = new CBotPreIncExpr(); - i->SetToken(pp); - - if (p->GivType() == TokenTypVar) - { - if (NULL != (i->m_Instr = CBotExprVar::Compile(p, pStk, PR_READ))) - { - if (pStk->GivType() >= CBotTypBoolean) - { - pStk->SetError(TX_BADTYPE, pp); - delete inst; - return pStack->Return(NULL, pStk); - } - return pStack->Return(i, pStk); - } - delete i; - return pStack->Return(NULL, pStk); - } - } - - // is it a number or DefineNum? - if (p->GivType() == TokenTypNum || - p->GivType() == TokenTypDef ) - { - CBotInstr* inst = CBotExprNum::Compile(p, pStk); - return pStack->Return(inst, pStk); - } - - // is this a chaine? - if (p->GivType() == TokenTypString) - { - CBotInstr* inst = CBotExprAlpha::Compile(p, pStk); - return pStack->Return(inst, pStk); - } - - // is a "true" or "false" - if (p->GivType() == ID_TRUE || - p->GivType() == ID_FALSE ) - { - CBotInstr* inst = CBotExprBool::Compile(p, pStk); - return pStack->Return(inst, pStk); - } - - // is an object to be created with new - if (p->GivType() == ID_NEW) - { - CBotInstr* inst = CBotNew::Compile(p, pStk); - return pStack->Return(inst, pStk); - } - - // is a null pointer - if (IsOfType(p, ID_NULL)) - { - CBotInstr* inst = new CBotExprNull (); - inst->SetToken(pp); - CBotVar* var = CBotVar::Create("", CBotTypNullPointer); - pStk->SetVar(var); - return pStack->Return(inst, pStk); - } - - // is a number nan - if (IsOfType(p, ID_NAN)) - { - CBotInstr* inst = new CBotExprNan (); - inst->SetToken(pp); - CBotVar* var = CBotVar::Create("", CBotTypInt); - var->SetInit(IS_NAN); - pStk->SetVar(var); - return pStack->Return(inst, pStk); - } - - - return pStack->Return(NULL, pStk); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// -// Management of pre-and post increment / decrement -// There is no routine Compiles, the object is created directly -// Compiles in CBotParExpr :: - - -CBotPostIncExpr::CBotPostIncExpr() -{ - m_Instr = NULL; - name = "CBotPostIncExpr"; -} - -CBotPostIncExpr::~CBotPostIncExpr() -{ - delete m_Instr; -} - -CBotPreIncExpr::CBotPreIncExpr() -{ - m_Instr = NULL; - name = "CBotPreIncExpr"; -} - -CBotPreIncExpr::~CBotPreIncExpr() -{ - delete m_Instr; -} - -bool CBotPostIncExpr::Execute(CBotStack* &pj) -{ - CBotStack* pile1 = pj->AddStack(this); - CBotStack* pile2 = pile1; - - CBotVar* var1 = NULL; - - // retrieves the variable fields and indexes according - if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false; - - pile1->SetState(1); - pile1->SetCopyVar(var1); // place le résultat (avant incrémentation); - - CBotStack* pile3 = pile2->AddStack(this); - if (pile3->IfStep()) return false; - - if (var1->GivInit() == IS_NAN) - { - pile1->SetError(TX_OPNAN, &m_token); - } - - if (var1->GivInit() != IS_DEF) - { - pile1->SetError(TX_NOTINIT, &m_token); - } - - if (GivTokenType() == ID_INC) var1->Inc(); - else var1->Dec(); - - return pj->Return(pile1); // operation done, result on pile2 -} - -void CBotPostIncExpr::RestoreState(CBotStack* &pj, bool bMain) -{ - if (!bMain) return; - - CBotStack* pile1 = pj->RestoreStack(this); - if (pile1 == NULL) return; - - ((CBotExprVar*)m_Instr)->RestoreStateVar(pile1, bMain); - - if (pile1 != NULL) pile1->RestoreStack(this); -} - -bool CBotPreIncExpr::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if (pile->IfStep()) return false; - - CBotVar* var1; - - if (pile->GivState() == 0) - { - CBotStack* pile2 = pile; - // retrieves the variable fields and indexes according - // pile2 is modified on return - if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false; - - if (var1->GivInit() == IS_NAN) - { - pile->SetError(TX_OPNAN, &m_token); - return pj->Return(pile); // operation performed - } - - if (var1->GivInit() != IS_DEF) - { - pile->SetError(TX_NOTINIT, &m_token); - return pj->Return(pile); // operation performed - } - - if (GivTokenType() == ID_INC) var1->Inc(); - else var1->Dec(); // ((CBotVarInt*)var1)->m_val - - pile->IncState(); - } - - if (!m_Instr->Execute(pile)) return false; - return pj->Return(pile); // operation performed -} - - -void CBotPreIncExpr::RestoreState(CBotStack* &pj, bool bMain) -{ - if (!bMain) return; - - CBotStack* pile = pj->RestoreStack(this); - if (pile == NULL) return; - - if (pile->GivState() == 0) - { - return; - } - - m_Instr->RestoreState(pile, bMain); -} - - -////////////////////////////////////////////////////////////////////////////////////// -// compile an unary expression -// + -// - -// not -// ! -// ~ - -CBotExprUnaire::CBotExprUnaire() -{ - m_Expr = NULL; - name = "CBotExprUnaire"; -} - -CBotExprUnaire::~CBotExprUnaire() -{ - delete m_Expr; -} - -CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack) -{ - int op = p->GivType(); - CBotToken* pp = p; - if (!IsOfTypeList( p, ID_ADD, ID_SUB, ID_LOG_NOT, ID_TXT_NOT, ID_NOT, 0 )) return NULL; - - CBotCStack* pStk = pStack->TokenStack(pp); - - CBotExprUnaire* inst = new CBotExprUnaire(); - inst->SetToken(pp); - - if (NULL != (inst->m_Expr = CBotParExpr::Compile( p, pStk ))) - { - if (op == ID_ADD && pStk->GivType() < CBotTypBoolean) // only with the number - return pStack->Return(inst, pStk); - if (op == ID_SUB && pStk->GivType() < CBotTypBoolean) // only with the numer - return pStack->Return(inst, pStk); - if (op == ID_NOT && pStk->GivType() < CBotTypFloat) // only with an integer - return pStack->Return(inst, pStk); - if (op == ID_LOG_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean - return pStack->Return(inst, pStk); - if (op == ID_TXT_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean - return pStack->Return(inst, pStk); - - pStk->SetError(TX_BADTYPE, &inst->m_token); - } - delete inst; - return pStack->Return(NULL, pStk); -} - -// executes unary expression - -bool CBotExprUnaire::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if (pile->GivState() == 0) - { - if (!m_Expr->Execute(pile)) return false; // interrupted ? - pile->IncState(); - } - - CBotStack* pile2 = pile->AddStack(); - if (pile2->IfStep()) return false; - - CBotVar* var = pile->GivVar(); // get the result on the stack - - switch (GivTokenType()) - { - case ID_ADD: - break; - case ID_SUB: - var->Neg(); // change the sign - break; - case ID_NOT: - case ID_LOG_NOT: - case ID_TXT_NOT: - var->Not(); - break; - } - return pj->Return(pile); // forwards below -} - -void CBotExprUnaire::RestoreState(CBotStack* &pj, bool bMain) -{ - if (!bMain) return; - - CBotStack* pile = pj->RestoreStack(this); - if ( pile == NULL) return; - - if (pile->GivState() == 0) - { - m_Expr->RestoreState(pile, bMain); // interrupted here! - return; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// -// index management for arrays -// array [ expression ] - - -CBotIndexExpr::CBotIndexExpr() -{ - m_expr = NULL; - name = "CBotIndexExpr"; -} - -CBotIndexExpr::~CBotIndexExpr() -{ - delete m_expr; -} - -// finds a field from the instance at compile time - -bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) -{ - if (pVar->GivType(1) != CBotTypArrayPointer) - ASM_TRAP(); - - pVar = ((CBotVarArray*)pVar)->GivItem(0, false); // at compile time makes the element [0] - if (pVar == NULL) - { - pile->SetError(TX_OUTARRAY, m_token.GivEnd()); - return false; - } - if (m_next3 != NULL) return m_next3->ExecuteVar(pVar, pile); - return true; -} - -// attention, changes the pointer to the stack intentionally -// place the index calculated on the additional stack - - -bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) -{ - CBotStack* pj = pile; - - if (pVar->GivType(1) != CBotTypArrayPointer) - ASM_TRAP(); - - pile = pile->AddStack(); - - if (pile->GivState() == 0) - { - if (!m_expr->Execute(pile)) return false; - pile->IncState(); - } - // handles array - - CBotVar* p = pile->GivVar(); // result on the stack - - if (p == NULL || p->GivType() > CBotTypDouble) - { - pile->SetError(TX_BADINDEX, prevToken); - return pj->Return(pile); - } - - int n = p->GivValInt(); // position in the table - - pVar = ((CBotVarArray*)pVar)->GivItem(n, bExtend); - if (pVar == NULL) - { - pile->SetError(TX_OUTARRAY, prevToken); - return pj->Return(pile); - } - - pVar->Maj(pile->GivPUser(), true); - - if ( m_next3 != NULL && - !m_next3->ExecuteVar(pVar, pile, prevToken, bStep, bExtend) ) return false; - - // does not release the stack - // to avoid recalculation of the index twice where appropriate - return true; -} - -void CBotIndexExpr::RestoreStateVar(CBotStack* &pile, bool bMain) -{ - pile = pile->RestoreStack(); - if (pile == NULL) return; - - if (bMain && pile->GivState() == 0) - { - m_expr->RestoreState(pile, true); - return; - } - - if (m_next3) - m_next3->RestoreStateVar(pile, bMain); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// -// field management in an instance (dot operator) -// toto.x - - -CBotFieldExpr::CBotFieldExpr() -{ - name = "CBotFieldExpr"; - m_nIdent = 0; -} - -CBotFieldExpr::~CBotFieldExpr() -{ -} - -void CBotFieldExpr::SetUniqNum(int num) -{ - m_nIdent = num; -} - - -// find a field from the instance at compile - -bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) -{ - if (pVar->GivType(1) != CBotTypPointer) - ASM_TRAP(); - - pVar = pVar->GivItemRef(m_nIdent); - if (pVar == NULL) - { - pile->SetError(TX_NOITEM, &m_token); - return false; - } - - if ( m_next3 != NULL && - !m_next3->ExecuteVar(pVar, pile) ) return false; - - return true; -} - -bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) -{ - CBotStack* pj = pile; - pile = pile->AddStack(this); // changes in output stack - if (pile == EOX) return true; - - - if (pVar->GivType(1) != CBotTypPointer) - ASM_TRAP(); - - CBotVarClass* pItem = pVar->GivPointer(); - if (pItem == NULL) - { - pile->SetError(TX_NULLPT, prevToken); - return pj->Return(pile); - } - if (pItem->GivUserPtr() == OBJECTDELETED) - { - pile->SetError(TX_DELETEDPT, prevToken); - return pj->Return(pile); - } - - if (bStep && pile->IfStep()) return false; - - pVar = pVar->GivItemRef(m_nIdent); - if (pVar == NULL) - { - pile->SetError(TX_NOITEM, &m_token); - return pj->Return(pile); - } - - if (pVar->IsStatic()) - { - // for a static variable, takes it in the class itself - CBotClass* pClass = pItem->GivClass(); - pVar = pClass->GivItem(m_token.GivString()); - } - - // request the update of the element, if applicable - pVar->Maj(pile->GivPUser(), true); - - if ( m_next3 != NULL && - !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, bExtend) ) return false; - - // does not release the stack - // to maintain the state SetState () corresponding to step - - return true; -} - -void CBotFieldExpr::RestoreStateVar(CBotStack* &pj, bool bMain) -{ - pj = pj->RestoreStack(this); - if (pj == NULL) return; - - if (m_next3 != NULL) - m_next3->RestoreStateVar(pj, bMain); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////// -// compile a left operand for an assignment -CBotLeftExpr::CBotLeftExpr() -{ - name = "CBotLeftExpr"; - m_nIdent = 0; -} - -CBotLeftExpr::~CBotLeftExpr() -{ -} - -// compiles an expression for a left-operand (left of an assignment) -// this can be -// toto -// toto[ 3 ] -// toto.x -// toto.pos.x -// toto[2].pos.x -// toto[1].pos[2].x -// toto[1][2][3] - -CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotCStack* pStk = pStack->TokenStack(); - - pStk->SetStartError(p->GivStart()); - - // is it a variable name? - if (p->GivType() == TokenTypVar) - { - CBotLeftExpr* inst = new CBotLeftExpr(); // creates the object - - inst->SetToken(p); - - CBotVar* var; - - if (NULL != (var = pStk->FindVar(p))) // seek if known variable - { - inst->m_nIdent = var->GivUniqNum(); - if (inst->m_nIdent > 0 && inst->m_nIdent < 9000) - { - if ( var->IsPrivate(PR_READ) && - !pStk->GivBotCall()->m_bCompileClass) - { - pStk->SetError(TX_PRIVATE, p); - goto err; - } - // this is an element of the current class - // adds the equivalent of this. before - CBotToken pthis("this"); - inst->SetToken(&pthis); - inst->m_nIdent = -2; // indent for this - - CBotFieldExpr* i = new CBotFieldExpr(); // new element - i->SetToken(p); // keeps the name of the token - inst->AddNext3(i); // add after - - var = pStk->FindVar(pthis); - var = var->GivItem(p->GivString()); - i->SetUniqNum(var->GivUniqNum()); - } - p = p->GivNext(); // next token - - while (true) - { - if (var->GivType() == CBotTypArrayPointer) - { - if (IsOfType( p, ID_OPBRK )) - { - CBotIndexExpr* i = new CBotIndexExpr(); - i->m_expr = CBotExpression::Compile(p, pStk); - inst->AddNext3(i); // add to the chain - - var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0] - - if (i->m_expr == NULL) - { - pStk->SetError(TX_BADINDEX, p->GivStart()); - goto err; - } - - if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) - { - pStk->SetError(TX_CLBRK, p->GivStart()); - goto err; - } - continue; - } - } - - if (var->GivType(1) == CBotTypPointer) // for classes - { - if (IsOfType(p, ID_DOT)) - { - CBotToken* pp = p; - - CBotFieldExpr* i = new CBotFieldExpr(); // new element - i->SetToken(pp); // keeps the name of the token - inst->AddNext3(i); // adds after - - if (p->GivType() == TokenTypVar) // must be a name - { - var = var->GivItem(p->GivString()); // get item correspondent - if (var != NULL) - { - if ( var->IsPrivate(PR_READ) && - !pStk->GivBotCall()->m_bCompileClass) - { - pStk->SetError(TX_PRIVATE, pp); - goto err; - } - - i->SetUniqNum(var->GivUniqNum()); - p = p->GivNext(); // skips the name - continue; - } - pStk->SetError(TX_NOITEM, p); - } - pStk->SetError(TX_DOT, p->GivStart()); - goto err; - } - } - break; - } - - - if (pStk->IsOk()) return (CBotLeftExpr*) pStack->Return(inst, pStk); - } - pStk->SetError(TX_UNDEFVAR, p); -err: - delete inst; - return (CBotLeftExpr*) pStack->Return(NULL, pStk); - } - - return (CBotLeftExpr*) pStack->Return(NULL, pStk); -} - -// runs, is a variable and assigns the result to the stack -bool CBotLeftExpr::Execute(CBotStack* &pj, CBotStack* array) -{ - CBotStack* pile = pj->AddStack(); - - CBotVar* var1 = NULL; - CBotVar* var2 = NULL; - // fetch a variable (not copy) - if (!ExecuteVar(var1, array, NULL, false)) return false; - - if (pile->IfStep()) return false; - - if (var1) - { - var2 = pj->GivVar(); // result on the input stack - if (var2) - { - CBotTypResult t1 = var1->GivTypResult(); - CBotTypResult t2 = var2->GivTypResult(); - if (t2.Eq(CBotTypPointer)) - { - CBotClass* c1 = t1.GivClass(); - CBotClass* c2 = t2.GivClass(); - if ( !c2->IsChildOf(c1)) - { - CBotToken* pt = &m_token; - pile->SetError(TX_BADTYPE, pt); - return pj->Return(pile); // operation performed - } - } - var1->SetVal(var2); // do assignment - } - pile->SetCopyVar(var1); // replace the stack with the copy of the variable - // (for name) - } - - return pj->Return(pile); // operation performed -} - -// fetch a variable during compilation - -bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) -{ - pVar = pile->FindVar(m_token); - if (pVar == NULL) return false; - - if ( m_next3 != NULL && - !m_next3->ExecuteVar(pVar, pile) ) return false; - - return true; -} - -// fetch the variable at runtume - -bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep) -{ - pile = pile->AddStack(this); - - pVar = pile->FindVar(m_nIdent); - if (pVar == NULL) - { -#ifdef _DEBUG - ASM_TRAP(); -#endif - pile->SetError(2, &m_token); - return false; - } - - if (bStep && m_next3 == NULL && pile->IfStep()) return false; - - if ( m_next3 != NULL && - !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, true) ) return false; - - return true; -} - -void CBotLeftExpr::RestoreStateVar(CBotStack* &pile, bool bMain) -{ - pile = pile->RestoreStack(this); - if (pile == NULL) return; - - if (m_next3 != NULL) - m_next3->RestoreStateVar(pile, bMain); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// converts a string into integer -// may be of the form 0xabc123 - -long GivNumInt(const char* p) -{ - long num = 0; - while (*p >= '0' && *p <= '9') - { - num = num * 10 + *p - '0'; - p++; - } - if (*p == 'x' || *p == 'X') - { - while (*++p != 0) - { - if (*p >= '0' && *p <= '9') - { - num = num * 16 + *p - '0'; - continue; - } - if (*p >= 'A' && *p <= 'F') - { - num = num * 16 + *p - 'A' + 10; - continue; - } - if (*p >= 'a' && *p <= 'f') - { - num = num * 16 + *p - 'a' + 10; - continue; - } - break; - } - } - return num; -} - -// converts a string into a float number -extern float GivNumFloat(const char* p) -{ - double num = 0; - double div = 10; - bool bNeg = false; - - if (*p == '-') - { - bNeg = true; - p++; - } - while (*p >= '0' && *p <= '9') - { - num = num * 10. + (*p - '0'); - p++; - } - - if (*p == '.') - { - p++; - while (*p >= '0' && *p <= '9') - { - num = num + (*p - '0') / div; - div = div * 10; - p++; - } - } - - int exp = 0; - if (*p == 'e' || *p == 'E') - { - char neg = 0; - p++; - if (*p == '-' || *p == '+') neg = *p++; - - while (*p >= '0' && *p <= '9') - { - exp = exp * 10 + (*p - '0'); - p++; - } - if (neg == '-') exp = -exp; - } - - while (exp > 0) - { - num *= 10.0; - exp--; - } - - while (exp < 0) - { - num /= 10.0; - exp++; - } - - if (bNeg) num = -num; - return (float)num; -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compiles a token representing a number -CBotExprNum::CBotExprNum() -{ - name = "CBotExprNum"; -} - -CBotExprNum::~CBotExprNum() -{ -} - -CBotInstr* CBotExprNum::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotCStack* pStk = pStack->TokenStack(); - - CBotExprNum* inst = new CBotExprNum(); - - inst->SetToken(p); - CBotString s = p->GivString(); - - inst->m_numtype = CBotTypInt; - if (p->GivType() == TokenTypDef) - { - inst->m_valint = p->GivIdKey(); - } - else - { - if (s.Find('.') >= 0 || ( s.Find('x') < 0 && ( s.Find('e') >= 0 || s.Find('E') >= 0 ) )) - { - inst->m_numtype = CBotTypFloat; - inst->m_valfloat = GivNumFloat(s); - } - else - { - inst->m_valint = GivNumInt(s); - } - } - - if (pStk->NextToken(p)) - { - CBotVar* var = CBotVar::Create((CBotToken*)NULL, inst->m_numtype); - pStk->SetVar(var); - - return pStack->Return(inst, pStk); - } - delete inst; - return pStack->Return(NULL, pStk); -} - -// execute, returns the corresponding number - -bool CBotExprNum::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if (pile->IfStep()) return false; - - CBotVar* var = CBotVar::Create((CBotToken*)NULL, m_numtype); - - CBotString nombre ; - if (m_token.GivType() == TokenTypDef) - { - nombre = m_token.GivString(); - } - - switch (m_numtype) - { - case CBotTypShort: - case CBotTypInt: - var->SetValInt(m_valint, nombre); - break; - case CBotTypFloat: - var->SetValFloat(m_valfloat); - break; - } - pile->SetVar(var); // place on the stack - - return pj->Return(pile); // it's ok -} - -void CBotExprNum::RestoreState(CBotStack* &pj, bool bMain) -{ - if (bMain) pj->RestoreStack(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compile a token representing a string - -CBotExprAlpha::CBotExprAlpha() -{ - name = "CBotExprAlpha"; -} - -CBotExprAlpha::~CBotExprAlpha() -{ -} - -CBotInstr* CBotExprAlpha::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotCStack* pStk = pStack->TokenStack(); - - CBotExprAlpha* inst = new CBotExprAlpha(); - - inst->SetToken(p); - p = p->GivNext(); - - CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString); - pStk->SetVar(var); - - return pStack->Return(inst, pStk); -} - -// execute, returns the corresponding string - -bool CBotExprAlpha::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if (pile->IfStep()) return false; - - CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString); - - CBotString chaine = m_token.GivString(); - chaine = chaine.Mid(1, chaine.GivLength()-2); // removes the quotes - - var->SetValString(chaine); // value of the number - - pile->SetVar(var); // put on the stack - - return pj->Return(pile); -} - -void CBotExprAlpha::RestoreState(CBotStack* &pj, bool bMain) -{ - if (bMain) pj->RestoreStack(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compile a token representing true or false - -CBotExprBool::CBotExprBool() -{ - name = "CBotExprBool"; -} - -CBotExprBool::~CBotExprBool() -{ -} - -CBotInstr* CBotExprBool::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotCStack* pStk = pStack->TokenStack(); - CBotExprBool* inst = NULL; - - if ( p->GivType() == ID_TRUE || - p->GivType() == ID_FALSE ) - { - inst = new CBotExprBool(); - inst->SetToken(p); // stores the operation false or true - p = p->GivNext(); - - CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean); - pStk->SetVar(var); - } - - return pStack->Return(inst, pStk); -} - -// executes, returns true or false - -bool CBotExprBool::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if (pile->IfStep()) return false; - - CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean); - - if (GivTokenType() == ID_TRUE) var->SetValInt(1); - else var->SetValInt(0); - - pile->SetVar(var); // put on the stack - return pj->Return(pile); // forwards below -} - -void CBotExprBool::RestoreState(CBotStack* &pj, bool bMain) -{ - if (bMain) pj->RestoreStack(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// management of the operand "null" - -CBotExprNull::CBotExprNull() -{ - name = "CBotExprNull"; -} - -CBotExprNull::~CBotExprNull() -{ -} - -// executes, returns an empty pointer - -bool CBotExprNull::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if (pile->IfStep()) return false; - CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypNullPointer); - - var->SetInit(true); // null pointer valid - pile->SetVar(var); // place on the stack - return pj->Return(pile); // forwards below -} - -void CBotExprNull::RestoreState(CBotStack* &pj, bool bMain) -{ - if (bMain) pj->RestoreStack(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// management of the operand "nan" - -CBotExprNan::CBotExprNan() -{ - name = "CBotExprNan"; -} - -CBotExprNan::~CBotExprNan() -{ -} - -// executes, returns null pointer - -bool CBotExprNan::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); - - if (pile->IfStep()) return false; - CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypInt); - - var->SetInit(IS_NAN); // nan - pile->SetVar(var); // put on the stack - return pj->Return(pile); // forward below -} - -void CBotExprNan::RestoreState(CBotStack* &pj, bool bMain) -{ - if (bMain) pj->RestoreStack(this); -} - -////////////////////////////////////////////////////////////////////////////////////// -// compile a variable name -// check that it is known on the stack -// and it has been initialized - -CBotExprVar::CBotExprVar() -{ - name = "CBotExprVar"; - m_nIdent = 0; -} - -CBotExprVar::~CBotExprVar() -{ -} - -CBotInstr* CBotExprVar::Compile(CBotToken* &p, CBotCStack* pStack, int privat) -{ - CBotToken* pDebut = p; - CBotCStack* pStk = pStack->TokenStack(); - - pStk->SetStartError(p->GivStart()); - - // is it a variable? - if (p->GivType() == TokenTypVar) - { - CBotInstr* inst = new CBotExprVar(); // create the object - - inst->SetToken(p); - - CBotVar* var; - - if (NULL != (var = pStk->FindVar(p))) // seek if known variable - { - int ident = var->GivUniqNum(); - ((CBotExprVar*)inst)->m_nIdent = ident; // identifies variable by its number - - if (ident > 0 && ident < 9000) - { - if ( var->IsPrivate(privat) && - !pStk->GivBotCall()->m_bCompileClass) - { - pStk->SetError(TX_PRIVATE, p); - goto err; - } - - // This is an element of the current class - // ads the equivalent of this. before - /// \TODO need to be fixed revised and fixed after adding unit - ///tests - CBotToken token("this"); - inst->SetToken(&token); - ((CBotExprVar*)inst)->m_nIdent = -2; // identificator for this - - CBotFieldExpr* i = new CBotFieldExpr(); // new element - i->SetToken(p); // keeps the name of the token - i->SetUniqNum(ident); - inst->AddNext3(i); // added after - } - - p = p->GivNext(); // next token - - while (true) - { - if (var->GivType() == CBotTypArrayPointer) - { - if (IsOfType( p, ID_OPBRK )) // check if there is an aindex - { - CBotIndexExpr* i = new CBotIndexExpr(); - i->m_expr = CBotExpression::Compile(p, pStk); // compile the formula - inst->AddNext3(i); // add to the chain - - var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0] - - if (i->m_expr == NULL) - { - pStk->SetError(TX_BADINDEX, p->GivStart()); - goto err; - } - if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) - { - pStk->SetError(TX_CLBRK, p->GivStart()); - goto err; - } - continue; - } - } - if (var->GivType(1) == CBotTypPointer) // for classes - { - if (IsOfType(p, ID_DOT)) - { - CBotToken* pp = p; - - if (p->GivType() == TokenTypVar) // must be a name - { - if (p->GivNext()->GivType() == ID_OPENPAR) // a method call? - { - CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var); - if (!pStk->IsOk()) goto err; - inst->AddNext3(i); // added after - return pStack->Return(inst, pStk); - } - else - { - CBotFieldExpr* i = new CBotFieldExpr(); // new element - i->SetToken(pp); // keeps the name of the token - inst->AddNext3(i); // add after - var = var->GivItem(p->GivString()); // get item correspondent - if (var != NULL) - { - i->SetUniqNum(var->GivUniqNum()); - if ( var->IsPrivate() && - !pStk->GivBotCall()->m_bCompileClass) - { - pStk->SetError(TX_PRIVATE, pp); - goto err; - } - } - } - - - if (var != NULL) - { - p = p->GivNext(); // skips the name - continue; - } - pStk->SetError(TX_NOITEM, p); - goto err; - } - pStk->SetError(TX_DOT, p->GivStart()); - goto err; - } - } - - break; - } - - pStk->SetCopyVar(var); // place the copy of the variable on the stack (for type) - if (pStk->IsOk()) return pStack->Return(inst, pStk); - } - pStk->SetError(TX_UNDEFVAR, p); -err: - delete inst; - return pStack->Return(NULL, pStk); - } - - return pStack->Return(NULL, pStk); -} - -CBotInstr* CBotExprVar::CompileMethode(CBotToken* &p, CBotCStack* pStack) -{ - CBotToken* pp = p; - CBotCStack* pStk = pStack->TokenStack(); - - pStk->SetStartError(pp->GivStart()); - - // is it a variable ? - if (pp->GivType() == TokenTypVar) - { - CBotToken pthis("this"); - CBotVar* var = pStk->FindVar(pthis); - if (var == 0) return pStack->Return(NULL, pStk); - - CBotInstr* inst = new CBotExprVar(); - - // this is an element of the current class - // adds the equivalent of this. before - - inst->SetToken(&pthis); - ((CBotExprVar*)inst)->m_nIdent = -2; // ident for this - - CBotToken* pp = p; - - if (pp->GivType() == TokenTypVar) - { - if (pp->GivNext()->GivType() == ID_OPENPAR) // a method call? - { - CBotInstr* i = CBotInstrMethode::Compile(pp, pStk, var); - if (pStk->IsOk()) - { - inst->AddNext3(i); // add after - p = pp; // previous instruction - return pStack->Return(inst, pStk); - } - pStk->SetError(0,0); // the error is not adressed here - } - } - delete inst; - } - return pStack->Return(NULL, pStk); -} - - -// execute, making the value of a variable - -bool CBotExprVar::Execute(CBotStack* &pj) -{ - CBotVar* pVar = NULL; - CBotStack* pile = pj->AddStack(this); - - CBotStack* pile1 = pile; - - if (pile1->GivState() == 0) - { - if (!ExecuteVar(pVar, pile, NULL, true)) return false; // Get the variable fields and indexes according - - if (pVar) pile1->SetCopyVar(pVar); // place a copy on the stack - else - { - return pj->Return(pile1); - } - pile1->IncState(); - } - - pVar = pile1->GivVar(); - - if (pVar == NULL) - { - return pj->Return(pile1); - } - - if (pVar->GivInit() == IS_UNDEF) - { - CBotToken* pt = &m_token; - while (pt->GivNext() != NULL) pt = pt->GivNext(); - pile1->SetError(TX_NOTINIT, pt); - return pj->Return(pile1); - } - return pj->Return(pile1); // operation completed -} - -void CBotExprVar::RestoreState(CBotStack* &pj, bool bMain) -{ - if (!bMain) return; - - CBotStack* pile = pj->RestoreStack(this); - if (pile == NULL) return; - - CBotStack* pile1 = pile; - - if (pile1->GivState() == 0) - { - RestoreStateVar(pile, bMain); // retrieves the variable fields and indexes according - return; - } -} - -// fetch a variable at runtime - -bool CBotExprVar::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep) -{ - CBotStack* pile = pj; - pj = pj->AddStack(this); - - if (bStep && m_nIdent>0 && pj->IfStep()) return false; - - pVar = pj->FindVar(m_nIdent, true); // tries with the variable update if necessary - if (pVar == NULL) - { -#ifdef _DEBUG - ASM_TRAP(); -#endif - pj->SetError(1, &m_token); - return false; - } - if ( m_next3 != NULL && - !m_next3->ExecuteVar(pVar, pj, &m_token, bStep, false) ) - return false; // field of an instance, table, methode - - return pile->ReturnKeep(pj); // does not put on stack but get the result if a method was called -} - - -// fetch variable at runtime - -void CBotExprVar::RestoreStateVar(CBotStack* &pj, bool bMain) -{ - pj = pj->RestoreStack(this); - if (pj == NULL) return; - - if (m_next3 != NULL) - m_next3->RestoreStateVar(pj, bMain); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// compile a list of parameters - -CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars) -{ - bool first = true; - CBotInstr* ret = NULL; // to return to the list - - CBotCStack* pile = pStack; - int i = 0; - - if (IsOfType(p, ID_OPENPAR)) - { - int start, end; - if (!IsOfType(p, ID_CLOSEPAR)) while (true) - { - start = p->GivStart(); - pile = pile->TokenStack(); // keeps the result on the stack - - if (first) pStack->SetStartError(start); - first = false; - - CBotInstr* param = CBotExpression::Compile(p, pile); - end = p->GivStart(); - - if (!pile->IsOk()) - { - return pStack->Return(NULL, pile); - } - - if (ret == NULL) ret = param; - else ret->AddNext(param); // construct the list - - if (param != NULL) - { - if (pile->GivTypResult().Eq(99)) - { - delete pStack->TokenStack(); - pStack->SetError(TX_VOID, p->GivStart()); - return NULL; - } - ppVars[i] = pile->GivVar(); - ppVars[i]->GivToken()->SetPos(start, end); - i++; - - if (IsOfType(p, ID_COMMA)) continue; // skips the comma - if (IsOfType(p, ID_CLOSEPAR)) break; - } - - pStack->SetError(TX_CLOSEPAR, p->GivStart()); - delete pStack->TokenStack(); - return NULL; - } - } - ppVars[i] = NULL; - return ret; -} - -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////// -// compile a method call - -CBotInstrMethode::CBotInstrMethode() -{ - m_Parameters = NULL; - m_MethodeIdent = 0; - name = "CBotInstrMethode"; -} - -CBotInstrMethode::~CBotInstrMethode() -{ - delete m_Parameters; -} - -CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var) -{ - CBotInstrMethode* inst = new CBotInstrMethode(); - inst->SetToken(p); // corresponding token - - if (NULL != var) - { - CBotToken* pp = p; - p = p->GivNext(); - - if (p->GivType() == ID_OPENPAR) - { - inst->m_NomMethod = pp->GivString(); - - // compiles the list of parameters - CBotVar* ppVars[1000]; - inst->m_Parameters = CompileParams(p, pStack, ppVars); - - if (pStack->IsOk()) - { - CBotClass* pClass = var->GivClass(); // pointer to the class - inst->m_ClassName = pClass->GivName(); // name of the class - CBotTypResult r = pClass->CompileMethode(inst->m_NomMethod, var, ppVars, - pStack, inst->m_MethodeIdent); - delete pStack->TokenStack(); // release parameters on the stack - inst->m_typRes = r; - - if (inst->m_typRes.GivType() > 20) - { - pStack->SetError(inst->m_typRes.GivType(), pp); - delete inst; - return NULL; - } - // put the result on the stack to have something - if (inst->m_typRes.GivType() > 0) - { - CBotVar* pResult = CBotVar::Create("", inst->m_typRes); - if (inst->m_typRes.Eq(CBotTypClass)) - { - pResult->SetClass(inst->m_typRes.GivClass()); - } - pStack->SetVar(pResult); - } - return inst; - } - delete inst; - return NULL; - } - } - pStack->SetError(1234, p); - delete inst; - return NULL; -} - -// execute the method call - -bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend) -{ - CBotVar* ppVars[1000]; - CBotStack* pile1 = pj->AddStack(this, true); // a place for the copy of This - - if (pVar->GivPointer() == NULL) - { - pj->SetError(TX_NULLPT, prevToken); - } - - if (pile1->IfStep()) return false; - - CBotStack* pile2 = pile1->AddStack(); // for the next parameters - - if ( pile1->GivState() == 0) - { - CBotVar* pThis = CBotVar::Create(pVar); - pThis->Copy(pVar); - // this value should be taken before the evaluation parameters - // Test.Action (Test = Other); - // action must act on the value before test = Other! - - pThis->SetName("this"); - pThis->SetUniqNum(-2); - pile1->AddVar(pThis); - pile1->IncState(); - } - int i = 0; - - CBotInstr* p = m_Parameters; - // evaluate the parameters - // and places the values on the stack - // to be interrupted at any time - - if (p != NULL) while ( true) - { - if (pile2->GivState() == 0) - { - if (!p->Execute(pile2)) return false; // interrupted here? - if (!pile2->SetState(1)) return false; // special mark to recognize parameters - } - ppVars[i++] = pile2->GivVar(); // construct the list of pointers - pile2 = pile2->AddStack(); // space on the stack for the result - p = p->GivNext(); - if ( p == NULL) break; - } - ppVars[i] = NULL; - - CBotClass* pClass = CBotClass::Find(m_ClassName); - CBotVar* pThis = pile1->FindVar(-2); - CBotVar* pResult = NULL; - if (m_typRes.GivType() > 0) pResult = CBotVar::Create("", m_typRes); - if (m_typRes.Eq(CBotTypClass)) - { - pResult->SetClass(m_typRes.GivClass()); - } - CBotVar* pRes = pResult; - - if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod, - pThis, ppVars, - pResult, pile2, GivToken())) return false; - if (pRes != pResult) delete pRes; - - pVar = NULL; // does not return value for this - return pj->Return(pile2); // release the entire stack -} - -void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain) -{ - if (!bMain) return; - - CBotVar* ppVars[1000]; - CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This - if (pile1 == NULL) return; - - CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming - if (pile2 == NULL) return; - - CBotVar* pThis = pile1->FindVar("this"); - pThis->SetUniqNum(-2); - - int i = 0; - - CBotInstr* p = m_Parameters; - // evaluate the parameters - // and places the values on the stack - // to be interrupted at any time - - if (p != NULL) while ( true) - { - if (pile2->GivState() == 0) - { - p->RestoreState(pile2, true); // interrupted here! - return; - } - ppVars[i++] = pile2->GivVar(); // construct the list of pointers - pile2 = pile2->RestoreStack(); - if (pile2 == NULL) return; - - p = p->GivNext(); - if ( p == NULL) break; - } - ppVars[i] = NULL; - - CBotClass* pClass = CBotClass::Find(m_ClassName); - CBotVar* pResult = NULL; - - CBotVar* pRes = pResult; - - pClass->RestoreMethode(m_MethodeIdent, m_NomMethod, - pThis, ppVars, pile2); -} - - -bool CBotInstrMethode::Execute(CBotStack* &pj) -{ - CBotVar* ppVars[1000]; - CBotStack* pile1 = pj->AddStack(this, true); // place for the copy of This - - if (pile1->IfStep()) return false; - - CBotStack* pile2 = pile1->AddStack(); // and for the parameters coming - - if ( pile1->GivState() == 0) - { - CBotVar* pThis = pile1->CopyVar(m_token); - // this value should be taken before the evaluation parameters - // Test.Action (Test = Other); - // Action must act on the value before test = Other! - pThis->SetName("this"); - pile1->AddVar(pThis); - pile1->IncState(); - } - int i = 0; - - CBotInstr* p = m_Parameters; - // evaluate the parameters - // and places the values on the stack - // to be interrupted at any time - if (p != NULL) while ( true) - { - if (pile2->GivState() == 0) - { - if (!p->Execute(pile2)) return false; // interrupted here? - if (!pile2->SetState(1)) return false; // special mark to recognize parameters - } - ppVars[i++] = pile2->GivVar(); // construct the list of pointers - pile2 = pile2->AddStack(); // space on the stack for the results - p = p->GivNext(); - if ( p == NULL) break; - } - ppVars[i] = NULL; - - CBotClass* pClass = CBotClass::Find(m_ClassName); - CBotVar* pThis = pile1->FindVar("this"); - CBotVar* pResult = NULL; - if (m_typRes.GivType()>0) pResult = CBotVar::Create("", m_typRes); - if (m_typRes.Eq(CBotTypClass)) - { - pResult->SetClass(m_typRes.GivClass()); - } - CBotVar* pRes = pResult; - - if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod, - pThis, ppVars, - pResult, pile2, GivToken())) return false; // interupted - - // set the new value of this in place of the old variable - CBotVar* old = pile1->FindVar(m_token); - old->Copy(pThis, false); - - if (pRes != pResult) delete pRes; - - return pj->Return(pile2); // release the entire stack -} - -/////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////// -// compile an instruction "new" - -CBotNew::CBotNew() -{ - name = "CBotNew"; - m_Parameters = NULL; - m_nMethodeIdent = 0; -} - -CBotNew::~CBotNew() -{ -} - -CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotToken* pp = p; - if (!IsOfType(p, ID_NEW)) return NULL; - - // verifies that the token is a class name - if (p->GivType() != TokenTypVar) return NULL; - - CBotClass* pClass = CBotClass::Find(p); - if (pClass == NULL) - { - pStack->SetError(TX_BADNEW, p); - return NULL; - } - - CBotNew* inst = new CBotNew(); - inst->SetToken(pp); - - inst->m_vartoken = p; - p = p->GivNext(); - - // creates the object on the "job" - // with a pointer to the object - CBotVar* pVar = CBotVar::Create("", pClass); - - // do the call of the creator - CBotCStack* pStk = pStack->TokenStack(); - { - // check if there are parameters - CBotVar* ppVars[1000]; - inst->m_Parameters = CompileParams(p, pStk, ppVars); - if (!pStk->IsOk()) goto error; - - // constructor exist? - CBotTypResult r = pClass->CompileMethode(pClass->GivName(), pVar, ppVars, pStk, inst->m_nMethodeIdent); - delete pStk->TokenStack(); // release extra stack - int typ = r.GivType(); - - // if there is no constructor, and no parameters either, it's ok - if (typ == TX_UNDEFCALL && inst->m_Parameters == NULL) typ = 0; - pVar->SetInit(true); // mark the instance as init - - if (typ>20) - { - pStk->SetError(typ, inst->m_vartoken.GivEnd()); - goto error; - } - - // if the constructor does not exist, but there are parameters - if (typ<0 && inst->m_Parameters != NULL) - { - pStk->SetError(TX_NOCONST, &inst->m_vartoken); - goto error; - } - - // makes pointer to the object on the stack - pStk->SetVar(pVar); - return pStack->Return(inst, pStk); - } -error: - delete inst; - return pStack->Return(NULL, pStk); -} - -// executes instruction "new" - -bool CBotNew::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); //main stack - - if (pile->IfStep()) return false; - - CBotStack* pile1 = pj->AddStack2(); //secondary stack - - CBotVar* pThis = NULL; - - CBotToken* pt = &m_vartoken; - CBotClass* pClass = CBotClass::Find(pt); - - // create the variable "this" pointer type to the stack - - if ( pile->GivState()==0) - { - // create an instance of the requested class - // and initialize the pointer to that object - - - pThis = CBotVar::Create("this", pClass); - pThis->SetUniqNum(-2) ; - - pile1->SetVar(pThis); // place on stack1 - pile->IncState(); - } - - // fetch the this pointer if it was interrupted - if ( pThis == NULL) - { - pThis = pile1->GivVar(); // find the pointer - } - - // is there an assignment or parameters (constructor) - if ( pile->GivState()==1) - { - // evaluates the constructor of the instance - - CBotVar* ppVars[1000]; - CBotStack* pile2 = pile; - - int i = 0; - - CBotInstr* p = m_Parameters; - // evaluate the parameters - // and places the values on the stack - // to be interrupted at any time - - if (p != NULL) while ( true) - { - pile2 = pile2->AddStack(); // space on the stack for the result - if (pile2->GivState() == 0) - { - if (!p->Execute(pile2)) return false; // interrupted here? - pile2->SetState(1); - } - ppVars[i++] = pile2->GivVar(); - p = p->GivNext(); - if ( p == NULL) break; - } - ppVars[i] = NULL; - - // create a variable for the result - CBotVar* pResult = NULL; // constructos still void - - if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(), - pThis, ppVars, - pResult, pile2, GivToken())) return false; // interrupt - - pThis->ConstructorSet(); // indicates that the constructor has been called - } - - return pj->Return(pile1); // passes below -} - -void CBotNew::RestoreState(CBotStack* &pj, bool bMain) -{ - if (!bMain) return; - - CBotStack* pile = pj->RestoreStack(this); //primary stack - if (pile == NULL) return; - - CBotStack* pile1 = pj->AddStack2(); //secondary stack - - CBotToken* pt = &m_vartoken; - CBotClass* pClass = CBotClass::Find(pt); - - // create the variable "this" pointer type to the object - - if ( pile->GivState()==0) - { - return; - } - - CBotVar* pThis = pile1->GivVar(); // find the pointer - pThis->SetUniqNum(-2); - - // is ther an assignment or parameters (constructor) - if ( pile->GivState()==1) - { - // evaluates the constructor of the instance - - CBotVar* ppVars[1000]; - CBotStack* pile2 = pile; - - int i = 0; - - CBotInstr* p = m_Parameters; - // evaluate the parameters - // and places the values on the stack - // to be interrupted at any time - - if (p != NULL) while ( true) - { - pile2 = pile2->RestoreStack(); // space on the stack for the result - if (pile2 == NULL) return; - - if (pile2->GivState() == 0) - { - p->RestoreState(pile2, bMain); // interrupt here! - return; - } - ppVars[i++] = pile2->GivVar(); - p = p->GivNext(); - if ( p == NULL) break; - } - ppVars[i] = NULL; - - pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GivString(), pThis, - ppVars, pile2) ; // interrupt here! - } -} - -///////////////////////////////////////////////////////////// -// check if two results are consistent to make an operation - -bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op) -{ - int t1 = type1.GivType(); - int t2 = type2.GivType(); - - int max = (t1 > t2) ? t1 : t2; - - if (max == 99) return false; // result is void? - - // special case for strin concatenation - if (op == ID_ADD && max >= CBotTypString) return true; - if (op == ID_ASSADD && max >= CBotTypString) return true; - if (op == ID_ASS && t1 == CBotTypString) return true; - - if (max >= CBotTypBoolean) - { - if ( (op == ID_EQ || op == ID_NE) && - (t1 == CBotTypPointer && t2 == CBotTypNullPointer)) return true; - if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && - (t2 == CBotTypPointer && t1 == CBotTypNullPointer)) return true; - if ( (op == ID_EQ || op == ID_NE) && - (t1 == CBotTypArrayPointer && t2 == CBotTypNullPointer)) return true; - if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && - (t2 == CBotTypArrayPointer && t1 == CBotTypNullPointer)) return true; - if (t2 != t1) return false; - if (t1 == CBotTypArrayPointer) return type1.Compare(type2); - if (t1 == CBotTypPointer || - t1 == CBotTypClass || - t1 == CBotTypIntrinsic ) - { - CBotClass* c1 = type1.GivClass(); - CBotClass* c2 = type2.GivClass(); - - return c1->IsChildOf(c2) || c2->IsChildOf(c1); - // accept the case in reverse - // the transaction will be denied at runtime if the pointer is not - // compatible - } - - return true; - } - - type1.SetType(max); - type2.SetType(max); - return true; -} - -// check if two variables are compatible for parameter passing - -bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2) -{ - int t1 = type1.GivType(); - int t2 = type2.GivType(); - - if (t1 == CBotTypIntrinsic) t1 = CBotTypClass; - if (t2 == CBotTypIntrinsic) t2 = CBotTypClass; - - int max = (t1 > t2) ? t1 : t2; - - if (max == 99) return false; // result is void? - - if (max >= CBotTypBoolean) - { - if (t2 != t1) return false; - - if (max == CBotTypArrayPointer) - return TypesCompatibles(type1.GivTypElem(), type2.GivTypElem()); - - if (max == CBotTypClass || max == CBotTypPointer) - return type1.GivClass() == type2.GivClass() ; - - return true ; - } - return true; -} - - -///////////////////////////////////////////////////////////////////////////////////// -// file management - -// necessary because it is not possible to do the fopen in the main program -// fwrite and fread in a dll or using the FILE * returned. - - -FILE* fOpen(const char* name, const char* mode) -{ - return fopen(name, mode); -} - -int fClose(FILE* filehandle) -{ - return fclose(filehandle); -} - -size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle) -{ - return fwrite(buffer, elemsize, length, filehandle); -} - -size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle) -{ - return fread(buffer, elemsize, length, filehandle); -} - -size_t fWrite(const void *buffer, size_t length, FILE* filehandle) -{ - return fwrite(buffer, 1, length, filehandle); -} - -size_t fRead(void *buffer, size_t length, FILE* filehandle) -{ - return fread(buffer, 1, length, filehandle); -} - - -//////////////////////////////////////// - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. +/////////////////////////////////////////////////////////////////////// + +// compilation of various instructions +// compile all routines as static +// and return an object according to what was found as instruction + +// compiler principle: +// compile the routines return an object of the class corresponding to the operation found +// this is always a subclass of CBotInstr. +// (CBotInstr objects are never used directly) + + +// compiles if the routine returns NULL is that the statement is false +// or misunderstood. +// the error is then on the stack CBotCStack :: Isok () is false + + + +#include "CBot.h" + +CBotInstr::CBotInstr() +{ + name = "CBotInstr"; + m_next = NULL; + m_next2b = NULL; + m_next3 = NULL; + m_next3b = NULL; +} + +CBotInstr::~CBotInstr() +{ + delete m_next; + delete m_next2b; + delete m_next3; + delete m_next3b; +} + +// counter of nested loops, +// to determine the break and continue valid +// list of labels used + + +int CBotInstr::m_LoopLvl = 0; +CBotStringArray CBotInstr::m_labelLvl = CBotStringArray(); + +// adds a level with a label +void CBotInstr::IncLvl(CBotString& label) +{ + m_labelLvl.SetSize(m_LoopLvl+1); + m_labelLvl[m_LoopLvl] = label; + m_LoopLvl++; +} + +// adds a level (switch statement) +void CBotInstr::IncLvl() +{ + m_labelLvl.SetSize(m_LoopLvl+1); + m_labelLvl[m_LoopLvl] = "#SWITCH"; + m_LoopLvl++; +} + +// free a level +void CBotInstr::DecLvl() +{ + m_LoopLvl--; + m_labelLvl[m_LoopLvl].Empty(); +} + +// control validity of break and continue +bool CBotInstr::ChkLvl(const CBotString& label, int type) +{ + int i = m_LoopLvl; + while (--i>=0) + { + if ( type == ID_CONTINUE && m_labelLvl[i] == "#SWITCH") continue; + if (label.IsEmpty()) return true; + if (m_labelLvl[i] == label) return true; + } + return false; +} + +bool CBotInstr::IsOfClass(CBotString n) +{ + return name == n; +} + + +//////////////////////////////////////////////////////////////////////////// +// database management class CBotInstr + +// set the token corresponding to the instruction + +void CBotInstr::SetToken(CBotToken* p) +{ + m_token = *p; +} + +// return the type of the token assicated with the instruction + +int CBotInstr::GivTokenType() +{ + return m_token.GivType(); +} + +// return associated token + +CBotToken* CBotInstr::GivToken() +{ + return &m_token; +} + +// adds the statement following the other + +void CBotInstr::AddNext(CBotInstr* n) +{ + CBotInstr* p = this; + while (p->m_next != NULL) p = p->m_next; + p->m_next = n; +} + +void CBotInstr::AddNext3(CBotInstr* n) +{ + CBotInstr* p = this; + while (p->m_next3 != NULL) p = p->m_next3; + p->m_next3 = n; +} + +void CBotInstr::AddNext3b(CBotInstr* n) +{ + CBotInstr* p = this; + while (p->m_next3b != NULL) p = p->m_next3b; + p->m_next3b = n; +} + +// returns next statement + +CBotInstr* CBotInstr::GivNext() +{ + return m_next; +} + +CBotInstr* CBotInstr::GivNext3() +{ + return m_next3; +} + +CBotInstr* CBotInstr::GivNext3b() +{ + return m_next3b; +} + +/////////////////////////////////////////////////////////////////////////// +// compile an instruction which can be +// while, do, try, throw, if, for, switch, break, continue, return +// int, float, boolean, string, +// declaration of an instance of a class +// arbitrary expression + + +CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + + if (p == NULL) return NULL; + + int type = p->GivType(); // what is the next token + + // is it a lable? + if (IsOfType(pp, TokenTypVar) && + IsOfType(pp, ID_DOTS)) + { + type = pp->GivType(); + // these instructions accept only lable + if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0)) + { + pStack->SetError(TX_LABEL, pp->GivStart()); + return NULL; + } + } + + // call routine corresponding to the compilation token found + switch (type) + { + case ID_WHILE: + return CBotWhile::Compile(p, pStack); + + case ID_FOR: + return CBotFor::Compile(p, pStack); + + case ID_DO: + return CBotDo::Compile(p, pStack); + + case ID_REPEAT: + return CBotRepeat::Compile(p, pStack); + + case ID_BREAK: + case ID_CONTINUE: + return CBotBreak::Compile(p, pStack); + + case ID_SWITCH: + return CBotSwitch::Compile(p, pStack); + + case ID_TRY: + return CBotTry::Compile(p, pStack); + + case ID_THROW: + return CBotThrow::Compile(p, pStack); + + case ID_DEBUGDD: + return CBotStartDebugDD::Compile(p, pStack); + + case ID_INT: + return CBotInt::Compile(p, pStack); + + case ID_FLOAT: + return CBotFloat::Compile(p, pStack); + + case ID_STRING: + return CBotIString::Compile(p, pStack); + + case ID_BOOLEAN: + case ID_BOOL: + return CBotBoolean::Compile(p, pStack); + + case ID_IF: + return CBotIf::Compile(p, pStack); + + case ID_RETURN: + return CBotReturn::Compile(p, pStack); + + case ID_ELSE: + pStack->SetStartError(p->GivStart()); + pStack->SetError(TX_ELSEWITHOUTIF, p->GivEnd()); + return NULL; + + case ID_CASE: + pStack->SetStartError(p->GivStart()); + pStack->SetError(TX_OUTCASE, p->GivEnd()); + return NULL; + } + + pStack->SetStartError(p->GivStart()); + + // should not be a reserved word DefineNum + if (p->GivType() == TokenTypDef) + { + pStack->SetError(TX_RESERVED, p); + return NULL; + } + + // this might be an instance of class definnition + CBotToken* ppp = p; + if (IsOfType(ppp, TokenTypVar)) + { + if (CBotClass::Find(p) != NULL) + { + // yes, compiles the declaration of the instance + return CBotClassInst::Compile(p, pStack); + } + } + + // this can be an arythmetic instruction + CBotInstr* inst = CBotExpression::Compile(p, pStack); + if (IsOfType(p, ID_SEP)) + { + return inst; + } + pStack->SetError(TX_ENDOF, p->GivStart()); + delete inst; + return NULL; +} + +bool CBotInstr::Execute(CBotStack* &pj) +{ + CBotString ClassManquante = name; + ASM_TRAP(); // should never go through this routine + // but use the routines of the subclasses + return false; +} + +bool CBotInstr::Execute(CBotStack* &pj, CBotVar* pVar) +{ + if (!Execute(pj)) return false; + pVar->SetVal(pj->GivVar()); + return true; +} + +void CBotInstr::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotString ClassManquante = name; + ASM_TRAP(); // should never go through this routine + // but use the routines of the subclasses +} + + +bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + ASM_TRAP(); // dad do not know, see the girls + return false; +} + +bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) +{ + ASM_TRAP(); // dad do not know, see the girls + return false; +} + +void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + ASM_TRAP(); // dad do not know, see the girls +} + +// 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. + +bool CBotInstr::CompCase(CBotStack* &pj, int val) +{ + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a statement block " { i ; i ; } " + +// this class have no constructor because there is never an instance of this +// class (TODO what about default constructor?) +// the object returned by Compile is usually of type CBotListInstr + + +CBotInstr* CBotBlock::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal) +{ + pStack->SetStartError(p->GivStart()); + + if (IsOfType(p, ID_OPBLK)) + { + CBotInstr* inst = CBotListInstr::Compile(p, pStack, bLocal); + + if (IsOfType(p, ID_CLBLK)) + { + return inst; + } + + pStack->SetError(TX_CLOSEBLK, p->GivStart()); // missing parenthesis + delete inst; + return NULL; + } + + pStack->SetError(TX_OPENBLK, p->GivStart()); + return NULL; +} + +CBotInstr* CBotBlock::CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal) +{ + // is this a new block + if (p->GivType() == ID_OPBLK) return CBotBlock::Compile(p, pStack); + + // otherwise, look for a single statement instead + + // to handle the case with local definition instruction (*) + CBotCStack* pStk = pStack->TokenStack(p, bLocal); + + return pStack->Return( CBotInstr::Compile(p, pStk), // a single instruction + pStk); +} + +// (*) is the case in the following statement +// if (1 == 1) int x = 0; +// where the variable x is known only in the block following the if + + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a list of instructions separated by semicolons + +CBotListInstr::CBotListInstr() +{ + m_Instr = NULL; + name = "CBotListInstr"; +} + +CBotListInstr::~CBotListInstr() +{ + delete m_Instr; +} + +CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal) +{ + CBotCStack* pStk = pStack->TokenStack(p, bLocal); // variables are local + + CBotListInstr* inst = new CBotListInstr(); + + while (true) + { + if (p == NULL) break; + + if (IsOfType(p, ID_SEP)) continue; // empty statement ignored + if (p->GivType() == ID_CLBLK) break; + + if (IsOfType(p, 0)) + { + pStack->SetError(TX_CLOSEBLK, p->GivStart()); + delete inst; + return pStack->Return(NULL, pStk); + } + + CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk); // compiles next + + if (!pStk->IsOk()) + { + delete inst; + return pStack->Return(NULL, pStk); + } + + if (inst->m_Instr == NULL) inst->m_Instr = i; + else inst->m_Instr->AddNext(i); // added a result + } + return pStack->Return(inst, pStk); +} + +// executes a set of instructions + +bool CBotListInstr::Execute(CBotStack* &pj) +{ + + CBotStack* pile = pj->AddStack(this, true); //needed for SetState() + if (pile->StackOver() ) return pj->Return( pile); + + + CBotInstr* p = m_Instr; // the first expression + + int state = pile->GivState(); + while (state-->0) p = p->GivNext(); // returns to the interrupted operation + + if (p != NULL) while (true) + { + if (!p->Execute(pile)) return false; + p = p->GivNext(); + if (p == NULL) break; + if (!pile->IncState()) ;//return false; // ready for next + } + + return pj->Return(pile); +} + +void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotInstr* p = m_Instr; // the first expression + + int state = pile->GivState(); + while ( p != NULL && state-- > 0) + { + p->RestoreState(pile, false); + p = p->GivNext(); // returns to the interrupted operation + } + + if (p != NULL) p->RestoreState(pile, true); +} + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// compilation of an element to the left of an assignment + +CBotLeftExprVar::CBotLeftExprVar() +{ + name = "CBotLeftExprVar"; + m_typevar = -1; + m_nIdent = 0; +} + +CBotLeftExprVar::~CBotLeftExprVar() +{ +} + +CBotInstr* CBotLeftExprVar::Compile(CBotToken* &p, CBotCStack* pStack) +{ + // verifies that the token is a variable name + if (p->GivType() != TokenTypVar) + { + pStack->SetError( TX_NOVAR, p->GivStart()); + return NULL; + } + + CBotLeftExprVar* inst = new CBotLeftExprVar(); + inst->SetToken(p); + p = p->GivNext(); + + return inst; +} + +// creates a variable and assigns the result to the stack +bool CBotLeftExprVar::Execute(CBotStack* &pj) +{ + CBotVar* var1; + CBotVar* var2; + + var1 = CBotVar::Create(m_token.GivString(), m_typevar); + var1->SetUniqNum(m_nIdent); // with the unique identifier + pj->AddVar(var1); // place it on the stack + + var2 = pj->GivVar(); // result on the stack + if (var2) var1->SetVal(var2); // do the assignment + + return true; +} + +void CBotLeftExprVar::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotVar* var1; + + var1 = pj->FindVar(m_token.GivString()); + if (var1 == NULL) ASM_TRAP(); + + var1->SetUniqNum(m_nIdent); // with the unique identifier +} + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// defining an array of any type +// int a[12]; +// point x[]; + +CBotInstArray::CBotInstArray() +{ + m_var = NULL; + m_listass = NULL; + name = "CBotInstArray"; +} + +CBotInstArray::~CBotInstArray() +{ + delete m_var; + delete m_listass; +} + + +CBotInstr* CBotInstArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) +{ + CBotCStack* pStk = pStack->TokenStack(p); + + CBotInstArray* inst = new CBotInstArray(); + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + + // determinse the expression is valid for the item on the left side + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable? + { + pStk->SetError(TX_REDEFVAR, vartoken); + goto error; + } + + CBotInstr* i; + while (IsOfType(p, ID_OPBRK)) + { + if (p->GivType() != ID_CLBRK) + i = CBotExpression::Compile(p, pStk); // expression for the value + 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(TX_CLBRK, p->GivStart()); + goto error; + } + } + + CBotVar* var = CBotVar::Create(vartoken, type); // create an instance + inst->m_typevar = type; + + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); // place it on the stack + + if (IsOfType(p, ID_ASS)) // with an assignment + { + inst->m_listass = CBotListArray::Compile(p, pStk, type.GivTypElem()); + } + + if (pStk->IsOk()) return pStack->Return(inst, pStk); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + + +// executes the definition of an array + +bool CBotInstArray::Execute(CBotStack* &pj) +{ + CBotStack* pile1 = pj->AddStack(this); + + CBotStack* pile = pile1; + + if (pile1->GivState() == 0) + { + // seek the maximum dimension of the table + CBotInstr* p = GivNext3b(); // the different formulas + int nb = 0; + + while (p != NULL) + { + pile = pile->AddStack(); // little room to work + nb++; + if (pile->GivState() == 0) + { + if (!p->Execute(pile)) return false; // size calculation //interrupted? + pile->IncState(); + } + p = p->GivNext3b(); + } + + p = GivNext3b(); + pile = pile1; // returns to the stack + int n = 0; + int max[100]; + + while (p != NULL) + { + pile = pile->AddStack(); + CBotVar* v = pile->GivVar(); // result + max[n] = v->GivValInt(); // value + if (max[n]>MAXARRAYSIZE) + { + pile->SetError(TX_OUTARRAY, &m_token); + return pj->Return (pile); + } + n++; + p = p->GivNext3b(); + } + while (n<100) max[n++] = 0; + + m_typevar.SetArray(max); // store the limitations + + // create simply a NULL pointer + CBotVar* var = CBotVar::Create(m_var->GivToken(), m_typevar); + var->SetPointer(NULL); + var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); + pj->AddVar(var); + +#if STACKMEM + pile1->AddStack()->Delete(); +#else + delete pile1->AddStack(); // need more indices +#endif + pile1->IncState(); + } + + if (pile1->GivState() == 1) + { + if (m_listass != NULL) // there is the assignment for this table + { + CBotVar* pVar = pj->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent); + + if (!m_listass->Execute(pile1, pVar)) return false; + } + pile1->IncState(); + } + + if (pile1->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile1 )) return false; + + return pj->Return(pile1); +} + +void CBotInstArray::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile1 = pj; + + CBotVar* var = pj->FindVar(m_var->GivToken()->GivString()); + if (var != NULL) var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); + + if (bMain) + { + pile1 = pj->RestoreStack(this); + CBotStack* pile = pile1; + if (pile == NULL) return; + + if (pile1->GivState() == 0) + { + // seek the maximum dimension of the table + CBotInstr* p = GivNext3b(); + + while (p != NULL) + { + pile = pile->RestoreStack(); + if (pile == NULL) return; + if (pile->GivState() == 0) + { + p->RestoreState(pile, bMain); + return; + } + p = p->GivNext3b(); + } + } + if (pile1->GivState() == 1 && m_listass != NULL) + { + m_listass->RestoreState(pile1, bMain); + } + + } + + if (m_next2b ) m_next2b->RestoreState( pile1, bMain); +} + +// special case for empty indexes +bool CBotEmpty :: Execute(CBotStack* &pj) +{ + CBotVar* pVar = CBotVar::Create("", CBotTypInt); + pVar->SetValInt(-1); + pj->SetVar(pVar); + return true; +} + +void CBotEmpty :: RestoreState(CBotStack* &pj, bool bMain) +{ +} + +////////////////////////////////////////////////////////////////////////////////////// +// defining a list table initialization +// int [ ] a [ ] = (( 1, 2, 3 ) , ( 3, 2, 1 )) ; + + +CBotListArray::CBotListArray() +{ + m_expr = NULL; + name = "CBotListArray"; +} + +CBotListArray::~CBotListArray() +{ + delete m_expr; +} + + +CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) +{ + CBotCStack* pStk = pStack->TokenStack(p); + + CBotToken* pp = p; + + if (IsOfType( p, ID_NULL )) + { + CBotInstr* inst = new CBotExprNull (); + inst->SetToken(pp); + return pStack->Return(inst, pStk); // ok with empty element + } + + CBotListArray* inst = new CBotListArray(); + + if (IsOfType( p, ID_OPENPAR )) + { + // each element takes the one after the other + if (type.Eq( CBotTypArrayPointer )) + { + type = type.GivTypElem(); + + pStk->SetStartError(p->GivStart()); + if (NULL == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) )) + { + goto error; + } + + while (IsOfType( p, ID_COMMA )) // other elements? + { + pStk->SetStartError(p->GivStart()); + + CBotInstr* i = CBotListArray::Compile(p, pStk, type); + if (NULL == i) + { + goto error; + } + + inst->m_expr->AddNext3(i); + } + } + else + { + pStk->SetStartError(p->GivStart()); + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + CBotVar* pv = pStk->GivVar(); // result of the expression + + if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + + while (IsOfType( p, ID_COMMA )) // other elements? + { + pStk->SetStartError(p->GivStart()); + + CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ; + if (NULL == i) + { + goto error; + } + + CBotVar* pv = pStk->GivVar(); // result of the expression + + if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + inst->m_expr->AddNext3(i); + } + } + + if (!IsOfType(p, ID_CLOSEPAR) ) + { + pStk->SetError(TX_CLOSEPAR, p->GivStart()); + goto error; + } + + return pStack->Return(inst, pStk); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + + +// executes the definition of an array + +bool CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar) +{ + CBotStack* pile1 = pj->AddStack(); + CBotVar* pVar2; + + CBotInstr* p = m_expr; + + int n = 0; + + for (; p != NULL ; n++, p = p->GivNext3()) + { + if (pile1->GivState() > n) continue; + + pVar2 = pVar->GivItem(n, true); + + if (!p->Execute(pile1, pVar2)) return false; // evaluate expression + + pile1->IncState(); + } + + return pj->Return(pile1); +} + +void CBotListArray::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) + { + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotInstr* p = m_expr; + + int state = pile->GivState(); + + while(state-- > 0) p = p->GivNext3() ; + + p->RestoreState(pile, bMain); // size calculation //interrupted! + } +} + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// definition of an integer variable +// int a, b = 12; + +CBotInt::CBotInt() +{ + m_next = NULL; // for multiple definitions + m_var = + m_expr = NULL; + name = "CBotInt"; +} + +CBotInt::~CBotInt() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first) +{ + if (IsOfType(p, ID_OPBRK)) + { + if (!IsOfType(p, ID_CLBRK)) + { + pStack->SetError(TX_CLBRK, p->GivStart()); + return NULL; + } + + CBotInstr* inst = CompileArray(p, pStack, CBotTypResult(CBotTypArrayPointer, type), false); + if (inst != NULL || !pStack->IsOk()) return inst; + } + + // compiles an array declaration + if (first) return NULL ; + + CBotInstr* inst = CBotInstArray::Compile(p, pStack, type); + if (inst == NULL) return NULL; + + if (IsOfType(p, ID_COMMA)) // several definitions + { + if (NULL != ( inst->m_next2b = CBotInstArray::CompileArray(p, pStack, type, false))) // compiles next one + { + return inst; + } + delete inst; + return NULL; + } + + if (IsOfType(p, ID_SEP)) // end of instruction + { + return inst; + } + + delete inst; + pStack->SetError(TX_ENDOF, p->GivStart()); + return NULL; +} + +CBotInstr* CBotInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; // no repetition of the token "int" + + if (!cont && !IsOfType(p, ID_INT)) return NULL; + + CBotInt* inst = (CBotInt*)CompileArray(p, pStack, CBotTypInt); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotInt(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + + // determines the expression is valid for the item on the left side + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypInt; + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable + { + pStk->SetError(TX_REDEFVAR, vartoken); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) + { + delete inst; // type is not CBotInt + p = vartoken; // returns the variable name + + // compiles an array declaration + + CBotInstr* inst2 = CBotInstArray::Compile(p, pStk, CBotTypInt); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + + if (IsOfType(p, ID_COMMA)) // several definition chained + { + if (NULL != ( inst2->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile the next one + { + return pStack->Return(inst2, pStk); + } + } + inst = (CBotInt*)inst2; + goto suite; // no assignment, variable already created + } + + if (IsOfType(p, ID_ASS)) // with an assignment? + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + if (pStk->GivType() >= CBotTypBoolean) // compatible type ? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + } + + { + CBotVar* var = CBotVar::Create(vartoken, CBotTypInt);// create the variable (evaluated after the assignment) + var->SetInit(inst->m_expr != NULL); // if initialized with assignment + var->SetUniqNum( //set it with a unique number + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); // place it on the stack + } + + if (IsOfType(p, ID_COMMA)) // chained several definitions + { + if (NULL != ( inst->m_next2b = CBotInt::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); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// execute the definition of the integer variable + +bool CBotInt::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); // essential for SetState() + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; // initial value // interrupted? + m_var->Execute(pile); // creates and assign the result + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; // other(s) definition(s) + + return pj->Return(pile); // forward below +} + +void CBotInt::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); // initial value // interrupted? + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) m_next2b->RestoreState(pile, bMain); // other(s) definition(s) +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// defining a boolean variable +// int a, b = false; + +CBotBoolean::CBotBoolean() +{ + m_var = + m_expr = NULL; + name = "CBotBoolean"; +} + +CBotBoolean::~CBotBoolean() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; + + if (!cont && !IsOfType(p, ID_BOOLEAN, ID_BOOL)) return NULL; + + CBotBoolean* inst = (CBotBoolean*)CompileArray(p, pStack, CBotTypBoolean); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotBoolean(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + CBotVar* var = NULL; + + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypBoolean; + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable + { + pStk->SetError(TX_REDEFVAR, vartoken); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) + { + delete inst; // type is not CBotInt + p = vartoken; // resutns to the variable name + + // compiles an array declaration + + inst = (CBotBoolean*)CBotInstArray::Compile(p, pStk, CBotTypBoolean); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + goto suite; // no assignment, variable already created + } + + if (IsOfType(p, ID_ASS)) + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + if (!pStk->GivTypResult().Eq(CBotTypBoolean)) + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + } + + var = CBotVar::Create(vartoken, CBotTypBoolean);// create the variable (evaluated after the assignment) + var->SetInit(inst->m_expr != NULL); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); +suite: + if (IsOfType(p, ID_COMMA)) + { + if (NULL != ( inst->m_next2b = CBotBoolean::Compile(p, pStk, true, noskip))) + { + return pStack->Return(inst, pStk); + } + } + + if (noskip || IsOfType(p, ID_SEP)) + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes a boolean variable definition + +bool CBotBoolean::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this);//essential for SetState() + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; + m_var->Execute(pile); + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; + + return pj->Return(pile); +} + +void CBotBoolean::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); // initial value interrupted? + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) + m_next2b->RestoreState(pile, bMain); // other(s) definition(s) +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// definition of a real/float variable +// int a, b = 12.4; + +CBotFloat::CBotFloat() +{ + m_var = + m_expr = NULL; + name = "CBotFloat"; +} + +CBotFloat::~CBotFloat() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; + + if (!cont && !IsOfType(p, ID_FLOAT)) return NULL; + + CBotFloat* inst = (CBotFloat*)CompileArray(p, pStack, CBotTypFloat); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotFloat(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + CBotVar* var = NULL; + inst->SetToken(vartoken); + + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypFloat; + if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable + { + pStk->SetStartError(vartoken->GivStart()); + pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) + { + delete inst; + p = vartoken; + inst = (CBotFloat*)CBotInstArray::Compile(p, pStk, CBotTypFloat); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + goto suite; // no assignment, variable already created + } + + if (IsOfType(p, ID_ASS)) + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + if (pStk->GivType() >= CBotTypBoolean) + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + } + + var = CBotVar::Create(vartoken, CBotTypFloat); + var->SetInit(inst->m_expr != NULL); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); +suite: + if (IsOfType(p, ID_COMMA)) + { + if (NULL != ( inst->m_next2b = CBotFloat::Compile(p, pStk, true, noskip))) + { + return pStack->Return(inst, pStk); + } + } + + if (noskip || IsOfType(p, ID_SEP)) + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes the definition of a real variable + +bool CBotFloat::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; + m_var->Execute(pile); + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; + + return pj->Return(pile); +} + +void CBotFloat::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) + m_next2b->RestoreState(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// define a string variable +// int a, b = "salut"; + +CBotIString::CBotIString() +{ + m_var = + m_expr = NULL; + name = "CBotIString"; +} + +CBotIString::~CBotIString() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotIString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; + + if (!cont && !IsOfType(p, ID_STRING)) return NULL; + + CBotIString* inst = (CBotIString*)CompileArray(p, pStack, CBotTypString); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotIString(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypString; + if (pStk->CheckVarLocal(vartoken)) + { + pStk->SetStartError(vartoken->GivStart()); + pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); + goto error; + } + + if (IsOfType(p, ID_ASS)) + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } +/* if (!pStk->GivTypResult().Eq(CBotTypString)) // type compatible ? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + }*/ + } + + CBotVar* var = CBotVar::Create(vartoken, CBotTypString); + var->SetInit(inst->m_expr != NULL); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); + + if (IsOfType(p, ID_COMMA)) + { + if (NULL != ( inst->m_next2b = CBotIString::Compile(p, pStk, true, noskip))) + { + return pStack->Return(inst, pStk); + } + } + + if (noskip || IsOfType(p, ID_SEP)) + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes the definition of the string variable + +bool CBotIString::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; + m_var->Execute(pile); + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; + + return pj->Return(pile); +} + +void CBotIString::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) + m_next2b->RestoreState(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a statement such as " x = 123 " ou " z * 5 + 4 " +// with or without assignment + +CBotExpression::CBotExpression() +{ + m_leftop = NULL; + m_rightop = NULL; + 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->GivType(); + + 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 == NULL) + { + pStack->SetError(TX_BADLEFT, p->GivEnd()); + delete inst; + return NULL; + } + + inst->m_rightop = CBotExpression::Compile(p, pStack); + if (inst->m_rightop == NULL) + { + delete inst; + return NULL; + } + + CBotTypResult type1 = pStack->GivTypResult(); + + // get the variable assigned to mark + CBotVar* var = NULL; + inst->m_leftop->ExecuteVar(var, pStack); + if (var == NULL) + { + delete inst; + return NULL; + } + + if (OpType != ID_ASS && var->GivInit() != IS_DEF) + { + pStack->SetError(TX_NOTINIT, pp); + delete inst; + return NULL; + } + + CBotTypResult type2 = var->GivTypResult(); + + // 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.GivClass(); + CBotClass* c2 = type2.GivClass(); + if (!c1->IsChildOf(c2)) type2.SetType(-1); +//- if (!type1.Eq(CBotTypClass)) var->SetPointer(pStack->GivVar()->GivPointer());*/ + var->SetInit(2); + } + else + var->SetInit(true); + + 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.GivType() >= CBotTypBoolean) type2 = -1; // numbers only + break; + } + + if (!TypeCompatible(type1, type2, OpType)) + { + pStack->SetError(TX_BADTYPE, &inst->m_token); + delete inst; + return NULL; + } + + return inst; // compatible type? + } + + delete inst; + int start, end, error = pStack->GivError(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 != NULL && error == TX_PRIVATE && p->GivType() == 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->GivToken(); + CBotVar* pVar = NULL; + + CBotStack* pile1 = pile; + + bool IsInit = true; + CBotVar* result = NULL; + + // must be done before any indexes (stack can be changed) + if (!m_leftop->ExecuteVar(pVar, pile, NULL, false)) return false; // variable before accessing the value on the right + + if ( pile1->GivState()==0) + { + pile1->SetCopyVar(pVar); // keeps the copy on the stack (if interrupted) + pile1->IncState(); + } + + CBotStack* pile2 = pile->AddStack(); + + if ( pile2->GivState()==0) + { + if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted? + pile2->IncState(); + } + + if (pile1->GivState() == 1) + { + if (m_token.GivType() != ID_ASS) + { + pVar = pile1->GivVar(); // recovers if interrupted + IsInit = pVar->GivInit(); + if (IsInit == IS_NAN) + { + pile2->SetError(TX_OPNAN, m_leftop->GivToken()); + return pj->Return(pile2); + } + result = CBotVar::Create("", pVar->GivTypResult(2)); + } + + switch (m_token.GivType()) + { + case ID_ASS: + break; + case ID_ASSADD: + result->Add(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSSUB: + result->Sub(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSMUL: + result->Mul(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSDIV: + if (IsInit && + result->Div(pile1->GivVar(), pile2->GivVar())) + pile2->SetError(TX_DIVZERO, &m_token); + pile2->SetVar(result); + break; + case ID_ASSMODULO: + if (IsInit && + result->Modulo(pile1->GivVar(), pile2->GivVar())) + pile2->SetError(TX_DIVZERO, &m_token); + pile2->SetVar(result); + break; + case ID_ASSAND: + result->And(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSXOR: + result->XOr(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSOR: + result->Or(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSSL: + result->SL(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSSR: + result->SR(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSASR: + result->ASR(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + default: + ASM_TRAP(); + } + if (!IsInit) + pile2->SetError(TX_NOTINIT, m_leftop->GivToken()); + + 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->GivToken(); + CBotVar* pVar = NULL; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotStack* pile1 = pile; + + if ( pile1->GivState()==0) + { + m_leftop->RestoreStateVar(pile, true); + return; + } + + m_leftop->RestoreStateVar(pile, false); + + CBotStack* pile2 = pile->RestoreStack(); + if (pile2 == NULL) return; + + if ( pile2->GivState()==0) + { + if (m_rightop) m_rightop->RestoreState(pile2, bMain); + return; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a statement such as "(condition)" +// the condition must be Boolean + +// this class has no constructor, because there is never an instance of this class +// the object returned by Compile is usually type CBotExpression + + +CBotInstr* CBotCondition::Compile(CBotToken* &p, CBotCStack* pStack) +{ + pStack->SetStartError(p->GivStart()); + if (IsOfType(p, ID_OPENPAR)) + { + CBotInstr* inst = CBotBoolExpr::Compile(p, pStack); + if (NULL != inst) + { + if (IsOfType(p, ID_CLOSEPAR)) + { + return inst; + } + pStack->SetError(TX_CLOSEPAR, p->GivStart()); // missing parenthesis + } + delete inst; + } + + pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis + + return NULL; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a statement such as "(condition)" +// the condition must be Boolean +// +// this class has no constructor, because there is never an instance of this +// class +// the object returned by Compile is usually type CBotExpression +// + +CBotInstr* CBotBoolExpr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + pStack->SetStartError(p->GivStart()); + + CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStack); + + if (NULL != inst) + { + if (pStack->GivTypResult().Eq(CBotTypBoolean)) + { + return inst; + } + pStack->SetError(TX_NOTBOOL, p->GivStart()); // is not a boolean + } + + delete inst; + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile either: +// instruction in parentheses (...) +// a unary expression (negative, not) +// variable name +// variables pre and post-incremented or decremented +// a given number DefineNum +// a constant +// procedure call +// new statement +// +// this class has no constructor, because there is never an instance of this class +// the object returned by Compile is the class corresponding to the instruction + + +CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(p->GivStart()); + + // is it an expression in parentheses? + if (IsOfType(p, ID_OPENPAR)) + { + CBotInstr* inst = CBotExpression::Compile(p, pStk); + + if (NULL != inst) + { + if (IsOfType(p, ID_CLOSEPAR)) + { + return pStack->Return(inst, pStk); + } + pStk->SetError(TX_CLOSEPAR, p->GivStart()); + } + delete inst; + return pStack->Return(NULL, pStk); + } + + // is this a unary operation? + CBotInstr* inst = CBotExprUnaire::Compile(p, pStk); + if (inst != NULL || !pStk->IsOk()) + return pStack->Return(inst, pStk); + + // is it a variable name? + if (p->GivType() == TokenTypVar) + { + // this may be a method call without the "this." before + inst = CBotExprVar::CompileMethode(p, pStk); + if (inst != NULL) return pStack->Return(inst, pStk); + + + // is it a procedure call? + inst = CBotInstrCall::Compile(p, pStk); + if (inst != NULL || !pStk->IsOk()) + return pStack->Return(inst, pStk); + + + CBotToken* pvar = p; + // no, it an "ordinaty" variable + inst = CBotExprVar::Compile(p, pStk); + + CBotToken* pp = p; + // post incremented or decremented? + if (IsOfType(p, ID_INC, ID_DEC)) + { + if (pStk->GivType() >= CBotTypBoolean) + { + pStk->SetError(TX_BADTYPE, pp); + delete inst; + return pStack->Return(NULL, pStk); + } + + // recompile the variable for read-only + delete inst; + p = pvar; + inst = CBotExprVar::Compile(p, pStk, PR_READ); + p = p->GivNext(); + + CBotPostIncExpr* i = new CBotPostIncExpr(); + i->SetToken(pp); + i->m_Instr = inst; // associated statement + return pStack->Return(i, pStk); + } + return pStack->Return(inst, pStk); + } + + // pre increpemted or pre decremented? + CBotToken* pp = p; + if (IsOfType(p, ID_INC, ID_DEC)) + { + CBotPreIncExpr* i = new CBotPreIncExpr(); + i->SetToken(pp); + + if (p->GivType() == TokenTypVar) + { + if (NULL != (i->m_Instr = CBotExprVar::Compile(p, pStk, PR_READ))) + { + if (pStk->GivType() >= CBotTypBoolean) + { + pStk->SetError(TX_BADTYPE, pp); + delete inst; + return pStack->Return(NULL, pStk); + } + return pStack->Return(i, pStk); + } + delete i; + return pStack->Return(NULL, pStk); + } + } + + // is it a number or DefineNum? + if (p->GivType() == TokenTypNum || + p->GivType() == TokenTypDef ) + { + CBotInstr* inst = CBotExprNum::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is this a chaine? + if (p->GivType() == TokenTypString) + { + CBotInstr* inst = CBotExprAlpha::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is a "true" or "false" + if (p->GivType() == ID_TRUE || + p->GivType() == ID_FALSE ) + { + CBotInstr* inst = CBotExprBool::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is an object to be created with new + if (p->GivType() == ID_NEW) + { + CBotInstr* inst = CBotNew::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is a null pointer + if (IsOfType(p, ID_NULL)) + { + CBotInstr* inst = new CBotExprNull (); + inst->SetToken(pp); + CBotVar* var = CBotVar::Create("", CBotTypNullPointer); + pStk->SetVar(var); + return pStack->Return(inst, pStk); + } + + // is a number nan + if (IsOfType(p, ID_NAN)) + { + CBotInstr* inst = new CBotExprNan (); + inst->SetToken(pp); + CBotVar* var = CBotVar::Create("", CBotTypInt); + var->SetInit(IS_NAN); + pStk->SetVar(var); + return pStack->Return(inst, pStk); + } + + + return pStack->Return(NULL, pStk); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// Management of pre-and post increment / decrement +// There is no routine Compiles, the object is created directly +// Compiles in CBotParExpr :: + + +CBotPostIncExpr::CBotPostIncExpr() +{ + m_Instr = NULL; + name = "CBotPostIncExpr"; +} + +CBotPostIncExpr::~CBotPostIncExpr() +{ + delete m_Instr; +} + +CBotPreIncExpr::CBotPreIncExpr() +{ + m_Instr = NULL; + name = "CBotPreIncExpr"; +} + +CBotPreIncExpr::~CBotPreIncExpr() +{ + delete m_Instr; +} + +bool CBotPostIncExpr::Execute(CBotStack* &pj) +{ + CBotStack* pile1 = pj->AddStack(this); + CBotStack* pile2 = pile1; + + CBotVar* var1 = NULL; + + // retrieves the variable fields and indexes according + if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false; + + pile1->SetState(1); + pile1->SetCopyVar(var1); // places the result (before incrementation); + + CBotStack* pile3 = pile2->AddStack(this); + if (pile3->IfStep()) return false; + + if (var1->GivInit() == IS_NAN) + { + pile1->SetError(TX_OPNAN, &m_token); + } + + if (var1->GivInit() != IS_DEF) + { + pile1->SetError(TX_NOTINIT, &m_token); + } + + if (GivTokenType() == ID_INC) var1->Inc(); + else var1->Dec(); + + return pj->Return(pile1); // operation done, result on pile2 +} + +void CBotPostIncExpr::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile1 = pj->RestoreStack(this); + if (pile1 == NULL) return; + + ((CBotExprVar*)m_Instr)->RestoreStateVar(pile1, bMain); + + if (pile1 != NULL) pile1->RestoreStack(this); +} + +bool CBotPreIncExpr::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var1; + + if (pile->GivState() == 0) + { + CBotStack* pile2 = pile; + // retrieves the variable fields and indexes according + // pile2 is modified on return + if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false; + + if (var1->GivInit() == IS_NAN) + { + pile->SetError(TX_OPNAN, &m_token); + return pj->Return(pile); // operation performed + } + + if (var1->GivInit() != IS_DEF) + { + pile->SetError(TX_NOTINIT, &m_token); + return pj->Return(pile); // operation performed + } + + if (GivTokenType() == ID_INC) var1->Inc(); + else var1->Dec(); // ((CBotVarInt*)var1)->m_val + + pile->IncState(); + } + + if (!m_Instr->Execute(pile)) return false; + return pj->Return(pile); // operation performed +} + + +void CBotPreIncExpr::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if (pile->GivState() == 0) + { + return; + } + + m_Instr->RestoreState(pile, bMain); +} + + +////////////////////////////////////////////////////////////////////////////////////// +// compile an unary expression +// + +// - +// not +// ! +// ~ + +CBotExprUnaire::CBotExprUnaire() +{ + m_Expr = NULL; + name = "CBotExprUnaire"; +} + +CBotExprUnaire::~CBotExprUnaire() +{ + delete m_Expr; +} + +CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack) +{ + int op = p->GivType(); + CBotToken* pp = p; + if (!IsOfTypeList( p, ID_ADD, ID_SUB, ID_LOG_NOT, ID_TXT_NOT, ID_NOT, 0 )) return NULL; + + CBotCStack* pStk = pStack->TokenStack(pp); + + CBotExprUnaire* inst = new CBotExprUnaire(); + inst->SetToken(pp); + + if (NULL != (inst->m_Expr = CBotParExpr::Compile( p, pStk ))) + { + if (op == ID_ADD && pStk->GivType() < CBotTypBoolean) // only with the number + return pStack->Return(inst, pStk); + if (op == ID_SUB && pStk->GivType() < CBotTypBoolean) // only with the numer + return pStack->Return(inst, pStk); + if (op == ID_NOT && pStk->GivType() < CBotTypFloat) // only with an integer + return pStack->Return(inst, pStk); + if (op == ID_LOG_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean + return pStack->Return(inst, pStk); + if (op == ID_TXT_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean + return pStack->Return(inst, pStk); + + pStk->SetError(TX_BADTYPE, &inst->m_token); + } + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes unary expression + +bool CBotExprUnaire::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->GivState() == 0) + { + if (!m_Expr->Execute(pile)) return false; // interrupted ? + pile->IncState(); + } + + CBotStack* pile2 = pile->AddStack(); + if (pile2->IfStep()) return false; + + CBotVar* var = pile->GivVar(); // get the result on the stack + + switch (GivTokenType()) + { + case ID_ADD: + break; + case ID_SUB: + var->Neg(); // change the sign + break; + case ID_NOT: + case ID_LOG_NOT: + case ID_TXT_NOT: + var->Not(); + break; + } + return pj->Return(pile); // forwards below +} + +void CBotExprUnaire::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if ( pile == NULL) return; + + if (pile->GivState() == 0) + { + m_Expr->RestoreState(pile, bMain); // interrupted here! + return; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// index management for arrays +// array [ expression ] + + +CBotIndexExpr::CBotIndexExpr() +{ + m_expr = NULL; + name = "CBotIndexExpr"; +} + +CBotIndexExpr::~CBotIndexExpr() +{ + delete m_expr; +} + +// finds a field from the instance at compile time + +bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + if (pVar->GivType(1) != CBotTypArrayPointer) + ASM_TRAP(); + + pVar = ((CBotVarArray*)pVar)->GivItem(0, false); // at compile time makes the element [0] + if (pVar == NULL) + { + pile->SetError(TX_OUTARRAY, m_token.GivEnd()); + return false; + } + if (m_next3 != NULL) return m_next3->ExecuteVar(pVar, pile); + return true; +} + +// attention, changes the pointer to the stack intentionally +// place the index calculated on the additional stack + + +bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) +{ + CBotStack* pj = pile; + + if (pVar->GivType(1) != CBotTypArrayPointer) + ASM_TRAP(); + + pile = pile->AddStack(); + + if (pile->GivState() == 0) + { + if (!m_expr->Execute(pile)) return false; + pile->IncState(); + } + // handles array + + CBotVar* p = pile->GivVar(); // result on the stack + + if (p == NULL || p->GivType() > CBotTypDouble) + { + pile->SetError(TX_BADINDEX, prevToken); + return pj->Return(pile); + } + + int n = p->GivValInt(); // position in the table + + pVar = ((CBotVarArray*)pVar)->GivItem(n, bExtend); + if (pVar == NULL) + { + pile->SetError(TX_OUTARRAY, prevToken); + return pj->Return(pile); + } + + pVar->Maj(pile->GivPUser(), true); + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile, prevToken, bStep, bExtend) ) return false; + + // does not release the stack + // to avoid recalculation of the index twice where appropriate + return true; +} + +void CBotIndexExpr::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + pile = pile->RestoreStack(); + if (pile == NULL) return; + + if (bMain && pile->GivState() == 0) + { + m_expr->RestoreState(pile, true); + return; + } + + if (m_next3) + m_next3->RestoreStateVar(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// field management in an instance (dot operator) +// toto.x + + +CBotFieldExpr::CBotFieldExpr() +{ + name = "CBotFieldExpr"; + m_nIdent = 0; +} + +CBotFieldExpr::~CBotFieldExpr() +{ +} + +void CBotFieldExpr::SetUniqNum(int num) +{ + m_nIdent = num; +} + + +// find a field from the instance at compile + +bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + if (pVar->GivType(1) != CBotTypPointer) + ASM_TRAP(); + + pVar = pVar->GivItemRef(m_nIdent); + if (pVar == NULL) + { + pile->SetError(TX_NOITEM, &m_token); + return false; + } + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile) ) return false; + + return true; +} + +bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) +{ + CBotStack* pj = pile; + pile = pile->AddStack(this); // changes in output stack + if (pile == EOX) return true; + + + if (pVar->GivType(1) != CBotTypPointer) + ASM_TRAP(); + + CBotVarClass* pItem = pVar->GivPointer(); + if (pItem == NULL) + { + pile->SetError(TX_NULLPT, prevToken); + return pj->Return(pile); + } + if (pItem->GivUserPtr() == OBJECTDELETED) + { + pile->SetError(TX_DELETEDPT, prevToken); + return pj->Return(pile); + } + + if (bStep && pile->IfStep()) return false; + + pVar = pVar->GivItemRef(m_nIdent); + if (pVar == NULL) + { + pile->SetError(TX_NOITEM, &m_token); + return pj->Return(pile); + } + + if (pVar->IsStatic()) + { + // for a static variable, takes it in the class itself + CBotClass* pClass = pItem->GivClass(); + pVar = pClass->GivItem(m_token.GivString()); + } + + // request the update of the element, if applicable + pVar->Maj(pile->GivPUser(), true); + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, bExtend) ) return false; + + // does not release the stack + // to maintain the state SetState () corresponding to step + + return true; +} + +void CBotFieldExpr::RestoreStateVar(CBotStack* &pj, bool bMain) +{ + pj = pj->RestoreStack(this); + if (pj == NULL) return; + + if (m_next3 != NULL) + m_next3->RestoreStateVar(pj, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// compile a left operand for an assignment +CBotLeftExpr::CBotLeftExpr() +{ + name = "CBotLeftExpr"; + m_nIdent = 0; +} + +CBotLeftExpr::~CBotLeftExpr() +{ +} + +// compiles an expression for a left-operand (left of an assignment) +// this can be +// toto +// toto[ 3 ] +// toto.x +// toto.pos.x +// toto[2].pos.x +// toto[1].pos[2].x +// toto[1][2][3] + +CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(p->GivStart()); + + // is it a variable name? + if (p->GivType() == TokenTypVar) + { + CBotLeftExpr* inst = new CBotLeftExpr(); // creates the object + + inst->SetToken(p); + + CBotVar* var; + + if (NULL != (var = pStk->FindVar(p))) // seek if known variable + { + inst->m_nIdent = var->GivUniqNum(); + if (inst->m_nIdent > 0 && inst->m_nIdent < 9000) + { + if ( var->IsPrivate(PR_READ) && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, p); + goto err; + } + // this is an element of the current class + // adds the equivalent of this. before + CBotToken pthis("this"); + inst->SetToken(&pthis); + inst->m_nIdent = -2; // indent for this + + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(p); // keeps the name of the token + inst->AddNext3(i); // add after + + var = pStk->FindVar(pthis); + var = var->GivItem(p->GivString()); + i->SetUniqNum(var->GivUniqNum()); + } + p = p->GivNext(); // next token + + while (true) + { + if (var->GivType() == CBotTypArrayPointer) + { + if (IsOfType( p, ID_OPBRK )) + { + CBotIndexExpr* i = new CBotIndexExpr(); + i->m_expr = CBotExpression::Compile(p, pStk); + inst->AddNext3(i); // add to the chain + + var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0] + + if (i->m_expr == NULL) + { + pStk->SetError(TX_BADINDEX, p->GivStart()); + goto err; + } + + if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto err; + } + continue; + } + } + + if (var->GivType(1) == CBotTypPointer) // for classes + { + if (IsOfType(p, ID_DOT)) + { + CBotToken* pp = p; + + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(pp); // keeps the name of the token + inst->AddNext3(i); // adds after + + if (p->GivType() == TokenTypVar) // must be a name + { + var = var->GivItem(p->GivString()); // get item correspondent + if (var != NULL) + { + if ( var->IsPrivate(PR_READ) && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, pp); + goto err; + } + + i->SetUniqNum(var->GivUniqNum()); + p = p->GivNext(); // skips the name + continue; + } + pStk->SetError(TX_NOITEM, p); + } + pStk->SetError(TX_DOT, p->GivStart()); + goto err; + } + } + break; + } + + + if (pStk->IsOk()) return (CBotLeftExpr*) pStack->Return(inst, pStk); + } + pStk->SetError(TX_UNDEFVAR, p); +err: + delete inst; + return (CBotLeftExpr*) pStack->Return(NULL, pStk); + } + + return (CBotLeftExpr*) pStack->Return(NULL, pStk); +} + +// runs, is a variable and assigns the result to the stack +bool CBotLeftExpr::Execute(CBotStack* &pj, CBotStack* array) +{ + CBotStack* pile = pj->AddStack(); + + CBotVar* var1 = NULL; + CBotVar* var2 = NULL; + // fetch a variable (not copy) + if (!ExecuteVar(var1, array, NULL, false)) return false; + + if (pile->IfStep()) return false; + + if (var1) + { + var2 = pj->GivVar(); // result on the input stack + if (var2) + { + CBotTypResult t1 = var1->GivTypResult(); + CBotTypResult t2 = var2->GivTypResult(); + if (t2.Eq(CBotTypPointer)) + { + CBotClass* c1 = t1.GivClass(); + CBotClass* c2 = t2.GivClass(); + if ( !c2->IsChildOf(c1)) + { + CBotToken* pt = &m_token; + pile->SetError(TX_BADTYPE, pt); + return pj->Return(pile); // operation performed + } + } + var1->SetVal(var2); // do assignment + } + pile->SetCopyVar(var1); // replace the stack with the copy of the variable + // (for name) + } + + return pj->Return(pile); // operation performed +} + +// fetch a variable during compilation + +bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + pVar = pile->FindVar(m_token); + if (pVar == NULL) return false; + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile) ) return false; + + return true; +} + +// fetch the variable at runtume + +bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep) +{ + pile = pile->AddStack(this); + + pVar = pile->FindVar(m_nIdent); + if (pVar == NULL) + { +#ifdef _DEBUG + ASM_TRAP(); +#endif + pile->SetError(2, &m_token); + return false; + } + + if (bStep && m_next3 == NULL && pile->IfStep()) return false; + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, true) ) return false; + + return true; +} + +void CBotLeftExpr::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + pile = pile->RestoreStack(this); + if (pile == NULL) return; + + if (m_next3 != NULL) + m_next3->RestoreStateVar(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// converts a string into integer +// may be of the form 0xabc123 + +long GivNumInt(const char* p) +{ + long num = 0; + while (*p >= '0' && *p <= '9') + { + num = num * 10 + *p - '0'; + p++; + } + if (*p == 'x' || *p == 'X') + { + while (*++p != 0) + { + if (*p >= '0' && *p <= '9') + { + num = num * 16 + *p - '0'; + continue; + } + if (*p >= 'A' && *p <= 'F') + { + num = num * 16 + *p - 'A' + 10; + continue; + } + if (*p >= 'a' && *p <= 'f') + { + num = num * 16 + *p - 'a' + 10; + continue; + } + break; + } + } + return num; +} + +// converts a string into a float number +extern float GivNumFloat(const char* p) +{ + double num = 0; + double div = 10; + bool bNeg = false; + + if (*p == '-') + { + bNeg = true; + p++; + } + while (*p >= '0' && *p <= '9') + { + num = num * 10. + (*p - '0'); + p++; + } + + if (*p == '.') + { + p++; + while (*p >= '0' && *p <= '9') + { + num = num + (*p - '0') / div; + div = div * 10; + p++; + } + } + + int exp = 0; + if (*p == 'e' || *p == 'E') + { + char neg = 0; + p++; + if (*p == '-' || *p == '+') neg = *p++; + + while (*p >= '0' && *p <= '9') + { + exp = exp * 10 + (*p - '0'); + p++; + } + if (neg == '-') exp = -exp; + } + + while (exp > 0) + { + num *= 10.0; + exp--; + } + + while (exp < 0) + { + num /= 10.0; + exp++; + } + + if (bNeg) num = -num; + return (float)num; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a token representing a number +CBotExprNum::CBotExprNum() +{ + name = "CBotExprNum"; +} + +CBotExprNum::~CBotExprNum() +{ +} + +CBotInstr* CBotExprNum::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + CBotExprNum* inst = new CBotExprNum(); + + inst->SetToken(p); + CBotString s = p->GivString(); + + inst->m_numtype = CBotTypInt; + if (p->GivType() == TokenTypDef) + { + inst->m_valint = p->GivIdKey(); + } + else + { + if (s.Find('.') >= 0 || ( s.Find('x') < 0 && ( s.Find('e') >= 0 || s.Find('E') >= 0 ) )) + { + inst->m_numtype = CBotTypFloat; + inst->m_valfloat = GivNumFloat(s); + } + else + { + inst->m_valint = GivNumInt(s); + } + } + + if (pStk->NextToken(p)) + { + CBotVar* var = CBotVar::Create((CBotToken*)NULL, inst->m_numtype); + pStk->SetVar(var); + + return pStack->Return(inst, pStk); + } + delete inst; + return pStack->Return(NULL, pStk); +} + +// execute, returns the corresponding number + +bool CBotExprNum::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, m_numtype); + + CBotString nombre ; + if (m_token.GivType() == TokenTypDef) + { + nombre = m_token.GivString(); + } + + switch (m_numtype) + { + case CBotTypShort: + case CBotTypInt: + var->SetValInt(m_valint, nombre); + break; + case CBotTypFloat: + var->SetValFloat(m_valfloat); + break; + } + pile->SetVar(var); // place on the stack + + return pj->Return(pile); // it's ok +} + +void CBotExprNum::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a token representing a string + +CBotExprAlpha::CBotExprAlpha() +{ + name = "CBotExprAlpha"; +} + +CBotExprAlpha::~CBotExprAlpha() +{ +} + +CBotInstr* CBotExprAlpha::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + CBotExprAlpha* inst = new CBotExprAlpha(); + + inst->SetToken(p); + p = p->GivNext(); + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString); + pStk->SetVar(var); + + return pStack->Return(inst, pStk); +} + +// execute, returns the corresponding string + +bool CBotExprAlpha::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString); + + CBotString chaine = m_token.GivString(); + chaine = chaine.Mid(1, chaine.GivLength()-2); // removes the quotes + + var->SetValString(chaine); // value of the number + + pile->SetVar(var); // put on the stack + + return pj->Return(pile); +} + +void CBotExprAlpha::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a token representing true or false + +CBotExprBool::CBotExprBool() +{ + name = "CBotExprBool"; +} + +CBotExprBool::~CBotExprBool() +{ +} + +CBotInstr* CBotExprBool::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + CBotExprBool* inst = NULL; + + if ( p->GivType() == ID_TRUE || + p->GivType() == ID_FALSE ) + { + inst = new CBotExprBool(); + inst->SetToken(p); // stores the operation false or true + p = p->GivNext(); + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean); + pStk->SetVar(var); + } + + return pStack->Return(inst, pStk); +} + +// executes, returns true or false + +bool CBotExprBool::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean); + + if (GivTokenType() == ID_TRUE) var->SetValInt(1); + else var->SetValInt(0); + + pile->SetVar(var); // put on the stack + return pj->Return(pile); // forwards below +} + +void CBotExprBool::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// management of the operand "null" + +CBotExprNull::CBotExprNull() +{ + name = "CBotExprNull"; +} + +CBotExprNull::~CBotExprNull() +{ +} + +// executes, returns an empty pointer + +bool CBotExprNull::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypNullPointer); + + var->SetInit(true); // null pointer valid + pile->SetVar(var); // place on the stack + return pj->Return(pile); // forwards below +} + +void CBotExprNull::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// management of the operand "nan" + +CBotExprNan::CBotExprNan() +{ + name = "CBotExprNan"; +} + +CBotExprNan::~CBotExprNan() +{ +} + +// executes, returns null pointer + +bool CBotExprNan::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypInt); + + var->SetInit(IS_NAN); // nan + pile->SetVar(var); // put on the stack + return pj->Return(pile); // forward below +} + +void CBotExprNan::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////// +// compile a variable name +// check that it is known on the stack +// and it has been initialized + +CBotExprVar::CBotExprVar() +{ + name = "CBotExprVar"; + m_nIdent = 0; +} + +CBotExprVar::~CBotExprVar() +{ +} + +CBotInstr* CBotExprVar::Compile(CBotToken* &p, CBotCStack* pStack, int privat) +{ + CBotToken* pDebut = p; + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(p->GivStart()); + + // is it a variable? + if (p->GivType() == TokenTypVar) + { + CBotInstr* inst = new CBotExprVar(); // create the object + + inst->SetToken(p); + + CBotVar* var; + + if (NULL != (var = pStk->FindVar(p))) // seek if known variable + { + int ident = var->GivUniqNum(); + ((CBotExprVar*)inst)->m_nIdent = ident; // identifies variable by its number + + if (ident > 0 && ident < 9000) + { + if ( var->IsPrivate(privat) && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, p); + goto err; + } + + // This is an element of the current class + // ads the equivalent of this. before + /// \TODO need to be fixed revised and fixed after adding unit + ///tests + CBotToken token("this"); + inst->SetToken(&token); + ((CBotExprVar*)inst)->m_nIdent = -2; // identificator for this + + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(p); // keeps the name of the token + i->SetUniqNum(ident); + inst->AddNext3(i); // added after + } + + p = p->GivNext(); // next token + + while (true) + { + if (var->GivType() == CBotTypArrayPointer) + { + if (IsOfType( p, ID_OPBRK )) // check if there is an aindex + { + CBotIndexExpr* i = new CBotIndexExpr(); + i->m_expr = CBotExpression::Compile(p, pStk); // compile the formula + inst->AddNext3(i); // add to the chain + + var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0] + + if (i->m_expr == NULL) + { + pStk->SetError(TX_BADINDEX, p->GivStart()); + goto err; + } + if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto err; + } + continue; + } + } + if (var->GivType(1) == CBotTypPointer) // for classes + { + if (IsOfType(p, ID_DOT)) + { + CBotToken* pp = p; + + if (p->GivType() == TokenTypVar) // must be a name + { + if (p->GivNext()->GivType() == ID_OPENPAR) // a method call? + { + CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var); + if (!pStk->IsOk()) goto err; + inst->AddNext3(i); // added after + return pStack->Return(inst, pStk); + } + else + { + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(pp); // keeps the name of the token + inst->AddNext3(i); // add after + var = var->GivItem(p->GivString()); // get item correspondent + if (var != NULL) + { + i->SetUniqNum(var->GivUniqNum()); + if ( var->IsPrivate() && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, pp); + goto err; + } + } + } + + + if (var != NULL) + { + p = p->GivNext(); // skips the name + continue; + } + pStk->SetError(TX_NOITEM, p); + goto err; + } + pStk->SetError(TX_DOT, p->GivStart()); + goto err; + } + } + + break; + } + + pStk->SetCopyVar(var); // place the copy of the variable on the stack (for type) + if (pStk->IsOk()) return pStack->Return(inst, pStk); + } + pStk->SetError(TX_UNDEFVAR, p); +err: + delete inst; + return pStack->Return(NULL, pStk); + } + + return pStack->Return(NULL, pStk); +} + +CBotInstr* CBotExprVar::CompileMethode(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(pp->GivStart()); + + // is it a variable ? + if (pp->GivType() == TokenTypVar) + { + CBotToken pthis("this"); + CBotVar* var = pStk->FindVar(pthis); + if (var == 0) return pStack->Return(NULL, pStk); + + CBotInstr* inst = new CBotExprVar(); + + // this is an element of the current class + // adds the equivalent of this. before + + inst->SetToken(&pthis); + ((CBotExprVar*)inst)->m_nIdent = -2; // ident for this + + CBotToken* pp = p; + + if (pp->GivType() == TokenTypVar) + { + if (pp->GivNext()->GivType() == ID_OPENPAR) // a method call? + { + CBotInstr* i = CBotInstrMethode::Compile(pp, pStk, var); + if (pStk->IsOk()) + { + inst->AddNext3(i); // add after + p = pp; // previous instruction + return pStack->Return(inst, pStk); + } + pStk->SetError(0,0); // the error is not adressed here + } + } + delete inst; + } + return pStack->Return(NULL, pStk); +} + + +// execute, making the value of a variable + +bool CBotExprVar::Execute(CBotStack* &pj) +{ + CBotVar* pVar = NULL; + CBotStack* pile = pj->AddStack(this); + + CBotStack* pile1 = pile; + + if (pile1->GivState() == 0) + { + if (!ExecuteVar(pVar, pile, NULL, true)) return false; // Get the variable fields and indexes according + + if (pVar) pile1->SetCopyVar(pVar); // place a copy on the stack + else + { + return pj->Return(pile1); + } + pile1->IncState(); + } + + pVar = pile1->GivVar(); + + if (pVar == NULL) + { + return pj->Return(pile1); + } + + if (pVar->GivInit() == IS_UNDEF) + { + CBotToken* pt = &m_token; + while (pt->GivNext() != NULL) pt = pt->GivNext(); + pile1->SetError(TX_NOTINIT, pt); + return pj->Return(pile1); + } + return pj->Return(pile1); // operation completed +} + +void CBotExprVar::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotStack* pile1 = pile; + + if (pile1->GivState() == 0) + { + RestoreStateVar(pile, bMain); // retrieves the variable fields and indexes according + return; + } +} + +// fetch a variable at runtime + +bool CBotExprVar::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep) +{ + CBotStack* pile = pj; + pj = pj->AddStack(this); + + if (bStep && m_nIdent>0 && pj->IfStep()) return false; + + pVar = pj->FindVar(m_nIdent, true); // tries with the variable update if necessary + if (pVar == NULL) + { +#ifdef _DEBUG + ASM_TRAP(); +#endif + pj->SetError(1, &m_token); + return false; + } + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pj, &m_token, bStep, false) ) + return false; // field of an instance, table, methode + + return pile->ReturnKeep(pj); // does not put on stack but get the result if a method was called +} + + +// fetch variable at runtime + +void CBotExprVar::RestoreStateVar(CBotStack* &pj, bool bMain) +{ + pj = pj->RestoreStack(this); + if (pj == NULL) return; + + if (m_next3 != NULL) + m_next3->RestoreStateVar(pj, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// compile a list of parameters + +CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars) +{ + bool first = true; + CBotInstr* ret = NULL; // to return to the list + + CBotCStack* pile = pStack; + int i = 0; + + if (IsOfType(p, ID_OPENPAR)) + { + int start, end; + if (!IsOfType(p, ID_CLOSEPAR)) while (true) + { + start = p->GivStart(); + pile = pile->TokenStack(); // keeps the result on the stack + + if (first) pStack->SetStartError(start); + first = false; + + CBotInstr* param = CBotExpression::Compile(p, pile); + end = p->GivStart(); + + if (!pile->IsOk()) + { + return pStack->Return(NULL, pile); + } + + if (ret == NULL) ret = param; + else ret->AddNext(param); // construct the list + + if (param != NULL) + { + if (pile->GivTypResult().Eq(99)) + { + delete pStack->TokenStack(); + pStack->SetError(TX_VOID, p->GivStart()); + return NULL; + } + ppVars[i] = pile->GivVar(); + ppVars[i]->GivToken()->SetPos(start, end); + i++; + + if (IsOfType(p, ID_COMMA)) continue; // skips the comma + if (IsOfType(p, ID_CLOSEPAR)) break; + } + + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + delete pStack->TokenStack(); + return NULL; + } + } + ppVars[i] = NULL; + return ret; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a method call + +CBotInstrMethode::CBotInstrMethode() +{ + m_Parameters = NULL; + m_MethodeIdent = 0; + name = "CBotInstrMethode"; +} + +CBotInstrMethode::~CBotInstrMethode() +{ + delete m_Parameters; +} + +CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var) +{ + CBotInstrMethode* inst = new CBotInstrMethode(); + inst->SetToken(p); // corresponding token + + if (NULL != var) + { + CBotToken* pp = p; + p = p->GivNext(); + + if (p->GivType() == ID_OPENPAR) + { + inst->m_NomMethod = pp->GivString(); + + // compiles the list of parameters + CBotVar* ppVars[1000]; + inst->m_Parameters = CompileParams(p, pStack, ppVars); + + if (pStack->IsOk()) + { + CBotClass* pClass = var->GivClass(); // pointer to the class + inst->m_ClassName = pClass->GivName(); // name of the class + CBotTypResult r = pClass->CompileMethode(inst->m_NomMethod, var, ppVars, + pStack, inst->m_MethodeIdent); + delete pStack->TokenStack(); // release parameters on the stack + inst->m_typRes = r; + + if (inst->m_typRes.GivType() > 20) + { + pStack->SetError(inst->m_typRes.GivType(), pp); + delete inst; + return NULL; + } + // put the result on the stack to have something + if (inst->m_typRes.GivType() > 0) + { + CBotVar* pResult = CBotVar::Create("", inst->m_typRes); + if (inst->m_typRes.Eq(CBotTypClass)) + { + pResult->SetClass(inst->m_typRes.GivClass()); + } + pStack->SetVar(pResult); + } + return inst; + } + delete inst; + return NULL; + } + } + pStack->SetError(1234, p); + delete inst; + return NULL; +} + +// execute the method call + +bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend) +{ + CBotVar* ppVars[1000]; + CBotStack* pile1 = pj->AddStack(this, true); // a place for the copy of This + + if (pVar->GivPointer() == NULL) + { + pj->SetError(TX_NULLPT, prevToken); + } + + if (pile1->IfStep()) return false; + + CBotStack* pile2 = pile1->AddStack(); // for the next parameters + + if ( pile1->GivState() == 0) + { + CBotVar* pThis = CBotVar::Create(pVar); + pThis->Copy(pVar); + // this value should be taken before the evaluation parameters + // Test.Action (Test = Other); + // action must act on the value before test = Other! + + pThis->SetName("this"); + pThis->SetUniqNum(-2); + pile1->AddVar(pThis); + pile1->IncState(); + } + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + if (pile2->GivState() == 0) + { + if (!p->Execute(pile2)) return false; // interrupted here? + if (!pile2->SetState(1)) return false; // special mark to recognize parameters + } + ppVars[i++] = pile2->GivVar(); // construct the list of pointers + pile2 = pile2->AddStack(); // space on the stack for the result + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotClass* pClass = CBotClass::Find(m_ClassName); + CBotVar* pThis = pile1->FindVar(-2); + CBotVar* pResult = NULL; + if (m_typRes.GivType() > 0) pResult = CBotVar::Create("", m_typRes); + if (m_typRes.Eq(CBotTypClass)) + { + pResult->SetClass(m_typRes.GivClass()); + } + CBotVar* pRes = pResult; + + if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod, + pThis, ppVars, + pResult, pile2, GivToken())) return false; + if (pRes != pResult) delete pRes; + + pVar = NULL; // does not return value for this + return pj->Return(pile2); // release the entire stack +} + +void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + if (!bMain) return; + + CBotVar* ppVars[1000]; + CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This + if (pile1 == NULL) return; + + CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming + if (pile2 == NULL) return; + + CBotVar* pThis = pile1->FindVar("this"); + pThis->SetUniqNum(-2); + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + if (pile2->GivState() == 0) + { + p->RestoreState(pile2, true); // interrupted here! + return; + } + ppVars[i++] = pile2->GivVar(); // construct the list of pointers + pile2 = pile2->RestoreStack(); + if (pile2 == NULL) return; + + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotClass* pClass = CBotClass::Find(m_ClassName); + CBotVar* pResult = NULL; + + CBotVar* pRes = pResult; + + pClass->RestoreMethode(m_MethodeIdent, m_NomMethod, + pThis, ppVars, pile2); +} + + +bool CBotInstrMethode::Execute(CBotStack* &pj) +{ + CBotVar* ppVars[1000]; + CBotStack* pile1 = pj->AddStack(this, true); // place for the copy of This + + if (pile1->IfStep()) return false; + + CBotStack* pile2 = pile1->AddStack(); // and for the parameters coming + + if ( pile1->GivState() == 0) + { + CBotVar* pThis = pile1->CopyVar(m_token); + // this value should be taken before the evaluation parameters + // Test.Action (Test = Other); + // Action must act on the value before test = Other! + pThis->SetName("this"); + pile1->AddVar(pThis); + pile1->IncState(); + } + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + if (p != NULL) while ( true) + { + if (pile2->GivState() == 0) + { + if (!p->Execute(pile2)) return false; // interrupted here? + if (!pile2->SetState(1)) return false; // special mark to recognize parameters + } + ppVars[i++] = pile2->GivVar(); // construct the list of pointers + pile2 = pile2->AddStack(); // space on the stack for the results + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotClass* pClass = CBotClass::Find(m_ClassName); + CBotVar* pThis = pile1->FindVar("this"); + CBotVar* pResult = NULL; + if (m_typRes.GivType()>0) pResult = CBotVar::Create("", m_typRes); + if (m_typRes.Eq(CBotTypClass)) + { + pResult->SetClass(m_typRes.GivClass()); + } + CBotVar* pRes = pResult; + + if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod, + pThis, ppVars, + pResult, pile2, GivToken())) return false; // interupted + + // set the new value of this in place of the old variable + CBotVar* old = pile1->FindVar(m_token); + old->Copy(pThis, false); + + if (pRes != pResult) delete pRes; + + return pj->Return(pile2); // release the entire stack +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compile an instruction "new" + +CBotNew::CBotNew() +{ + name = "CBotNew"; + m_Parameters = NULL; + m_nMethodeIdent = 0; +} + +CBotNew::~CBotNew() +{ +} + +CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + if (!IsOfType(p, ID_NEW)) return NULL; + + // verifies that the token is a class name + if (p->GivType() != TokenTypVar) return NULL; + + CBotClass* pClass = CBotClass::Find(p); + if (pClass == NULL) + { + pStack->SetError(TX_BADNEW, p); + return NULL; + } + + CBotNew* inst = new CBotNew(); + inst->SetToken(pp); + + inst->m_vartoken = p; + p = p->GivNext(); + + // creates the object on the "job" + // with a pointer to the object + CBotVar* pVar = CBotVar::Create("", pClass); + + // do the call of the creator + CBotCStack* pStk = pStack->TokenStack(); + { + // check if there are parameters + CBotVar* ppVars[1000]; + inst->m_Parameters = CompileParams(p, pStk, ppVars); + if (!pStk->IsOk()) goto error; + + // constructor exist? + CBotTypResult r = pClass->CompileMethode(pClass->GivName(), pVar, ppVars, pStk, inst->m_nMethodeIdent); + delete pStk->TokenStack(); // release extra stack + int typ = r.GivType(); + + // if there is no constructor, and no parameters either, it's ok + if (typ == TX_UNDEFCALL && inst->m_Parameters == NULL) typ = 0; + pVar->SetInit(true); // mark the instance as init + + if (typ>20) + { + pStk->SetError(typ, inst->m_vartoken.GivEnd()); + goto error; + } + + // if the constructor does not exist, but there are parameters + if (typ<0 && inst->m_Parameters != NULL) + { + pStk->SetError(TX_NOCONST, &inst->m_vartoken); + goto error; + } + + // makes pointer to the object on the stack + pStk->SetVar(pVar); + return pStack->Return(inst, pStk); + } +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes instruction "new" + +bool CBotNew::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); //main stack + + if (pile->IfStep()) return false; + + CBotStack* pile1 = pj->AddStack2(); //secondary stack + + CBotVar* pThis = NULL; + + CBotToken* pt = &m_vartoken; + CBotClass* pClass = CBotClass::Find(pt); + + // create the variable "this" pointer type to the stack + + if ( pile->GivState()==0) + { + // create an instance of the requested class + // and initialize the pointer to that object + + + pThis = CBotVar::Create("this", pClass); + pThis->SetUniqNum(-2) ; + + pile1->SetVar(pThis); // place on stack1 + pile->IncState(); + } + + // fetch the this pointer if it was interrupted + if ( pThis == NULL) + { + pThis = pile1->GivVar(); // find the pointer + } + + // is there an assignment or parameters (constructor) + if ( pile->GivState()==1) + { + // evaluates the constructor of the instance + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + pile2 = pile2->AddStack(); // space on the stack for the result + if (pile2->GivState() == 0) + { + if (!p->Execute(pile2)) return false; // interrupted here? + pile2->SetState(1); + } + ppVars[i++] = pile2->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + // create a variable for the result + CBotVar* pResult = NULL; // constructos still void + + if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(), + pThis, ppVars, + pResult, pile2, GivToken())) return false; // interrupt + + pThis->ConstructorSet(); // indicates that the constructor has been called + } + + return pj->Return(pile1); // passes below +} + +void CBotNew::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); //primary stack + if (pile == NULL) return; + + CBotStack* pile1 = pj->AddStack2(); //secondary stack + + CBotToken* pt = &m_vartoken; + CBotClass* pClass = CBotClass::Find(pt); + + // create the variable "this" pointer type to the object + + if ( pile->GivState()==0) + { + return; + } + + CBotVar* pThis = pile1->GivVar(); // find the pointer + pThis->SetUniqNum(-2); + + // is ther an assignment or parameters (constructor) + if ( pile->GivState()==1) + { + // evaluates the constructor of the instance + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + pile2 = pile2->RestoreStack(); // space on the stack for the result + if (pile2 == NULL) return; + + if (pile2->GivState() == 0) + { + p->RestoreState(pile2, bMain); // interrupt here! + return; + } + ppVars[i++] = pile2->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GivString(), pThis, + ppVars, pile2) ; // interrupt here! + } +} + +///////////////////////////////////////////////////////////// +// check if two results are consistent to make an operation + +bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op) +{ + int t1 = type1.GivType(); + int t2 = type2.GivType(); + + int max = (t1 > t2) ? t1 : t2; + + if (max == 99) return false; // result is void? + + // special case for strin concatenation + if (op == ID_ADD && max >= CBotTypString) return true; + if (op == ID_ASSADD && max >= CBotTypString) return true; + if (op == ID_ASS && t1 == CBotTypString) return true; + + if (max >= CBotTypBoolean) + { + if ( (op == ID_EQ || op == ID_NE) && + (t1 == CBotTypPointer && t2 == CBotTypNullPointer)) return true; + if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && + (t2 == CBotTypPointer && t1 == CBotTypNullPointer)) return true; + if ( (op == ID_EQ || op == ID_NE) && + (t1 == CBotTypArrayPointer && t2 == CBotTypNullPointer)) return true; + if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && + (t2 == CBotTypArrayPointer && t1 == CBotTypNullPointer)) return true; + if (t2 != t1) return false; + if (t1 == CBotTypArrayPointer) return type1.Compare(type2); + if (t1 == CBotTypPointer || + t1 == CBotTypClass || + t1 == CBotTypIntrinsic ) + { + CBotClass* c1 = type1.GivClass(); + CBotClass* c2 = type2.GivClass(); + + return c1->IsChildOf(c2) || c2->IsChildOf(c1); + // accept the case in reverse + // the transaction will be denied at runtime if the pointer is not + // compatible + } + + return true; + } + + type1.SetType(max); + type2.SetType(max); + return true; +} + +// check if two variables are compatible for parameter passing + +bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2) +{ + int t1 = type1.GivType(); + int t2 = type2.GivType(); + + if (t1 == CBotTypIntrinsic) t1 = CBotTypClass; + if (t2 == CBotTypIntrinsic) t2 = CBotTypClass; + + int max = (t1 > t2) ? t1 : t2; + + if (max == 99) return false; // result is void? + + if (max >= CBotTypBoolean) + { + if (t2 != t1) return false; + + if (max == CBotTypArrayPointer) + return TypesCompatibles(type1.GivTypElem(), type2.GivTypElem()); + + if (max == CBotTypClass || max == CBotTypPointer) + return type1.GivClass() == type2.GivClass() ; + + return true ; + } + return true; +} + + +///////////////////////////////////////////////////////////////////////////////////// +// file management + +// necessary because it is not possible to do the fopen in the main program +// fwrite and fread in a dll or using the FILE * returned. + + +FILE* fOpen(const char* name, const char* mode) +{ + return fopen(name, mode); +} + +int fClose(FILE* filehandle) +{ + return fclose(filehandle); +} + +size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle) +{ + return fwrite(buffer, elemsize, length, filehandle); +} + +size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle) +{ + return fread(buffer, elemsize, length, filehandle); +} + +size_t fWrite(const void *buffer, size_t length, FILE* filehandle) +{ + return fwrite(buffer, 1, length, filehandle); +} + +size_t fRead(void *buffer, size_t length, FILE* filehandle) +{ + return fread(buffer, 1, length, filehandle); +} + + +//////////////////////////////////////// + -- cgit v1.2.3-1-g7c22