diff options
Diffstat (limited to 'src/CBot')
-rw-r--r-- | src/CBot/CBot.cpp | 7927 | ||||
-rw-r--r-- | src/CBot/CBot.h | 3465 | ||||
-rw-r--r-- | src/CBot/CBotClass.cpp | 1762 |
3 files changed, 6578 insertions, 6576 deletions
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); +} + + +//////////////////////////////////////// + diff --git a/src/CBot/CBot.h b/src/CBot/CBot.h index 3b7d7e8..ebc8e52 100644 --- a/src/CBot/CBot.h +++ b/src/CBot/CBot.h @@ -1,1733 +1,1732 @@ -// * 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/.////////////////////////////////////////////////////////////////////
-/**
- * \file CBot.h
- * \brief Interpreter of the language CBot for COLOBOT game
- */
-
-
-
-#include "resource.h"
-#include "CBotDll.h" // public definitions
-#include "CBotToken.h" // token management
-
-#define STACKRUN true /// \def return execution directly on a suspended routine
-#define STACKMEM true /// \def preserve memory for the execution stack
-#define MAXSTACK 990 /// \def stack size reserved
-
-#define EOX (CBotStack*)-1 /// \def tag special condition
-
-
-// fix for MSVC instruction __asm int 3 (setting a trap)
-#if defined(__MINGW32__) || defined(__GNUC__)
-#define ASM_TRAP() asm("int $3");
-#else
-#define ASM_TRAP() __asm int 3;
-#endif
-
-/////////////////////////////////////////////////////////////////////
-// forward declaration
-
-class CBotCompExpr; // an expression like
- // () <= ()
-class CBotAddExpr; // an expression like
- // () + ()
-class CBotParExpr; // basic type or instruction in parenthesis
- // Toto.truc
- // 12.5
- // "string"
- // ( expression )
-class CBotExprVar; // a variable name as
- // Toto
- // chose.truc.machin
-class CBotWhile; // while (...) {...};
-class CBotIf; // if (...) {...} else {...}
-class CBotDefParam; // paramerer list of a function
-class CBotRepeat; // repeat (nb) {...}
-
-
-
-////////////////////////////////////////////////////////////////////////
-// Management of the execution stack
-////////////////////////////////////////////////////////////////////////
-
-// actually, externally, the only thing he can do
-// is to create an instance of a stack
-// to use for routine CBotProgram :: Execute (CBotStack)
-
-
-/**\class CBotStack
- * \brief Management of the execution stack.
- * \brief Actually the only thing it can do is to create an instance of a stack
- * \brief to use for routine CBotProgram :: Execute(CBotStack)*/
-class CBotStack
-{
-public:
-#if STACKMEM
- /**
- * \brief FirstStack Allocate first stack
- * \return pointer to created stack
- */
- static CBotStack * FirstStack();
-
- /** \brief Delete Remove current stack */
- void Delete();
-#endif
-
- /**
- * \brief CBotStack Constructor of the stack
- * \param ppapa Not used.
- */
- CBotStack(CBotStack* ppapa);
-
-
- /** \brief ~CBotStack Destructor */
- ~CBotStack();
-
- /**
- * \brief StackOver Check if end of stack is reached
- * \return true if end of stack
- */
- bool StackOver();
-
- /**
- * \brief GivError Get error number of the stack
- * \param [out] start beginning of the stack
- * \param [out] end end of stack
- * \return error number
- */
- int GivError(int& start, int& end);
-
- /**
- * \brief GivError Get error number
- * \return eror number
- */
- int GivError();// rend le numéro d'erreur retourné
-
- /**
- * \brief Reset Reset error at and set user
- * \param [in] pUser User of stack
- */
- void Reset(void* pUser);
-
- /**
- * \brief SetType Determines the type.
- * \param type Type of instruction on the stack.
- */
- void SetType(CBotTypResult& type);
-
- /**
- * \brief GivType Get the type of value on the stack.
- * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic).
- * \return Type number.
- */
- int GivType(int mode = 0);
-
- /**
- * \brief Gives the type of complete value on the stack.
- * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic).
- * \return Type of an element.
- */
- CBotTypResult GivTypResult(int mode = 0);
-
- /**
- * \brief Adds a local variable.
- * \param [in] p Variable to be added.
- */
- void AddVar(CBotVar* p);
-
- /**
- * \brief Fetch a variable by its token.
- * \brief This may be a composite variable
- * \param [in] pToken Token upon which search is performed
- * \param [in] bUpdate Not used. Probably need to be removed
- * \param [in] bModif Not used. Probably need to be removed
- * \return Found variable
- */
- CBotVar* FindVar(CBotToken* &pToken, bool bUpdate = false,
- bool bModif = false);
-
- /**
- * \brief Fetch a variable by its token.
- * \brief This may be a composite variable
- * \param [in] pToken Token upon which search is performed
- * \param [in] bUpdate Not used. Probably need to be removed
- * \param [in] bModif Not used. Probably need to be removed
- * \return Found variable
- */
- CBotVar* FindVar(CBotToken& Token, bool bUpdate = false,
- bool bModif = false);
-
- /**
- * \brief Fetch variable by its name
- * \param [in] name Name of variable to find
- * \return Found variable
- */
- CBotVar* FindVar(const char* name);
-
- /**
- * \brief Fetch a variable on the stack according to its identification number
- * \brief This is faster than comparing names
- * \param [in] ident Identifier of a variable
- * \param [in] bUpdate Not used. Probably need to be removed
- * \param [in] bModif Not used. Probably need to be removed
- * \return Found variable
- */
- CBotVar* FindVar(long ident, bool bUpdate = false,
- bool bModif = false);
-
- /**
- * \brief Find variable by its token and returns a copy of it.
- * \param Token Token upon which search is performed
- * \param bUpdate Not used.
- * \return Found variable, NULL if not found
- */
- CBotVar* CopyVar(CBotToken& Token, bool bUpdate = false);
-
-
- CBotStack* AddStack(CBotInstr* instr = NULL, bool bBlock = false); // étend le stack
- CBotStack* AddStackEOX(CBotCall* instr = NULL, bool bBlock = false); // étend le stack
- CBotStack* RestoreStack(CBotInstr* instr = NULL);
- CBotStack* RestoreStackEOX(CBotCall* instr = NULL);
-
- CBotStack* AddStack2(bool bBlock = false); // étend le stack
- bool Return(CBotStack* pFils); // transmet le résultat au dessus
- bool ReturnKeep(CBotStack* pFils); // transmet le résultat sans réduire la pile
- bool BreakReturn(CBotStack* pfils, const char* name = NULL);
- // en cas de break éventuel
- bool IfContinue(int state, const char* name);
- // ou de "continue"
-
- bool IsOk();
-
- bool SetState(int n, int lim = -10); // sélectionne un état
- int GivState(); // dans quel état j'ère ?
- bool IncState(int lim = -10); // passe à l'état suivant
- bool IfStep(); // faire du pas à pas ?
- bool Execute();
-
- void SetVar( CBotVar* var );
- void SetCopyVar( CBotVar* var );
- CBotVar* GivVar();
- CBotVar* GivCopyVar();
- CBotVar* GivPtVar();
- bool GivRetVar(bool bRet);
- long GivVal();
-
- void SetStartError(int pos);
- void SetError(int n, CBotToken* token = NULL);
- void SetPosError(CBotToken* token);
- void ResetError(int n, int start, int end);
- void SetBreak(int val, const char* name);
-
- void SetBotCall(CBotProgram* p);
- CBotProgram* GivBotCall(bool bFirst = false);
- void* GivPUser();
- bool GivBlock();
-
-
- bool ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype);
- void RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar);
-
- bool SaveState(FILE* pf);
- bool RestoreState(FILE* pf, CBotStack* &pStack);
-
- static
- void SetTimer(int n);
-
- void GetRunPos(const char* &FunctionName, int &start, int &end);
- CBotVar* GivStackVars(const char* &FunctionName, int level);
-
- int m_temp;
-
-private:
- CBotStack* m_next;
- CBotStack* m_next2;
- CBotStack* m_prev;
- friend class CBotInstArray;
-
-#ifdef _DEBUG
- int m_index;
-#endif
- int m_state;
- int m_step;
- static int m_error;
- static int m_start;
- static int m_end;
- static
- CBotVar* m_retvar; // résultat d'un return
-
- CBotVar* m_var; // résultat des opérations
- CBotVar* m_listVar; // les variables déclarées à ce niveau
-
- bool m_bBlock; // fait partie d'un bloc (variables sont locales à ce bloc)
- bool m_bOver; // limites de la pile ?
-// bool m_bDontDelete; // spécial, ne pas détruire les variables au delete
- CBotProgram* m_prog; // les fonctions définies par user
-
- static
- int m_initimer;
- static
- int m_timer;
- static
- CBotString m_labelBreak;
- static
- void* m_pUser;
-
- CBotInstr* m_instr; // l'instruction correspondante
- bool m_bFunc; // une entrée d'une fonction ?
- CBotCall* m_call; // point de reprise dans un call extern
- friend class CBotTry;
-};
-
-// les routines inline doivent être déclarées dans le fichier .h
-
-inline bool CBotStack::IsOk()
-{
- return (m_error == 0);
-}
-
-inline int CBotStack::GivState()
-{
- return m_state;
-}
-
-inline int CBotStack::GivError()
-{
- return m_error;
-}
-
-////////////////////////////////////////////////////////////////////////
-// Gestion de la pile de compilation
-////////////////////////////////////////////////////////////////////////
-
-
-class CBotCStack
-{
-private:
- CBotCStack* m_next;
- CBotCStack* m_prev;
-
- static
- int m_error;
- static
- int m_end;
- int m_start;
-
- CBotVar* m_var; // résultat des opérations
-
- bool m_bBlock; // fait partie d'un bloc (variables sont locales à ce bloc)
- CBotVar* m_listVar;
-
- static
- CBotProgram* m_prog; // liste des fonctions compilées
- static
- CBotTypResult m_retTyp;
-// static
-// CBotToken* m_retClass;
-
-public:
- CBotCStack(CBotCStack* ppapa);
- ~CBotCStack();
-
- bool IsOk();
- int GivError();
- int GivError(int& start, int& end);
- // rend le numéro d'erreur retourné
-
- void SetType(CBotTypResult& type);// détermine le type
- CBotTypResult GivTypResult(int mode = 0); // donne le type de valeur sur le stack
- int GivType(int mode = 0); // donne le type de valeur sur le stack
- CBotClass* GivClass(); // donne la classe de la valeur sur le stack
-
- void AddVar(CBotVar* p); // ajoute une variable locale
- CBotVar* FindVar(CBotToken* &p); // trouve une variable
- CBotVar* FindVar(CBotToken& Token);
- bool CheckVarLocal(CBotToken* &pToken);
- CBotVar* CopyVar(CBotToken& Token); // trouve et rend une copie
-
- CBotCStack* TokenStack(CBotToken* pToken = NULL, bool bBlock = false);
- CBotInstr* Return(CBotInstr* p, CBotCStack* pParent); // transmet le résultat au dessus
- CBotFunction* ReturnFunc(CBotFunction* p, CBotCStack* pParent); // transmet le résultat au dessus
-
- void SetVar( CBotVar* var );
- void SetCopyVar( CBotVar* var );
- CBotVar* GivVar();
-
- void SetStartError(int pos);
- void SetError(int n, int pos);
- void SetError(int n, CBotToken* p);
- void ResetError(int n, int start, int end);
-
- void SetRetType(CBotTypResult& type);
- CBotTypResult GivRetType();
-
-// void SetBotCall(CBotFunction* &pFunc);
- void SetBotCall(CBotProgram* p);
- CBotProgram* GivBotCall();
- CBotTypResult CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent);
- bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
-
- bool NextToken(CBotToken* &p);
-};
-
-
-extern bool SaveVar(FILE* pf, CBotVar* pVar);
-
-
-/////////////////////////////////////////////////////////////////////
-// classes defining an instruction
-class CBotInstr
-{
-private:
- static
- CBotStringArray
- m_labelLvl;
-protected:
- CBotToken m_token; // keeps the token
- CBotString name; // debug
- CBotInstr* m_next; // linked command
- CBotInstr* m_next2b; // second list definition chain
- CBotInstr* m_next3; // third list for indices and fields
- CBotInstr* m_next3b; // necessary for reporting tables
-/*
- for example, the following program
- int x[]; x[1] = 4;
- int y[x[1]][10], z;
- is generated
- CBotInstrArray
- m_next3b-> CBotEmpty
- m_next->
- CBotExpression ....
- m_next->
- CBotInstrArray
- m_next3b-> CBotExpression ('x') ( m_next3-> CBotIndexExpr ('1') )
- m_next3b-> CBotExpression ('10')
- m_next2-> 'z'
- m_next->...
-
-*/
-
- static
- int m_LoopLvl;
- friend class CBotClassInst;
- friend class CBotInt;
- friend class CBotListArray;
-
-public:
- CBotInstr();
- virtual
- ~CBotInstr();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- static
- CBotInstr* CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first = true);
-
- virtual
- bool Execute(CBotStack* &pj);
- virtual
- bool Execute(CBotStack* &pj, CBotVar* pVar);
- virtual
- void RestoreState(CBotStack* &pj, bool bMain);
-
- virtual
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- virtual
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
- virtual
- void RestoreStateVar(CBotStack* &pile, bool bMain);
-
- virtual
- bool CompCase(CBotStack* &pj, int val);
-
- void SetToken(CBotToken* p);
- int GivTokenType();
- CBotToken* GivToken();
-
- void AddNext(CBotInstr* n);
- CBotInstr* GivNext();
- void AddNext3(CBotInstr* n);
- CBotInstr* GivNext3();
- void AddNext3b(CBotInstr* n);
- CBotInstr* GivNext3b();
-
- static
- void IncLvl(CBotString& label);
- static
- void IncLvl();
- static
- void DecLvl();
- static
- bool ChkLvl(const CBotString& label, int type);
-
- bool IsOfClass(CBotString name);
-};
-
-class CBotWhile : public CBotInstr
-{
-private:
- CBotInstr* m_Condition; // la condition
- CBotInstr* m_Block; // les instructions
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotWhile();
- ~CBotWhile();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotRepeat : public CBotInstr
-{
-private:
- /// Number of iterations
- CBotInstr* m_NbIter;
-
- /// Instructions
- CBotInstr* m_Block;
-
- /// Label
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotRepeat();
- ~CBotRepeat();
-
- /// Static method used for compilation
- static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-
- /// Execute
- bool Execute(CBotStack* &pj);
-
- /// Restore state
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotDo : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_Condition; // la condition
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotDo();
- ~CBotDo();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotFor : public CBotInstr
-{
-private:
- CBotInstr* m_Init; // intruction initiale
- CBotInstr* m_Test; // la condition de test
- CBotInstr* m_Incr; // instruction pour l'incrément
- CBotInstr* m_Block; // les instructions
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotFor();
- ~CBotFor();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotBreak : public CBotInstr
-{
-private:
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotBreak();
- ~CBotBreak();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotReturn : public CBotInstr
-{
-private:
- CBotInstr* m_Instr; // le paramètre à retourner
-
-public:
- CBotReturn();
- ~CBotReturn();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotSwitch : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // value à chercher
- CBotInstr* m_Block; // les instructions
-
-public:
- CBotSwitch();
- ~CBotSwitch();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotCase : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // valeur à comparer
-
-public:
- CBotCase();
- ~CBotCase();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
- bool CompCase(CBotStack* &pj, int val);
-};
-
-class CBotCatch : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_Cond; // la condition
- CBotCatch* m_next; // le catch suivant
- friend class CBotTry;
-
-public:
- CBotCatch();
- ~CBotCatch();
- static
- CBotCatch* Compile(CBotToken* &p, CBotCStack* pStack);
- bool TestCatch(CBotStack* &pj, int val);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
- void RestoreCondState(CBotStack* &pj, bool bMain);
-};
-
-class CBotTry : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotCatch* m_ListCatch; // les catches
- CBotInstr* m_FinalInst; // instruction finale
-
-public:
- CBotTry();
- ~CBotTry();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotThrow : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // la valeur à envoyer
-
-public:
- CBotThrow();
- ~CBotThrow();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotStartDebugDD : public CBotInstr
-{
-private:
-
-public:
- CBotStartDebugDD();
- ~CBotStartDebugDD();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
-};
-
-
-class CBotIf : public CBotInstr
-{
-private:
- CBotInstr* m_Condition; // la condition
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_BlockElse; // les instructions
-
-public:
- CBotIf();
- ~CBotIf();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-// définition d'un nombre entier
-
-class CBotInt : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-/// CBotInstr* m_next; // plusieurs définitions enchaînées
-
-public:
- CBotInt();
- ~CBotInt();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un tableau
-
-class CBotInstArray : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_listass; // liste d'assignations pour le tableau
- CBotTypResult
- m_typevar; // type d'éléments
-// CBotString m_ClassName;
-
-public:
- CBotInstArray();
- ~CBotInstArray();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-// définition d'une liste d'assignation pour un tableau
-// int [ ] a [ ] = ( ( 1, 2, 3 ) , ( 3, 2, 1 ) ) ;
-
-class CBotListArray : public CBotInstr
-{
-private:
- CBotInstr* m_expr; // expression pour un élément
- // les autres sont chaînés avec CBotInstr::m_next3;
-public:
- CBotListArray();
- ~CBotListArray();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
- bool Execute(CBotStack* &pj, CBotVar* pVar);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotEmpty : public CBotInstr
-{
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un booléen
-
-class CBotBoolean : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotBoolean();
- ~CBotBoolean();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-// définition d'un nombre réel
-
-class CBotFloat : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotFloat();
- ~CBotFloat();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un elément string
-
-class CBotIString : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotIString();
- ~CBotIString();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un elément dans une classe quelconque
-
-class CBotClassInst : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotClass* m_pClass; // référence à la classe
- CBotInstr* m_Parameters; // les paramètres à évaluer pour le constructeur
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
- bool m_hasParams; // il y a des paramètres ?
- long m_nMethodeIdent;
-
-public:
- CBotClassInst();
- ~CBotClassInst();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass = NULL);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotCondition : public CBotInstr
-{
-private:
-
-public:
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-
-// left opérande
-// n'accepte que les expressions pouvant être à gauche d'une assignation
-
-class CBotLeftExpr : public CBotInstr
-{
-private:
- long m_nIdent;
-
-public:
- CBotLeftExpr();
- ~CBotLeftExpr();
- static
- CBotLeftExpr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack, CBotStack* array);
-
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
- void RestoreStateVar(CBotStack* &pile, bool bMain);
-};
-
-
-// gestion des champs d'une instance
-
-class CBotFieldExpr : public CBotInstr
-{
-private:
- friend class CBotExpression;
- int m_nIdent;
-
-public:
- CBotFieldExpr();
- ~CBotFieldExpr();
- void SetUniqNum(int num);
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-// gestion des index dans les tableaux
-
-class CBotIndexExpr : public CBotInstr
-{
-private:
- CBotInstr* m_expr; // expression pour le calcul de l'index
- friend class CBotLeftExpr;
- friend class CBotExprVar;
-
-public:
- CBotIndexExpr();
- ~CBotIndexExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-// une expression du genre
-// x = a;
-// x * y + 3;
-
-class CBotExpression : public CBotInstr
-{
-private:
- CBotLeftExpr* m_leftop; // élément de gauche
- CBotInstr* m_rightop; // élément de droite
-
-public:
- CBotExpression();
- ~CBotExpression();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotListExpression : public CBotInstr
-{
-private:
- CBotInstr* m_Expr; // la 1ère expression à évaluer
-
-public:
- CBotListExpression();
- ~CBotListExpression();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotLogicExpr : public CBotInstr
-{
-private:
- CBotInstr* m_condition; // test à évaluer
- CBotInstr* m_op1; // élément de gauche
- CBotInstr* m_op2; // élément de droite
- friend class CBotTwoOpExpr;
-
-public:
- CBotLogicExpr();
- ~CBotLogicExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-
-class CBotBoolExpr : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-
-
-// une expression éventuellement entre parenthèses ( ... )
-// il n'y a jamais d'instance de cette classe
-// l'objet retourné étant le contenu de la parenthése
-class CBotParExpr : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-// expression unaire
-class CBotExprUnaire : public CBotInstr
-{
-private:
- CBotInstr* m_Expr; // l'expression à évaluer
-public:
- CBotExprUnaire();
- ~CBotExprUnaire();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// toutes les opérations à 2 opérandes
-
-class CBotTwoOpExpr : public CBotInstr
-{
-private:
- CBotInstr* m_leftop; // élément de gauche
- CBotInstr* m_rightop; // élément de droite
-public:
- CBotTwoOpExpr();
- ~CBotTwoOpExpr();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = NULL);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-
-
-// un bloc d'instructions { .... }
-class CBotBlock : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true);
- static
- CBotInstr* CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal = false);
-};
-
-
-// le contenu d'un bloc d'instructions ... ; ... ; ... ; ... ;
-class CBotListInstr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr; // les instructions à faire
-
-public:
- CBotListInstr();
- ~CBotListInstr();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotInstrCall : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
-// int m_typeRes; // type du résultat
-// CBotString m_RetClassName; // class du résultat
- CBotTypResult
- m_typRes; // type complet du résultat
- long m_nFuncIdent; // id de la fonction
-
-public:
- CBotInstrCall();
- ~CBotInstrCall();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// un appel d'une méthode
-
-class CBotInstrMethode : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
-// int m_typeRes; // type du résultat
-// CBotString m_RetClassName; // class du résultat
- CBotTypResult
- m_typRes; // type complet du résultat
-
- CBotString m_NomMethod; // nom de la méthode
- long m_MethodeIdent; // identificateur de la méthode
-// long m_nThisIdent; // identificateur pour "this"
- CBotString m_ClassName; // nom de la classe
-
-public:
- CBotInstrMethode();
- ~CBotInstrMethode();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar);
- bool Execute(CBotStack* &pj);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-// expression for the variable name
-
-class CBotExprVar : public CBotInstr
-{
-private:
- long m_nIdent;
- friend class CBotPostIncExpr;
- friend class CBotPreIncExpr;
-
-public:
- CBotExprVar();
- ~CBotExprVar();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int privat=PR_PROTECT);
- static
- CBotInstr* CompileMethode(CBotToken* &p, CBotCStack* pStack);
-
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
- bool Execute2Var(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-class CBotPostIncExpr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr;
- friend class CBotParExpr;
-
-public:
- CBotPostIncExpr();
- ~CBotPostIncExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotPreIncExpr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr;
- friend class CBotParExpr;
-
-public:
- CBotPreIncExpr();
- ~CBotPreIncExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotLeftExprVar : public CBotInstr
-{
-private:
-public:
- CBotTypResult
- m_typevar; // type de variable déclarée
- long m_nIdent; // identificateur unique pour cette variable
-
-public:
- CBotLeftExprVar();
- ~CBotLeftExprVar();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotExprBool : public CBotInstr
-{
-private:
-
-public:
- CBotExprBool();
- ~CBotExprBool();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotExprNull : public CBotInstr
-{
-private:
-
-public:
- CBotExprNull();
- ~CBotExprNull();
-
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotExprNan : public CBotInstr
-{
-private:
-
-public:
- CBotExprNan();
- ~CBotExprNan();
-
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotNew : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
- long m_nMethodeIdent;
-// long m_nThisIdent;
- CBotToken m_vartoken;
-
-public:
- CBotNew();
- ~CBotNew();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// expression représentant un nombre
-
-class CBotExprNum : public CBotInstr
-{
-private:
- int m_numtype; // et le type de nombre
- long m_valint; // valeur pour un int
- float m_valfloat; // valeur pour un float
-
-public:
- CBotExprNum();
- ~CBotExprNum();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-
-// expression représentant une chaine de caractères
-
-class CBotExprAlpha : public CBotInstr
-{
-private:
-
-public:
- CBotExprAlpha();
- ~CBotExprAlpha();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-#define MAX(a,b) ((a>b) ? a : b)
-
-
-// classe pour la gestion des nombres entier (int)
-class CBotVarInt : public CBotVar
-{
-private:
- int m_val; // la valeur
- CBotString m_defnum; // le nom si donné par DefineNum
- friend class CBotVar;
-
-public:
- CBotVarInt( const CBotToken* name );
-// ~CBotVarInt();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
-
- void Add(CBotVar* left, CBotVar* right); // addition
- void Sub(CBotVar* left, CBotVar* right); // soustraction
- void Mul(CBotVar* left, CBotVar* right); // multiplication
- int Div(CBotVar* left, CBotVar* right); // division
- int Modulo(CBotVar* left, CBotVar* right); // reste de division
- void Power(CBotVar* left, CBotVar* right); // puissance
-
- bool Lo(CBotVar* left, CBotVar* right);
- bool Hi(CBotVar* left, CBotVar* right);
- bool Ls(CBotVar* left, CBotVar* right);
- bool Hs(CBotVar* left, CBotVar* right);
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- void XOr(CBotVar* left, CBotVar* right);
- void Or(CBotVar* left, CBotVar* right);
- void And(CBotVar* left, CBotVar* right);
-
- void SL(CBotVar* left, CBotVar* right);
- void SR(CBotVar* left, CBotVar* right);
- void ASR(CBotVar* left, CBotVar* right);
-
- void Neg();
- void Not();
- void Inc();
- void Dec();
-
- bool Save0State(FILE* pf);
- bool Save1State(FILE* pf);
-
-};
-
-// classe pour la gestion des nombres réels (float)
-class CBotVarFloat : public CBotVar
-{
-private:
- float m_val; // la valeur
-
-public:
- CBotVarFloat( const CBotToken* name );
-// ~CBotVarFloat();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
-
- void Add(CBotVar* left, CBotVar* right); // addition
- void Sub(CBotVar* left, CBotVar* right); // soustraction
- void Mul(CBotVar* left, CBotVar* right); // multiplication
- int Div(CBotVar* left, CBotVar* right); // division
- int Modulo(CBotVar* left, CBotVar* right); // reste de division
- void Power(CBotVar* left, CBotVar* right); // puissance
-
- bool Lo(CBotVar* left, CBotVar* right);
- bool Hi(CBotVar* left, CBotVar* right);
- bool Ls(CBotVar* left, CBotVar* right);
- bool Hs(CBotVar* left, CBotVar* right);
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- void Neg();
- void Inc();
- void Dec();
-
- bool Save1State(FILE* pf);
-};
-
-
-// classe pour la gestion des chaînes (String)
-class CBotVarString : public CBotVar
-{
-private:
- CBotString m_val; // la valeur
-
-public:
- CBotVarString( const CBotToken* name );
-// ~CBotVarString();
-
- void SetValString(const char* p);
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
- void Add(CBotVar* left, CBotVar* right); // addition
-
- bool Lo(CBotVar* left, CBotVar* right);
- bool Hi(CBotVar* left, CBotVar* right);
- bool Ls(CBotVar* left, CBotVar* right);
- bool Hs(CBotVar* left, CBotVar* right);
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- bool Save1State(FILE* pf);
-};
-
-// classe pour la gestion des boolean
-class CBotVarBoolean : public CBotVar
-{
-private:
- bool m_val; // la valeur
-
-public:
- CBotVarBoolean( const CBotToken* name );
-// ~CBotVarBoolean();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
- void And(CBotVar* left, CBotVar* right);
- void Or(CBotVar* left, CBotVar* right);
- void XOr(CBotVar* left, CBotVar* right);
- void Not();
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- bool Save1State(FILE* pf);
-};
-
-
-// classe pour la gestion des instances de classe
-class CBotVarClass : public CBotVar
-{
-private:
- static
- CBotVarClass* m_ExClass; // liste des instances existantes à un moment donné
- CBotVarClass* m_ExNext; // pour cette liste générale
- CBotVarClass* m_ExPrev; // pour cette liste générale
-
-private:
- CBotClass* m_pClass; // la définition de la classe
- CBotVarClass* m_pParent; // l'instance dans la classe parent
- CBotVar* m_pVar; // contenu
- friend class CBotVar; // mon papa est un copain
- friend class CBotVarPointer; // et le pointeur aussi
- int m_CptUse; // compteur d'utilisation
- long m_ItemIdent; // identificateur (unique) de l'instance
- bool m_bConstructor; // set si un constructeur a été appelé
-
-public:
- CBotVarClass( const CBotToken* name, const CBotTypResult& type );
-// CBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
- ~CBotVarClass();
-// void InitCBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
-
- void Copy(CBotVar* pSrc, bool bName=true);
- void SetClass(CBotClass* pClass); //, int &nIdent);
- CBotClass* GivClass();
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- CBotVar* GivItemRef(int nIdent);
-
- CBotVar* GivItem(int n, bool bExtend);
- CBotVar* GivItemList();
-
- CBotString GivValString();
-
- bool Save1State(FILE* pf);
- void Maj(void* pUser, bool bContinue);
-
- void IncrementUse(); // une référence en plus
- void DecrementUse(); // une référence en moins
-
- CBotVarClass*
- GivPointer();
- void SetItemList(CBotVar* pVar);
-
- void SetIdent(long n);
-
- static CBotVarClass* Find(long id);
-
-
-// CBotVar* GivMyThis();
-
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- void ConstructorSet();
-};
-
-
-// classe pour la gestion des pointeurs à une instances de classe
-class CBotVarPointer : public CBotVar
-{
-private:
- CBotVarClass*
- m_pVarClass; // contenu
- CBotClass* m_pClass; // la classe prévue pour ce pointeur
- friend class CBotVar; // mon papa est un copain
-
-public:
- CBotVarPointer( const CBotToken* name, CBotTypResult& type );
- ~CBotVarPointer();
-
- void Copy(CBotVar* pSrc, bool bName=true);
- void SetClass(CBotClass* pClass);
- CBotClass* GivClass();
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- CBotVar* GivItemRef(int nIdent);
- CBotVar* GivItemList();
-
- CBotString GivValString();
- void SetPointer(CBotVar* p);
- CBotVarClass*
- GivPointer();
-
- void SetIdent(long n); // associe un numéro d'identification (unique)
- long GivIdent(); // donne le numéro d'identification associé
- void ConstructorSet();
-
- bool Save1State(FILE* pf);
- void Maj(void* pUser, bool bContinue);
-
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-};
-
-
-// classe pour les tableaux
-
-#define MAXARRAYSIZE 9999
-
-class CBotVarArray : public CBotVar
-{
-private:
- CBotVarClass*
- m_pInstance; // instance gérant le tableau
-
- friend class CBotVar; // papa est un copain
-
-public:
- CBotVarArray( const CBotToken* name, CBotTypResult& type );
- ~CBotVarArray();
-
- void SetPointer(CBotVar* p);
- CBotVarClass*
- GivPointer();
-
- void Copy(CBotVar* pSrc, bool bName=true);
- CBotVar* GivItem(int n, bool bGrow=false); // rend un élément selon son index numérique
- // agrandi le tableau si nécessaire si bExtend
-// CBotVar* GivItem(const char* name); // rend un élément selon son index litéral
- CBotVar* GivItemList(); // donne le premier élément de la liste
-
- CBotString GivValString(); // donne le contenu du tableau dans une chaîne
-
- bool Save1State(FILE* pf);
-};
-
-
-extern CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars);
-
-extern bool TypeCompatible( CBotTypResult& type1, CBotTypResult& type2, int op = 0 );
-extern bool TypesCompatibles( const CBotTypResult& type1, const CBotTypResult& type2 );
-
-extern bool WriteWord(FILE* pf, unsigned short w);
-extern bool ReadWord(FILE* pf, unsigned short& w);
-extern bool ReadLong(FILE* pf, long& w);
-extern bool WriteFloat(FILE* pf, float w);
-extern bool WriteLong(FILE* pf, long w);
-extern bool ReadFloat(FILE* pf, float& w);
-extern bool WriteString(FILE* pf, CBotString s);
-extern bool ReadString(FILE* pf, CBotString& s);
-extern bool WriteType(FILE* pf, CBotTypResult type);
-extern bool ReadType(FILE* pf, CBotTypResult& type);
-
-extern float GivNumFloat( const char* p );
-
-#if false
-extern void DEBUG( const char* text, int val, CBotStack* pile );
-#endif
-
-///////////////////////////////////////////
-// classe pour les appels de routines (externes)
-
-class CBotCall
-{
-private:
- static
- CBotCall* m_ListCalls;
- static
- void* m_pUser;
- long m_nFuncIdent;
-
-private:
- CBotString m_name;
- bool (*m_rExec) (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser) ;
- CBotTypResult
- (*m_rComp) (CBotVar* &pVar, void* pUser) ;
- CBotCall* m_next;
-
-public:
- CBotCall(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
- ~CBotCall();
-
- static
- bool AddFunction(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
-
- static
- CBotTypResult
- CompileCall(CBotToken* &p, CBotVar** ppVars, CBotCStack* pStack, long& nIdent);
- static
- bool CheckCall(const char* name);
-
-// static
-// int DoCall(CBotToken* &p, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
- static
- int DoCall(long& nIdent, CBotToken* token, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
-#if STACKRUN
- bool Run(CBotStack* pStack);
- static
- bool RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack);
-#endif
-
- CBotString GivName();
- CBotCall* Next();
-
- static void SetPUser(void* pUser);
- static void Free();
-};
-
-// classe gérant les méthodes déclarées par AddFunction sur une classe
-
-class CBotCallMethode
-{
-private:
- CBotString m_name;
- bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception);
- CBotTypResult
- (*m_rComp) (CBotVar* pThis, CBotVar* &pVar);
- CBotCallMethode* m_next;
- friend class CBotClass;
- long m_nFuncIdent;
-
-public:
- CBotCallMethode(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
- ~CBotCallMethode();
-
- CBotTypResult
- CompileCall(const char* name, CBotVar* pThis,
- CBotVar** ppVars, CBotCStack* pStack,
- long& nIdent);
-
- int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pFunc);
-
- CBotString GivName();
- CBotCallMethode* Next();
- void AddNext(CBotCallMethode* p);
-
-};
-
-// une liste de paramètres
-
-class CBotDefParam
-{
-private:
- CBotToken m_token; // nom du paramètre
- CBotString m_typename; // nom du type
- CBotTypResult m_type; // type de paramètre
- CBotDefParam* m_next; // paramètre suivant
- long m_nIdent;
-
-public:
- CBotDefParam();
- ~CBotDefParam();
- static
- CBotDefParam* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotVar** ppVars, CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-
- void AddNext(CBotDefParam* p);
- int GivType();
- CBotTypResult GivTypResult();
- CBotDefParam* GivNext();
-
- CBotString GivParamString();
-};
-
-
-// une déclaration de fonction
-
-class CBotFunction : CBotInstr
-{
-private:
- // gestion d'une liste (static) de fonctions publiques
- static
- CBotFunction* m_listPublic;
- CBotFunction* m_nextpublic;
- CBotFunction* m_prevpublic;
- friend class CBotCStack;
-// long m_nThisIdent;
- long m_nFuncIdent;
- bool m_bSynchro; // méthode synchronisée ?
-
-private:
- CBotDefParam* m_Param; // liste des paramètres
- CBotInstr* m_Block; // le bloc d'instructions
- CBotFunction* m_next;
- CBotToken m_retToken; // si retourne un CBotTypClass
- CBotTypResult m_retTyp; // type complet du résultat
-
- bool m_bPublic; // fonction publique
- bool m_bExtern; // fonction extern
- CBotString m_MasterClass; // nom de la classe qu'on dérive
- CBotProgram* m_pProg;
- friend class CBotProgram;
- friend class CBotClass;
-
- CBotToken m_extern; // pour la position du mot "extern"
- CBotToken m_openpar;
- CBotToken m_closepar;
- CBotToken m_openblk;
- CBotToken m_closeblk;
-public:
- CBotFunction();
- ~CBotFunction();
- static
- CBotFunction* Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* pFunc, bool bLocal = true);
- static
- CBotFunction* Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass);
- bool Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
- void RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
-
- void AddNext(CBotFunction* p);
- CBotTypResult CompileCall(const char* name, CBotVar** ppVars, long& nIdent);
- CBotFunction* FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic = true);
-
- int DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken);
- void RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack);
- int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass);
- void RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass);
- bool CheckParam(CBotDefParam* pParam);
-
- static
- void AddPublic(CBotFunction* pfunc);
-
- CBotString GivName();
- CBotString GivParams();
- bool IsPublic();
- bool IsExtern();
- CBotFunction* Next();
-
- bool GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop);
-};
-
-
+// * 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/. +//////////////////////////////////////////////////////////////////// +/** + * \file CBot.h + * \brief Interpreter of the language CBot for COLOBOT game + */ + +#pragma once + +#include "resource.h" +#include "CBotDll.h" // public definitions +#include "CBotToken.h" // token management + +#define STACKRUN true /// \def return execution directly on a suspended routine +#define STACKMEM true /// \def preserve memory for the execution stack +#define MAXSTACK 990 /// \def stack size reserved + +#define EOX (CBotStack*)-1 /// \def tag special condition + + +// fix for MSVC instruction __asm int 3 (setting a trap) +#if defined(__MINGW32__) || defined(__GNUC__) +#define ASM_TRAP() asm("int $3"); +#else +#define ASM_TRAP() __asm int 3; +#endif + +///////////////////////////////////////////////////////////////////// +// forward declaration + +class CBotCompExpr; // an expression like + // () <= () +class CBotAddExpr; // an expression like + // () + () +class CBotParExpr; // basic type or instruction in parenthesis + // Toto.truc + // 12.5 + // "string" + // ( expression ) +class CBotExprVar; // a variable name as + // Toto + // chose.truc.machin +class CBotWhile; // while (...) {...}; +class CBotIf; // if (...) {...} else {...} +class CBotDefParam; // paramerer list of a function +class CBotRepeat; // repeat (nb) {...} + + + +//////////////////////////////////////////////////////////////////////// +// Management of the execution stack +//////////////////////////////////////////////////////////////////////// + +// actually, externally, the only thing it can do +// is to create an instance of a stack +// to use for routine CBotProgram :: Execute (CBotStack) + + +/**\class CBotStack + * \brief Management of the execution stack. + * \brief Actually the only thing it can do is to create an instance of a stack + * \brief to use for routine CBotProgram :: Execute(CBotStack)*/ +class CBotStack +{ +public: +#if STACKMEM + /** + * \brief FirstStack Allocate first stack + * \return pointer to created stack + */ + static CBotStack * FirstStack(); + + /** \brief Delete Remove current stack */ + void Delete(); +#endif + + /** + * \brief CBotStack Constructor of the stack + * \param ppapa Not used. + */ + CBotStack(CBotStack* ppapa); + + + /** \brief ~CBotStack Destructor */ + ~CBotStack(); + + /** + * \brief StackOver Check if end of stack is reached + * \return true if end of stack + */ + bool StackOver(); + + /** + * \brief GivError Get error number of the stack + * \param [out] start beginning of the stack + * \param [out] end end of stack + * \return error number + */ + int GivError(int& start, int& end); + + /** + * \brief GivError Get error number + * \return eror number + */ + int GivError();// rend le numéro d'erreur retourné + + /** + * \brief Reset Reset error at and set user + * \param [in] pUser User of stack + */ + void Reset(void* pUser); + + /** + * \brief SetType Determines the type. + * \param type Type of instruction on the stack. + */ + void SetType(CBotTypResult& type); + + /** + * \brief GivType Get the type of value on the stack. + * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic). + * \return Type number. + */ + int GivType(int mode = 0); + + /** + * \brief Gives the type of complete value on the stack. + * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic). + * \return Type of an element. + */ + CBotTypResult GivTypResult(int mode = 0); + + /** + * \brief Adds a local variable. + * \param [in] p Variable to be added. + */ + void AddVar(CBotVar* p); + + /** + * \brief Fetch a variable by its token. + * \brief This may be a composite variable + * \param [in] pToken Token upon which search is performed + * \param [in] bUpdate Not used. Probably need to be removed + * \param [in] bModif Not used. Probably need to be removed + * \return Found variable + */ + CBotVar* FindVar(CBotToken* &pToken, bool bUpdate = false, + bool bModif = false); + + /** + * \brief Fetch a variable by its token. + * \brief This may be a composite variable + * \param [in] pToken Token upon which search is performed + * \param [in] bUpdate Not used. Probably need to be removed + * \param [in] bModif Not used. Probably need to be removed + * \return Found variable + */ + CBotVar* FindVar(CBotToken& Token, bool bUpdate = false, + bool bModif = false); + + /** + * \brief Fetch variable by its name + * \param [in] name Name of variable to find + * \return Found variable + */ + CBotVar* FindVar(const char* name); + + /** + * \brief Fetch a variable on the stack according to its identification number + * \brief This is faster than comparing names + * \param [in] ident Identifier of a variable + * \param [in] bUpdate Not used. Probably need to be removed + * \param [in] bModif Not used. Probably need to be removed + * \return Found variable + */ + CBotVar* FindVar(long ident, bool bUpdate = false, + bool bModif = false); + + /** + * \brief Find variable by its token and returns a copy of it. + * \param Token Token upon which search is performed + * \param bUpdate Not used. + * \return Found variable, NULL if not found + */ + CBotVar* CopyVar(CBotToken& Token, bool bUpdate = false); + + + CBotStack* AddStack(CBotInstr* instr = NULL, bool bBlock = false); // extends the stack + CBotStack* AddStackEOX(CBotCall* instr = NULL, bool bBlock = false); // extends the stack + CBotStack* RestoreStack(CBotInstr* instr = NULL); + CBotStack* RestoreStackEOX(CBotCall* instr = NULL); + + CBotStack* AddStack2(bool bBlock = false); // extends the stack + bool Return(CBotStack* pFils); // transmits the result over + bool ReturnKeep(CBotStack* pFils); // transmits the result without reducing the stack + bool BreakReturn(CBotStack* pfils, const char* name = NULL); + // in case of eventual break + bool IfContinue(int state, const char* name); + // or "continue" + + bool IsOk(); + + bool SetState(int n, int lim = -10); // select a state + int GivState(); // in what state am I? + bool IncState(int lim = -10); // passes to the next state + bool IfStep(); // do step by step + bool Execute(); + + void SetVar( CBotVar* var ); + void SetCopyVar( CBotVar* var ); + CBotVar* GivVar(); + CBotVar* GivCopyVar(); + CBotVar* GivPtVar(); + bool GivRetVar(bool bRet); + long GivVal(); + + void SetStartError(int pos); + void SetError(int n, CBotToken* token = NULL); + void SetPosError(CBotToken* token); + void ResetError(int n, int start, int end); + void SetBreak(int val, const char* name); + + void SetBotCall(CBotProgram* p); + CBotProgram* GivBotCall(bool bFirst = false); + void* GivPUser(); + bool GivBlock(); + + + bool ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype); + void RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar); + + bool SaveState(FILE* pf); + bool RestoreState(FILE* pf, CBotStack* &pStack); + + static + void SetTimer(int n); + + void GetRunPos(const char* &FunctionName, int &start, int &end); + CBotVar* GivStackVars(const char* &FunctionName, int level); + + int m_temp; + +private: + CBotStack* m_next; + CBotStack* m_next2; + CBotStack* m_prev; + friend class CBotInstArray; + +#ifdef _DEBUG + int m_index; +#endif + int m_state; + int m_step; + static int m_error; + static int m_start; + static int m_end; + static + CBotVar* m_retvar; // result of a return + + CBotVar* m_var; // result of the operations + CBotVar* m_listVar; // variables declared at this level + + bool m_bBlock; // is part of a block (variables are local to this block) + bool m_bOver; // stack limits? +// bool m_bDontDelete; // special, not to destroy the variable during delete + CBotProgram* m_prog; // user-defined functions + + static + int m_initimer; + static + int m_timer; + static + CBotString m_labelBreak; + static + void* m_pUser; + + CBotInstr* m_instr; // the corresponding instruction + bool m_bFunc; // an input of a function? + CBotCall* m_call; // recovery point in a extern call + friend class CBotTry; +}; + +// inline routinees must be declared in file.h + +inline bool CBotStack::IsOk() +{ + return (m_error == 0); +} + +inline int CBotStack::GivState() +{ + return m_state; +} + +inline int CBotStack::GivError() +{ + return m_error; +} + +//////////////////////////////////////////////////////////////////////// +// Management of the stack of compilation +//////////////////////////////////////////////////////////////////////// + + +class CBotCStack +{ +private: + CBotCStack* m_next; + CBotCStack* m_prev; + + static int m_error; + static int m_end; + int m_start; + + CBotVar* m_var; // result of the operations + + bool m_bBlock; // is part of a block (variables are local to this block) + CBotVar* m_listVar; + + static + CBotProgram* m_prog; // list of compiled functions + static + CBotTypResult m_retTyp; +// static +// CBotToken* m_retClass; + +public: + CBotCStack(CBotCStack* ppapa); + ~CBotCStack(); + + bool IsOk(); + int GivError(); + int GivError(int& start, int& end); + // gives error number + + void SetType(CBotTypResult& type);// determines the type + CBotTypResult GivTypResult(int mode = 0); // gives the type of value on the stack + int GivType(int mode = 0); // gives the type of value on the stack + CBotClass* GivClass(); // gives the class of the value on the stack + + void AddVar(CBotVar* p); // adds a local variable + CBotVar* FindVar(CBotToken* &p); // finds a variable + CBotVar* FindVar(CBotToken& Token); + bool CheckVarLocal(CBotToken* &pToken); + CBotVar* CopyVar(CBotToken& Token); // finds and makes a copy + + CBotCStack* TokenStack(CBotToken* pToken = NULL, bool bBlock = false); + CBotInstr* Return(CBotInstr* p, CBotCStack* pParent); // transmits the result upper + CBotFunction* ReturnFunc(CBotFunction* p, CBotCStack* pParent); // transmits the result upper + + void SetVar( CBotVar* var ); + void SetCopyVar( CBotVar* var ); + CBotVar* GivVar(); + + void SetStartError(int pos); + void SetError(int n, int pos); + void SetError(int n, CBotToken* p); + void ResetError(int n, int start, int end); + + void SetRetType(CBotTypResult& type); + CBotTypResult GivRetType(); + +// void SetBotCall(CBotFunction* &pFunc); + void SetBotCall(CBotProgram* p); + CBotProgram* GivBotCall(); + CBotTypResult CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent); + bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam); + + bool NextToken(CBotToken* &p); +}; + + +extern bool SaveVar(FILE* pf, CBotVar* pVar); + + +///////////////////////////////////////////////////////////////////// +// class defining an instruction +class CBotInstr +{ +private: + static + CBotStringArray + m_labelLvl; +protected: + CBotToken m_token; // keeps the token + CBotString name; // debug + CBotInstr* m_next; // linked command + CBotInstr* m_next2b; // second list definition chain + CBotInstr* m_next3; // third list for indices and fields + CBotInstr* m_next3b; // necessary for reporting tables +/* + for example, the following program + int x[]; x[1] = 4; + int y[x[1]][10], z; + is generated + CBotInstrArray + m_next3b-> CBotEmpty + m_next-> + CBotExpression .... + m_next-> + CBotInstrArray + m_next3b-> CBotExpression ('x') ( m_next3-> CBotIndexExpr ('1') ) + m_next3b-> CBotExpression ('10') + m_next2-> 'z' + m_next->... + +*/ + + static + int m_LoopLvl; + friend class CBotClassInst; + friend class CBotInt; + friend class CBotListArray; + +public: + CBotInstr(); + virtual + ~CBotInstr(); + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + static + CBotInstr* CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first = true); + + virtual + bool Execute(CBotStack* &pj); + virtual + bool Execute(CBotStack* &pj, CBotVar* pVar); + virtual + void RestoreState(CBotStack* &pj, bool bMain); + + virtual + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + virtual + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend); + virtual + void RestoreStateVar(CBotStack* &pile, bool bMain); + + virtual + bool CompCase(CBotStack* &pj, int val); + + void SetToken(CBotToken* p); + int GivTokenType(); + CBotToken* GivToken(); + + void AddNext(CBotInstr* n); + CBotInstr* GivNext(); + void AddNext3(CBotInstr* n); + CBotInstr* GivNext3(); + void AddNext3b(CBotInstr* n); + CBotInstr* GivNext3b(); + + static + void IncLvl(CBotString& label); + static + void IncLvl(); + static + void DecLvl(); + static + bool ChkLvl(const CBotString& label, int type); + + bool IsOfClass(CBotString name); +}; + +class CBotWhile : public CBotInstr +{ +private: + CBotInstr* m_Condition; // condition + CBotInstr* m_Block; // instructions + CBotString m_label; // a label if there is + +public: + CBotWhile(); + ~CBotWhile(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotRepeat : public CBotInstr +{ +private: + /// Number of iterations + CBotInstr* m_NbIter; + + /// Instructions + CBotInstr* m_Block; + + /// Label + CBotString m_label; // a label if there is + +public: + CBotRepeat(); + ~CBotRepeat(); + + /// Static method used for compilation + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + + /// Execute + bool Execute(CBotStack* &pj); + + /// Restore state + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotDo : public CBotInstr +{ +private: + CBotInstr* m_Block; // instruction + CBotInstr* m_Condition; // conditions + CBotString m_label; // a label if there is + +public: + CBotDo(); + ~CBotDo(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotFor : public CBotInstr +{ +private: + CBotInstr* m_Init; // initial intruction + CBotInstr* m_Test; // test condition + CBotInstr* m_Incr; // instruction for increment + CBotInstr* m_Block; // instructions + CBotString m_label; // a label if there is + +public: + CBotFor(); + ~CBotFor(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotBreak : public CBotInstr +{ +private: + CBotString m_label; // a label if there is + +public: + CBotBreak(); + ~CBotBreak(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotReturn : public CBotInstr +{ +private: + CBotInstr* m_Instr; // paramter of return + +public: + CBotReturn(); + ~CBotReturn(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotSwitch : public CBotInstr +{ +private: + CBotInstr* m_Value; // value to seek + CBotInstr* m_Block; // instructions + +public: + CBotSwitch(); + ~CBotSwitch(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotCase : public CBotInstr +{ +private: + CBotInstr* m_Value; // value to compare + +public: + CBotCase(); + ~CBotCase(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + bool CompCase(CBotStack* &pj, int val); +}; + +class CBotCatch : public CBotInstr +{ +private: + CBotInstr* m_Block; // instructions + CBotInstr* m_Cond; //condition + CBotCatch* m_next; //following catch + friend class CBotTry; + +public: + CBotCatch(); + ~CBotCatch(); + static + CBotCatch* Compile(CBotToken* &p, CBotCStack* pStack); + bool TestCatch(CBotStack* &pj, int val); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + void RestoreCondState(CBotStack* &pj, bool bMain); +}; + +class CBotTry : public CBotInstr +{ +private: + CBotInstr* m_Block; // instructions + CBotCatch* m_ListCatch; // catches + CBotInstr* m_FinalInst; // final instruction + +public: + CBotTry(); + ~CBotTry(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotThrow : public CBotInstr +{ +private: + CBotInstr* m_Value; // the value to send + +public: + CBotThrow(); + ~CBotThrow(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotStartDebugDD : public CBotInstr +{ +private: + +public: + CBotStartDebugDD(); + ~CBotStartDebugDD(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); +}; + + +class CBotIf : public CBotInstr +{ +private: + CBotInstr* m_Condition; // condition + CBotInstr* m_Block; // instructions + CBotInstr* m_BlockElse; // instructions + +public: + CBotIf(); + ~CBotIf(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +// definition of an integer + +class CBotInt : public CBotInstr +{ +private: + CBotInstr* m_var; // the variable to initialize + CBotInstr* m_expr; // a value to put, if there is +/// CBotInstr* m_next; // several definitions chained + +public: + CBotInt(); + ~CBotInt(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// definition of an array + +class CBotInstArray : public CBotInstr +{ +private: + CBotInstr* m_var; // the variables to initialize + CBotInstr* m_listass; // list of assignments for array + CBotTypResult + m_typevar; // type of elements +// CBotString m_ClassName; + +public: + CBotInstArray(); + ~CBotInstArray(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +// definition of a assignment list for a table +// int [ ] a [ ] = ( ( 1, 2, 3 ) , ( 3, 2, 1 ) ) ; + +class CBotListArray : public CBotInstr +{ +private: + CBotInstr* m_expr; // an expression for an element + // others are linked with CBotInstr :: m_next3; +public: + CBotListArray(); + ~CBotListArray(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type); + bool Execute(CBotStack* &pj, CBotVar* pVar); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotEmpty : public CBotInstr +{ + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// defininition of a boolean + +class CBotBoolean : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotInstr* m_expr; // a value to put, if there is + +public: + CBotBoolean(); + ~CBotBoolean(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +// definition of a real number + +class CBotFloat : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotInstr* m_expr; // a value to put, if there is + +public: + CBotFloat(); + ~CBotFloat(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// definition of an element string + +class CBotIString : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotInstr* m_expr; // a value to put, if there is + +public: + CBotIString(); + ~CBotIString(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// definition of an element of any class + +class CBotClassInst : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotClass* m_pClass; // reference to the class + CBotInstr* m_Parameters; // parameters to be evaluated for the contructor + CBotInstr* m_expr; // a value to put, if there is + bool m_hasParams; // has it parameters? + long m_nMethodeIdent; + +public: + CBotClassInst(); + ~CBotClassInst(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass = NULL); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotCondition : public CBotInstr +{ +private: + +public: + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); +}; + + +// left operand +// accept the expressions that be to the left of assignment + +class CBotLeftExpr : public CBotInstr +{ +private: + long m_nIdent; + +public: + CBotLeftExpr(); + ~CBotLeftExpr(); + static + CBotLeftExpr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack, CBotStack* array); + + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep); + void RestoreStateVar(CBotStack* &pile, bool bMain); +}; + + +// management of the fields of an instance + +class CBotFieldExpr : public CBotInstr +{ +private: + friend class CBotExpression; + int m_nIdent; + +public: + CBotFieldExpr(); + ~CBotFieldExpr(); + void SetUniqNum(int num); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +// management of indices of the tables + +class CBotIndexExpr : public CBotInstr +{ +private: + CBotInstr* m_expr; // expression for calculating the index + friend class CBotLeftExpr; + friend class CBotExprVar; + +public: + CBotIndexExpr(); + ~CBotIndexExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +// expressions like +// x = a; +// x * y + 3; + +class CBotExpression : public CBotInstr +{ +private: + CBotLeftExpr* m_leftop; // left operand + CBotInstr* m_rightop; // right operant + +public: + CBotExpression(); + ~CBotExpression(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotListExpression : public CBotInstr +{ +private: + CBotInstr* m_Expr; // the first expression to be evaluated + +public: + CBotListExpression(); + ~CBotListExpression(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotLogicExpr : public CBotInstr +{ +private: + CBotInstr* m_condition; // test to evaluate + CBotInstr* m_op1; // left element + CBotInstr* m_op2; // right element + friend class CBotTwoOpExpr; + +public: + CBotLogicExpr(); + ~CBotLogicExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + + +class CBotBoolExpr : public CBotInstr +{ +private: + +public: + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); +}; + + + +// possibly an expression in parentheses ( ... ) +// there is never an instance of this class +// being the object returned inside the parenthesis +class CBotParExpr : public CBotInstr +{ +private: + +public: + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); +}; + +// unary expression +class CBotExprUnaire : public CBotInstr +{ +private: + CBotInstr* m_Expr; // expression to be evaluated +public: + CBotExprUnaire(); + ~CBotExprUnaire(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// all operations with two operands + +class CBotTwoOpExpr : public CBotInstr +{ +private: + CBotInstr* m_leftop; // left element + CBotInstr* m_rightop; // right element +public: + CBotTwoOpExpr(); + ~CBotTwoOpExpr(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = NULL); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + + + +// an instruction block { .... } +class CBotBlock : public CBotInstr +{ +private: + +public: + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true); + static + CBotInstr* CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal = false); +}; + + +// the content of a block of instructions ... ; ... ; ... ; ... ; +class CBotListInstr : public CBotInstr +{ +private: + CBotInstr* m_Instr; // instructions to do + +public: + CBotListInstr(); + ~CBotListInstr(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotInstrCall : public CBotInstr +{ +private: + CBotInstr* m_Parameters; // the parameters to be evaluated +// int m_typeRes; // type of the result +// CBotString m_RetClassName; // class of the result + CBotTypResult + m_typRes; // complete type of the result + long m_nFuncIdent; // id of a function + +public: + CBotInstrCall(); + ~CBotInstrCall(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// a call of method + +class CBotInstrMethode : public CBotInstr +{ +private: + CBotInstr* m_Parameters; // the parameters to be evaluated +// int m_typeRes; // type of the result +// CBotString m_RetClassName; // class of the result + CBotTypResult + m_typRes; // complete type of the result + + CBotString m_NomMethod; // name of the method + long m_MethodeIdent; // identifier of the method +// long m_nThisIdent; // identifier for "this" + CBotString m_ClassName; // name of the class + +public: + CBotInstrMethode(); + ~CBotInstrMethode(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar); + bool Execute(CBotStack* &pj); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +// expression for the variable name + +class CBotExprVar : public CBotInstr +{ +private: + long m_nIdent; + friend class CBotPostIncExpr; + friend class CBotPreIncExpr; + +public: + CBotExprVar(); + ~CBotExprVar(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int privat=PR_PROTECT); + static + CBotInstr* CompileMethode(CBotToken* &p, CBotCStack* pStack); + + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep); + bool Execute2Var(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +class CBotPostIncExpr : public CBotInstr +{ +private: + CBotInstr* m_Instr; + friend class CBotParExpr; + +public: + CBotPostIncExpr(); + ~CBotPostIncExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotPreIncExpr : public CBotInstr +{ +private: + CBotInstr* m_Instr; + friend class CBotParExpr; + +public: + CBotPreIncExpr(); + ~CBotPreIncExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotLeftExprVar : public CBotInstr +{ +private: +public: + CBotTypResult + m_typevar; // type of variable declared + long m_nIdent; // unique identifier for that variable + +public: + CBotLeftExprVar(); + ~CBotLeftExprVar(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotExprBool : public CBotInstr +{ +private: + +public: + CBotExprBool(); + ~CBotExprBool(); + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotExprNull : public CBotInstr +{ +private: + +public: + CBotExprNull(); + ~CBotExprNull(); + + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotExprNan : public CBotInstr +{ +private: + +public: + CBotExprNan(); + ~CBotExprNan(); + + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotNew : public CBotInstr +{ +private: + CBotInstr* m_Parameters; // the parameters to be evaluated + long m_nMethodeIdent; +// long m_nThisIdent; + CBotToken m_vartoken; + +public: + CBotNew(); + ~CBotNew(); + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// expression representing a number + +class CBotExprNum : public CBotInstr +{ +private: + int m_numtype; // et the type of number + long m_valint; // value for an int + float m_valfloat; // value for a float + +public: + CBotExprNum(); + ~CBotExprNum(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + + +// expression representing a string + +class CBotExprAlpha : public CBotInstr +{ +private: + +public: + CBotExprAlpha(); + ~CBotExprAlpha(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +#define MAX(a,b) ((a>b) ? a : b) + + +// class for the management of integer numbers (int) +class CBotVarInt : public CBotVar +{ +private: + int m_val; // the value + CBotString m_defnum; // the name if given by DefineNum + friend class CBotVar; + +public: + CBotVarInt( const CBotToken* name ); +// ~CBotVarInt(); + + void SetValInt(int val, const char* s = NULL); + void SetValFloat(float val); + int GivValInt(); + float GivValFloat(); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + + void Add(CBotVar* left, CBotVar* right); // addition + void Sub(CBotVar* left, CBotVar* right); // substraction + void Mul(CBotVar* left, CBotVar* right); // multiplication + int Div(CBotVar* left, CBotVar* right); // division + int Modulo(CBotVar* left, CBotVar* right); // remainder of division + void Power(CBotVar* left, CBotVar* right); // power + + bool Lo(CBotVar* left, CBotVar* right); + bool Hi(CBotVar* left, CBotVar* right); + bool Ls(CBotVar* left, CBotVar* right); + bool Hs(CBotVar* left, CBotVar* right); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + void XOr(CBotVar* left, CBotVar* right); + void Or(CBotVar* left, CBotVar* right); + void And(CBotVar* left, CBotVar* right); + + void SL(CBotVar* left, CBotVar* right); + void SR(CBotVar* left, CBotVar* right); + void ASR(CBotVar* left, CBotVar* right); + + void Neg(); + void Not(); + void Inc(); + void Dec(); + + bool Save0State(FILE* pf); + bool Save1State(FILE* pf); + +}; + +// Class for managing real numbers (float) +class CBotVarFloat : public CBotVar +{ +private: + float m_val; // the value + +public: + CBotVarFloat( const CBotToken* name ); +// ~CBotVarFloat(); + + void SetValInt(int val, const char* s = NULL); + void SetValFloat(float val); + int GivValInt(); + float GivValFloat(); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + + void Add(CBotVar* left, CBotVar* right); // addition + void Sub(CBotVar* left, CBotVar* right); // substraction + void Mul(CBotVar* left, CBotVar* right); // multiplication + int Div(CBotVar* left, CBotVar* right); // division + int Modulo(CBotVar* left, CBotVar* right); // remainder of division + void Power(CBotVar* left, CBotVar* right); // power + + bool Lo(CBotVar* left, CBotVar* right); + bool Hi(CBotVar* left, CBotVar* right); + bool Ls(CBotVar* left, CBotVar* right); + bool Hs(CBotVar* left, CBotVar* right); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + void Neg(); + void Inc(); + void Dec(); + + bool Save1State(FILE* pf); +}; + + +// class for management of strings (String) +class CBotVarString : public CBotVar +{ +private: + CBotString m_val; // the value + +public: + CBotVarString( const CBotToken* name ); +// ~CBotVarString(); + + void SetValString(const char* p); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + void Add(CBotVar* left, CBotVar* right); // addition + + bool Lo(CBotVar* left, CBotVar* right); + bool Hi(CBotVar* left, CBotVar* right); + bool Ls(CBotVar* left, CBotVar* right); + bool Hs(CBotVar* left, CBotVar* right); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + bool Save1State(FILE* pf); +}; + +// class for the management of boolean +class CBotVarBoolean : public CBotVar +{ +private: + bool m_val; // the value + +public: + CBotVarBoolean( const CBotToken* name ); +// ~CBotVarBoolean(); + + void SetValInt(int val, const char* s = NULL); + void SetValFloat(float val); + int GivValInt(); + float GivValFloat(); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + void And(CBotVar* left, CBotVar* right); + void Or(CBotVar* left, CBotVar* right); + void XOr(CBotVar* left, CBotVar* right); + void Not(); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + bool Save1State(FILE* pf); +}; + + +// class management class instances +class CBotVarClass : public CBotVar +{ +private: + static + CBotVarClass* m_ExClass; // list of existing instances at some point + CBotVarClass* m_ExNext; // for this general list + CBotVarClass* m_ExPrev; // for this general list + +private: + CBotClass* m_pClass; // the class definition + CBotVarClass* m_pParent; // the instance of a parent class + CBotVar* m_pVar; // contents + friend class CBotVar; // my daddy is a buddy WHAT? :D(\TODO mon papa est un copain ) + friend class CBotVarPointer; // and also the pointer + int m_CptUse; // counter usage + long m_ItemIdent; // identifier (unique) of an instance + bool m_bConstructor; // set if a constructor has been called + +public: + CBotVarClass( const CBotToken* name, const CBotTypResult& type ); +// CBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent ); + ~CBotVarClass(); +// void InitCBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent ); + + void Copy(CBotVar* pSrc, bool bName=true); + void SetClass(CBotClass* pClass); //, int &nIdent); + CBotClass* GivClass(); + CBotVar* GivItem(const char* name); // return an element of a class according to its name (*) + CBotVar* GivItemRef(int nIdent); + + CBotVar* GivItem(int n, bool bExtend); + CBotVar* GivItemList(); + + CBotString GivValString(); + + bool Save1State(FILE* pf); + void Maj(void* pUser, bool bContinue); + + void IncrementUse(); // a reference to incrementation + void DecrementUse(); // a reference to decrementation + + CBotVarClass* + GivPointer(); + void SetItemList(CBotVar* pVar); + + void SetIdent(long n); + + static CBotVarClass* Find(long id); + + +// CBotVar* GivMyThis(); + + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + void ConstructorSet(); +}; + + +// class for the management of pointers to a class instances +class CBotVarPointer : public CBotVar +{ +private: + CBotVarClass* + m_pVarClass; // contents + CBotClass* m_pClass; // class provided for this pointer + friend class CBotVar; // my daddy is a buddy + +public: + CBotVarPointer( const CBotToken* name, CBotTypResult& type ); + ~CBotVarPointer(); + + void Copy(CBotVar* pSrc, bool bName=true); + void SetClass(CBotClass* pClass); + CBotClass* GivClass(); + CBotVar* GivItem(const char* name); // return an element of a class according to its name (*) + CBotVar* GivItemRef(int nIdent); + CBotVar* GivItemList(); + + CBotString GivValString(); + void SetPointer(CBotVar* p); + CBotVarClass* + GivPointer(); + + void SetIdent(long n); // associates an identification number (unique) + long GivIdent(); // gives the identification number associated with + void ConstructorSet(); + + bool Save1State(FILE* pf); + void Maj(void* pUser, bool bContinue); + + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); +}; + + +// classe pour les tableaux + +#define MAXARRAYSIZE 9999 + +class CBotVarArray : public CBotVar +{ +private: + CBotVarClass* + m_pInstance; // instance manager of table + + friend class CBotVar; // my daddy is a buddy + +public: + CBotVarArray( const CBotToken* name, CBotTypResult& type ); + ~CBotVarArray(); + + void SetPointer(CBotVar* p); + CBotVarClass* + GivPointer(); + + void Copy(CBotVar* pSrc, bool bName=true); + CBotVar* GivItem(int n, bool bGrow=false); // makes an element according to its numeric index + // enlarged the table if necessary if bExtend +// CBotVar* GivItem(const char* name); // makes a element by literal index + CBotVar* GivItemList(); // gives the first item in the list + + CBotString GivValString(); // gets the contents of the array into a string + + bool Save1State(FILE* pf); +}; + + +extern CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars); + +extern bool TypeCompatible( CBotTypResult& type1, CBotTypResult& type2, int op = 0 ); +extern bool TypesCompatibles( const CBotTypResult& type1, const CBotTypResult& type2 ); + +extern bool WriteWord(FILE* pf, unsigned short w); +extern bool ReadWord(FILE* pf, unsigned short& w); +extern bool ReadLong(FILE* pf, long& w); +extern bool WriteFloat(FILE* pf, float w); +extern bool WriteLong(FILE* pf, long w); +extern bool ReadFloat(FILE* pf, float& w); +extern bool WriteString(FILE* pf, CBotString s); +extern bool ReadString(FILE* pf, CBotString& s); +extern bool WriteType(FILE* pf, CBotTypResult type); +extern bool ReadType(FILE* pf, CBotTypResult& type); + +extern float GivNumFloat( const char* p ); + +#if false +extern void DEBUG( const char* text, int val, CBotStack* pile ); +#endif + +/////////////////////////////////////////// +// class for routine calls (external) + +class CBotCall +{ +private: + static + CBotCall* m_ListCalls; + static + void* m_pUser; + long m_nFuncIdent; + +private: + CBotString m_name; + bool (*m_rExec) (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser) ; + CBotTypResult + (*m_rComp) (CBotVar* &pVar, void* pUser) ; + CBotCall* m_next; + +public: + CBotCall(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)); + ~CBotCall(); + + static + bool AddFunction(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)); + + static + CBotTypResult + CompileCall(CBotToken* &p, CBotVar** ppVars, CBotCStack* pStack, long& nIdent); + static + bool CheckCall(const char* name); + +// static +// int DoCall(CBotToken* &p, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype); + static + int DoCall(long& nIdent, CBotToken* token, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype); +#if STACKRUN + bool Run(CBotStack* pStack); + static + bool RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack); +#endif + + CBotString GivName(); + CBotCall* Next(); + + static void SetPUser(void* pUser); + static void Free(); +}; + +// class managing the methods declared by AddFunction on a class + +class CBotCallMethode +{ +private: + CBotString m_name; + bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception); + CBotTypResult + (*m_rComp) (CBotVar* pThis, CBotVar* &pVar); + CBotCallMethode* m_next; + friend class CBotClass; + long m_nFuncIdent; + +public: + CBotCallMethode(const char* name, + bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception), + CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar)); + ~CBotCallMethode(); + + CBotTypResult + CompileCall(const char* name, CBotVar* pThis, + CBotVar** ppVars, CBotCStack* pStack, + long& nIdent); + + int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pFunc); + + CBotString GivName(); + CBotCallMethode* Next(); + void AddNext(CBotCallMethode* p); + +}; + +// a list of parameters + +class CBotDefParam +{ +private: + CBotToken m_token; // name of the parameter + CBotString m_typename; // type name + CBotTypResult m_type; // type of paramteter + CBotDefParam* m_next; // next parameter + long m_nIdent; + +public: + CBotDefParam(); + ~CBotDefParam(); + static + CBotDefParam* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotVar** ppVars, CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + + void AddNext(CBotDefParam* p); + int GivType(); + CBotTypResult GivTypResult(); + CBotDefParam* GivNext(); + + CBotString GivParamString(); +}; + + +// a function declaration + +class CBotFunction : CBotInstr +{ +private: + // management of list of (static) public functions + static + CBotFunction* m_listPublic; + CBotFunction* m_nextpublic; + CBotFunction* m_prevpublic; + friend class CBotCStack; +// long m_nThisIdent; + long m_nFuncIdent; + bool m_bSynchro; // synchronized method? + +private: + CBotDefParam* m_Param; // parameter list + CBotInstr* m_Block; // the instruction block + CBotFunction* m_next; + CBotToken m_retToken; // if returns CBotTypClass + CBotTypResult m_retTyp; // complete type of the result + + bool m_bPublic; // public function + bool m_bExtern; // extern function + CBotString m_MasterClass; // name of the class we derive + CBotProgram* m_pProg; + friend class CBotProgram; + friend class CBotClass; + + CBotToken m_extern; // for the position of the word "extern" + CBotToken m_openpar; + CBotToken m_closepar; + CBotToken m_openblk; + CBotToken m_closeblk; +public: + CBotFunction(); + ~CBotFunction(); + static + CBotFunction* Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* pFunc, bool bLocal = true); + static + CBotFunction* Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass); + bool Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL); + void RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL); + + void AddNext(CBotFunction* p); + CBotTypResult CompileCall(const char* name, CBotVar** ppVars, long& nIdent); + CBotFunction* FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic = true); + + int DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken); + void RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack); + int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass); + void RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass); + bool CheckParam(CBotDefParam* pParam); + + static + void AddPublic(CBotFunction* pfunc); + + CBotString GivName(); + CBotString GivParams(); + bool IsPublic(); + bool IsExtern(); + CBotFunction* Next(); + + bool GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop); +}; + + diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index c99185f..692d3c7 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -1,880 +1,882 @@ -// * 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/.///////////////////////////////////////////////////////////////////////
-// Gestion des variables de type classe
-//
-
-#include "CBot.h"
-
-
-CBotClass* CBotClass::m_ExClass = NULL;
-
-CBotClass::CBotClass(const char* name, CBotClass* pPapa, bool bIntrinsic)
-{
- m_pParent = pPapa;
- m_name = name;
- m_pVar = NULL;
- m_next = NULL;
- m_pCalls = NULL;
- m_pMethod = NULL;
- m_rMaj = NULL;
- m_IsDef = true;
- m_bIntrinsic= bIntrinsic;
- m_cptLock = 0;
- m_cptOne = 0;
- m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
-
- for ( int j= 0; j< 5 ; j++ )
- {
- m_ProgInLock[j] = NULL;
- }
-
-
- // se place tout seul dans la liste
- if (m_ExClass) m_ExClass->m_ExPrev = this;
- m_ExNext = m_ExClass;
- m_ExPrev = NULL;
- m_ExClass = this;
-
-}
-
-CBotClass::~CBotClass()
-{
- // retire la classe de la liste
- if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
- else m_ExClass = m_ExNext;
-
- if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
- m_ExPrev = NULL;
- m_ExNext = NULL;
-
- delete m_pVar;
- delete m_pCalls;
- delete m_pMethod;
-
- delete m_next; // libère toutes celle de ce niveau
-}
-
-
-void CBotClass::Free()
-{
- while ( m_ExClass != NULL )
- {
- delete m_ExClass;
- }
-}
-
-void CBotClass::Purge()
-{
- if ( this == NULL ) return;
-
- delete m_pVar;
- m_pVar = NULL;
- delete m_pCalls;
- m_pCalls = NULL;
- delete m_pMethod;
- m_pMethod = NULL;
- m_IsDef = false;
-
- m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
-
- m_next->Purge();
- m_next = NULL; // n'appartient plus à cette chaîne
-}
-
-bool CBotClass::Lock(CBotProgram* p)
-{
- int i = m_cptLock++;
-
- if ( i == 0 )
- {
- m_cptOne = 1;
- m_ProgInLock[0] = p;
- return true;
- }
- if ( p == m_ProgInLock[0] )
- {
- m_cptOne++;
- m_cptLock--; // a déjà été compté
- return true;
- }
-
- for ( int j = 1 ; j <= i ; j++)
- {
- if ( p == m_ProgInLock[j] )
- {
- m_cptLock--;
- return false; // déjà en attente
- }
- }
-
- if ( i < 5 ) // maxi 5 en attente
- {
- m_ProgInLock[i] = p; // se place dans la queue
- }
- else
- m_cptLock--;
-
- return false;
-}
-
-void CBotClass::Unlock()
-{
- if ( --m_cptOne > 0 ) return ;
-
- int i = --m_cptLock;
- if ( i<0 )
- {
- m_cptLock = 0;
- return;
- }
-
- for ( int j= 0; j< i ; j++ )
- {
- m_ProgInLock[j] = m_ProgInLock[j+1];
- }
- m_ProgInLock[i] = 0;
-}
-
-void CBotClass::FreeLock(CBotProgram* p)
-{
- CBotClass* pClass = m_ExClass;
-
- while ( pClass != NULL )
- {
- if ( p == pClass->m_ProgInLock[0] )
- {
- pClass->m_cptLock -= pClass->m_cptOne;
- pClass->m_cptOne = 0;
- }
-
- for ( int j = 1; j < 5 ; j++ )
- if ( p == pClass->m_ProgInLock[j] )
- pClass->m_cptLock--;
-
- pClass = pClass->m_ExNext;
- }
-}
-
-
-
-bool CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate)
-{
- CBotToken token(name, CBotString());
- CBotClass* pClass = type.GivClass();
-
- CBotVar* pVar = CBotVar::Create( name, type );
-/// pVar->SetUniqNum(CBotVar::NextUniqNum());
- pVar->SetPrivate( mPrivate );
-
- if ( pClass != NULL )
- {
-// pVar->SetClass(pClass);
- if ( type.Eq(CBotTypClass) )
- {
- // ajoute une instruction new pour initialiser l'object
- pVar->m_InitExpr = new CBotNew() ;
- CBotToken nom( pClass->GivName() );
- pVar->m_InitExpr->SetToken(&nom);
- }
- }
- return AddItem( pVar );
-}
-
-
-bool CBotClass::AddItem(CBotVar* pVar)
-{
- pVar->SetUniqNum(++m_nbVar);
-
- if ( m_pVar == NULL ) m_pVar = pVar;
- else m_pVar->AddNext(pVar);
-
- return true;
-}
-
-void CBotClass::AddNext(CBotClass* pClass)
-{
- CBotClass* p = this;
- while (p->m_next != NULL) p = p->m_next;
-
- p->m_next = pClass;
-}
-
-CBotString CBotClass::GivName()
-{
- return m_name;
-}
-
-CBotClass* CBotClass::GivParent()
-{
- if ( this == NULL ) return NULL;
- return m_pParent;
-}
-
-bool CBotClass::IsChildOf(CBotClass* pClass)
-{
- CBotClass* p = this;
- while ( p != NULL )
- {
- if ( p == pClass ) return true;
- p = p->m_pParent;
- }
- return false;
-}
-
-
-CBotVar* CBotClass::GivVar()
-{
- return m_pVar;
-}
-
-CBotVar* CBotClass::GivItem(const char* name)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->GivNext();
- }
- if ( m_pParent != NULL ) return m_pParent->GivItem(name);
- return NULL;
-}
-
-CBotVar* CBotClass::GivItemRef(int nIdent)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivUniqNum() == nIdent ) return p;
- p = p->GivNext();
- }
- if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent);
- return NULL;
-}
-
-bool CBotClass::IsIntrinsic()
-{
- return m_bIntrinsic;
-}
-
-CBotClass* CBotClass::Find(CBotToken* &pToken)
-{
- return Find(pToken->GivString());
-}
-
-CBotClass* CBotClass::Find(const char* name)
-{
- CBotClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->m_ExNext;
- }
-
- return NULL;
-}
-
-bool CBotClass::AddFunction(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
-{
- // mémorise les pointeurs aux deux fonctions
- CBotCallMethode* p = m_pCalls;
- CBotCallMethode* pp = NULL;
-
- while ( p != NULL )
- {
- if ( name == p->GivName() )
- {
- if ( pp == NULL ) m_pCalls = p->m_next;
- else pp->m_next = p->m_next;
- delete p;
- break;
- }
- pp = p;
- p = p->m_next;
- }
-
- p = new CBotCallMethode(name, rExec, rCompile);
-
- if (m_pCalls == NULL) m_pCalls = p;
- else m_pCalls->AddNext(p); // ajoute à la liste
-
- return true;
-}
-
-bool CBotClass::AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) )
-{
- m_rMaj = rMaj;
- return true;
-}
-
-// compile une méthode associée à une instance de classe
-// la méthode peut être déclarée par AddFunction ou par l'utilisateur
-
-CBotTypResult CBotClass::CompileMethode(const char* name,
- CBotVar* pThis, CBotVar** ppParams,
- CBotCStack* pStack, long& nIdent)
-{
- nIdent = 0; // oublie le précédent s'il y a lieu
-
- // recherche dans les méthodes déclarées par AddFunction
-
- CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent);
- if ( r.GivType() >= 0) return r;
-
- // recherche dans les méthodes déclarées par l'utilisateur
-
- r = m_pMethod->CompileCall(name, ppParams, nIdent);
- if ( r.Eq(TX_UNDEFCALL) && m_pParent != NULL )
- return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent);
- return r;
-}
-
-// exécute une méthode
-
-bool CBotClass::ExecuteMethode(long& nIdent, const char* name,
- CBotVar* pThis, CBotVar** ppParams,
- CBotVar* &pResult, CBotStack* &pStack,
- CBotToken* pToken)
-{
- int ret = m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
- if (ret>=0) return ret;
-
- ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this);
- return ret;
-}
-
-// rétabli la pile d'exécution
-
-void CBotClass::RestoreMethode(long& nIdent, const char* name, CBotVar* pThis,
- CBotVar** ppParams, CBotStack* &pStack)
-{
- m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, this);
-}
-
-
-
-
-bool CBotClass::SaveStaticState(FILE* pf)
-{
- if (!WriteWord( pf, CBOTVERSION*2)) return false;
-
- // sauve l'état des variables statiques dans les classes
- CBotClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if (!WriteWord( pf, 1)) return false;
- // enregistre le nom de la classe
- if (!WriteString( pf, p->GivName() )) return false;
-
- CBotVar* pv = p->GivVar();
- while( pv != NULL )
- {
- if ( pv->IsStatic() )
- {
- if (!WriteWord( pf, 1)) return false;
- if (!WriteString( pf, pv->GivName() )) return false;
-
- if ( !pv->Save0State(pf)) return false; // entête commune
- if ( !pv->Save1State(pf) ) return false; // sauve selon la classe fille
- if ( !WriteWord( pf, 0)) return false;
- }
- pv = pv->GivNext();
- }
-
- if (!WriteWord( pf, 0)) return false;
- p = p->m_ExNext;
- }
-
- if (!WriteWord( pf, 0)) return false;
- return true;
-}
-
-bool CBotClass::RestoreStaticState(FILE* pf)
-{
- CBotString ClassName, VarName;
- CBotClass* pClass;
- unsigned short w;
-
- if (!ReadWord( pf, w )) return false;
- if ( w != CBOTVERSION*2 ) return false;
-
- while (true)
- {
- if (!ReadWord( pf, w )) return false;
- if ( w == 0 ) return true;
-
- if (!ReadString( pf, ClassName )) return false;
- pClass = Find(ClassName);
-
- while (true)
- {
- if (!ReadWord( pf, w )) return false;
- if ( w == 0 ) break;
-
- CBotVar* pVar = NULL;
- CBotVar* pv = NULL;
-
- if (!ReadString( pf, VarName )) return false;
- if ( pClass != NULL ) pVar = pClass->GivItem(VarName);
-
- if (!CBotVar::RestoreState(pf, pv)) return false; // la variable temp
-
- if ( pVar != NULL ) pVar->Copy(pv);
- delete pv;
- }
- }
- return true;
-}
-
-
-/////////////////////////////////////////////////////////////////////
-
-CBotClassInst::CBotClassInst()
-{
- m_next = NULL;
- m_var = NULL;
- m_Parameters = NULL;
- m_expr = NULL;
- m_hasParams = false;
- m_nMethodeIdent = 0;
- name = "CBotClassInst";
-}
-
-CBotClassInst::~CBotClassInst()
-{
- delete m_var;
-// delete m_next; // fait par le destructeur de la classe de base ~CBotInstr()
-}
-
-// définition de pointeur(s) à un objet
-// du style
-// CPoint A, B ;
-
-CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
-{
- // cherche la classe correspondante
- if ( pClass == NULL )
- {
- pStack->SetStartError(p->GivStart());
- pClass = CBotClass::Find(p);
- if ( pClass == NULL )
- {
- // pas trouvé ? c'est bizare
- pStack->SetError(TX_NOCLASS, p);
- return NULL;
- }
- p = p->GivNext();
- }
-
- bool bIntrinsic = pClass->IsIntrinsic();
- CBotTypResult type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer, pClass );
- CBotClassInst* inst = (CBotClassInst*)CompileArray(p, pStack, type);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
-
- CBotCStack* pStk = pStack->TokenStack();
-
- inst = new CBotClassInst();
- /// \TODO Need to be revised and fixed after adding unit tests
- CBotToken token(pClass->GivName(), CBotString(), p->GivStart(), p->GivEnd());
- inst->SetToken(&token);
- CBotToken* vartoken = p;
-
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = type;
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable
- {
- pStk->SetStartError(vartoken->GivStart());
- pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK)) // avec des indices ?
- {
- delete inst; // n'est pas de type CBotInt
- p = vartoken; // revient sur le nom de la variable
-
- // compile une déclaration de tableau
-
- inst = (CBotClassInst*)CBotInstArray::Compile( p, pStk, type );
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- goto suite; // pas d'assignation, variable déjà créée
- }
-
-
- CBotVar* var;
- var = CBotVar::Create(vartoken->GivString(), type); // crée l'instance
-// var->SetClass(pClass);
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
-
- // regarde s'il y a des paramètres
- inst->m_hasParams = (p->GivType() == ID_OPENPAR);
-
- CBotVar* ppVars[1000];
- inst->m_Parameters = CompileParams(p, pStk, ppVars);
- if ( !pStk->IsOk() ) goto error;
-
- // s'il y a des paramètres, fait l'équivalent de l'instruction new
- // CPoint A ( 0, 0 ) est équivalent à
- // CPoint A = new CPoint( 0, 0 )
-
-// if ( NULL != inst->m_Parameters )
- if ( inst->m_hasParams )
- {
- // le constructeur existe-il ?
-// CBotString noname;
- CBotTypResult r = pClass->CompileMethode(pClass->GivName(), var, ppVars, pStk, inst->m_nMethodeIdent);
- delete pStk->TokenStack(); // libère le supplément de pile
- int typ = r.GivType();
-
- if (typ == TX_UNDEFCALL)
- {
- // si le constructeur n'existe pas
- if (inst->m_Parameters != NULL) // avec des paramètres
- {
- pStk->SetError(TX_NOCONST, vartoken);
- goto error;
- }
- typ = 0;
- }
-
- if (typ>20)
- {
- pStk->SetError(typ, vartoken->GivEnd());
- goto error;
- }
-
- }
-
- if (IsOfType(p, ID_ASS)) // avec une assignation ?
- {
- if (inst->m_hasParams)
- {
- pStk->SetError(TX_ENDOF, p->GivStart());
- goto error;
- }
-
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
- CBotClass* result = pStk->GivClass();
- if ( !pStk->GivTypResult(1).Eq(CBotTypNullPointer) &&
- ( !pStk->GivTypResult(1).Eq(CBotTypPointer) ||
- ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
-// if ( !bIntrinsic ) var->SetPointer(pStk->GivVar()->GivPointer());
- if ( !bIntrinsic )
- {
- // n'utilise pas le résultat sur la pile, pour imposer la classe
- CBotVar* pvar = CBotVar::Create("", pClass);
- var->SetPointer( pvar ); // var déjà déclarée pointe l'instance
- delete pvar; // supprime le second pointeur
- }
- var->SetInit(true); // marque le pointeur comme init
- }
- else if (inst->m_hasParams)
- {
- // crée l'objet sur le "tas"
- // avec un pointeur sur cet objet
- if ( !bIntrinsic )
- {
- CBotVar* pvar = CBotVar::Create("", pClass);
- var->SetPointer( pvar ); // var déjà déclarée pointe l'instance
- delete pvar; // supprime le second pointeur
- }
- var->SetInit(2); // marque le pointeur comme init
- }
-suite:
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compile la suivante
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (IsOfType(p, ID_SEP)) // instruction terminée
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// déclaration de l'instance d'une classe, par exemple:
-// CPoint A, B;
-
-bool CBotClassInst::Execute(CBotStack* &pj)
-{
- CBotVar* pThis = NULL;
-
- CBotStack* pile = pj->AddStack(this);//indispensable pour SetState()
-// if ( pile == EOX ) return true;
-
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
-
- bool bIntrincic = pClass->IsIntrinsic();
-
- // crée la variable de type pointeur à l'objet
-
- if ( pile->GivState()==0)
- {
- CBotString name = m_var->m_token.GivString();
- if ( bIntrincic )
- {
- pThis = CBotVar::Create(name, CBotTypResult( CBotTypIntrinsic, pClass ));
- }
- else
- {
- pThis = CBotVar::Create(name, CBotTypResult( CBotTypPointer, pClass ));
- }
-
- pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // lui attribut un numéro unique
- pile->AddVar(pThis); // la place sur la pile
- pile->IncState();
- }
-
- if ( pThis == NULL ) pThis = pile->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent);
-
- if ( pile->GivState()<3)
- {
- // y a-t-il une assignation ou des paramètres (constructeur)
-
-// CBotVarClass* pInstance = NULL;
-
- if ( m_expr != NULL )
- {
- // évalue l'expression pour l'assignation
- if (!m_expr->Execute(pile)) return false;
-
- if ( bIntrincic )
- {
- CBotVar* pv = pile->GivVar();
- if ( pv == NULL || pv->GivPointer() == NULL )
- {
- pile->SetError(TX_NULLPT, &m_token);
- return pj->Return(pile);
- }
- pThis->Copy(pile->GivVar(), false);
- }
- else
- {
- CBotVarClass* pInstance;
- pInstance = ((CBotVarPointer*)pile->GivVar())->GivPointer(); // valeur pour l'assignation
- pThis->SetPointer(pInstance);
- }
- pThis->SetInit(true);
- }
-
- else if ( m_hasParams )
- {
- // évalue le constructeur d'une instance
-
- if ( !bIntrincic && pile->GivState() == 1)
- {
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
-
- // crée une instance de la classe demandée
-
- CBotVarClass* pInstance;
- pInstance = (CBotVarClass*)CBotVar::Create("", pClass);
- pThis->SetPointer(pInstance);
- delete pInstance;
-
- pile->IncState();
- }
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( true )
- {
- pile2 = pile2->AddStack(); // de la place sur la pile pour les résultats
- if ( pile2->GivState() == 0 )
- {
- if (!p->Execute(pile2)) return false; // interrompu ici ?
- pile2->SetState(1);
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // crée une variable pour le résultat
- CBotVar* pResult = NULL; // constructeurs toujours void
-
- if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(),
- pThis, ppVars,
- pResult, pile2, GivToken())) return false; // interrompu
-
- pThis->SetInit(true);
- pThis->ConstructorSet(); // signale que le constructeur a été appelé
- pile->Return(pile2); // libère un bout de pile
-
-// pInstance = pThis->GivPointer();
-
- }
-
-// if ( !bIntrincic ) pThis->SetPointer(pInstance); // le fait pointer l'instance
-
- pile->SetState(3); // fini cette partie
- }
-
- if ( pile->IfStep() ) return false;
-
- if ( m_next2b != NULL &&
- !m_next2b->Execute(pile)) return false; // autre(s) définition(s)
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-
-
-void CBotClassInst::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotVar* pThis = NULL;
-
- CBotStack* pile = pj;
- if ( bMain ) pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- // crée la variable de type pointeur à l'objet
- {
- CBotString name = m_var->m_token.GivString();
- pThis = pile->FindVar(name);
- pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // lui attribut un numéro unique
- }
-
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
- bool bIntrincic = pClass->IsIntrinsic();
-
- if ( bMain && pile->GivState()<3)
- {
- // y a-t-il une assignation ou des paramètres (constructeur)
-
-// CBotVarClass* pInstance = NULL;
-
- if ( m_expr != NULL )
- {
- // évalue l'expression pour l'assignation
- m_expr->RestoreState(pile, bMain);
- return;
- }
-
- else if ( m_hasParams )
- {
- // évalue le constructeur d'une instance
-
- if ( !bIntrincic && pile->GivState() == 1)
- {
- return;
- }
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( true )
- {
- pile2 = pile2->RestoreStack(); // de la place sur la pile pour les résultats
- if ( pile2 == NULL ) return;
-
- if ( pile2->GivState() == 0 )
- {
- p->RestoreState(pile2, bMain); // interrompu ici ?
- return;
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // crée une variable pour le résultat
- CBotVar* pResult = NULL; // constructeurs toujours void
-
- pClass->RestoreMethode(m_nMethodeIdent, pClass->GivName(), pThis, ppVars, pile2);
- return;
- }
- }
-
- if ( m_next2b != NULL )
- m_next2b->RestoreState(pile, bMain); // autre(s) définition(s)
-}
-
-
-// test si un nom de procédure est déjà défini quelque part
-
-bool CBotClass::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
-{
- CBotString name = pToken->GivString();
-
- if ( CBotCall::CheckCall(name) ) return true;
-
- CBotFunction* pp = m_pMethod;
- while ( pp != NULL )
- {
- if ( pToken->GivString() == pp->GivName() )
- {
- // les paramètres sont-ils exactement les mêmes ?
- if ( pp->CheckParam( pParam ) )
- return true;
- }
- pp = pp->Next();
- }
-
- return false;
-}
-
+// * 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/.// + +///////////////////////////////////////////////////////////////////// +// Management of variables of class type +// + +#include "CBot.h" + + +CBotClass* CBotClass::m_ExClass = NULL; + +CBotClass::CBotClass(const char* name, CBotClass* pPapa, bool bIntrinsic) +{ + m_pParent = pPapa; + m_name = name; + m_pVar = NULL; + m_next = NULL; + m_pCalls = NULL; + m_pMethod = NULL; + m_rMaj = NULL; + m_IsDef = true; + m_bIntrinsic= bIntrinsic; + m_cptLock = 0; + m_cptOne = 0; + m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar; + + for ( int j= 0; j< 5 ; j++ ) + { + m_ProgInLock[j] = NULL; + } + + + // is located alone in the list + if (m_ExClass) m_ExClass->m_ExPrev = this; + m_ExNext = m_ExClass; + m_ExPrev = NULL; + m_ExClass = this; + +} + +CBotClass::~CBotClass() +{ + // removes the list of class + if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext; + else m_ExClass = m_ExNext; + + if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev; + m_ExPrev = NULL; + m_ExNext = NULL; + + delete m_pVar; + delete m_pCalls; + delete m_pMethod; + + delete m_next; // releases all of them on this level +} + + +void CBotClass::Free() +{ + while ( m_ExClass != NULL ) + { + delete m_ExClass; + } +} + +void CBotClass::Purge() +{ + if ( this == NULL ) return; + + delete m_pVar; + m_pVar = NULL; + delete m_pCalls; + m_pCalls = NULL; + delete m_pMethod; + m_pMethod = NULL; + m_IsDef = false; + + m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar; + + m_next->Purge(); + m_next = NULL; // no longer belongs to this chain +} + +bool CBotClass::Lock(CBotProgram* p) +{ + int i = m_cptLock++; + + if ( i == 0 ) + { + m_cptOne = 1; + m_ProgInLock[0] = p; + return true; + } + if ( p == m_ProgInLock[0] ) + { + m_cptOne++; + m_cptLock--; // has already been counted + return true; + } + + for ( int j = 1 ; j <= i ; j++) + { + if ( p == m_ProgInLock[j] ) + { + m_cptLock--; + return false; // already pending + } + } + + if ( i < 5 ) // max 5 in query + { + m_ProgInLock[i] = p; // located in a queue + } + else + m_cptLock--; + + return false; +} + +void CBotClass::Unlock() +{ + if ( --m_cptOne > 0 ) return ; + + int i = --m_cptLock; + if ( i<0 ) + { + m_cptLock = 0; + return; + } + + for ( int j= 0; j< i ; j++ ) + { + m_ProgInLock[j] = m_ProgInLock[j+1]; + } + m_ProgInLock[i] = 0; +} + +void CBotClass::FreeLock(CBotProgram* p) +{ + CBotClass* pClass = m_ExClass; + + while ( pClass != NULL ) + { + if ( p == pClass->m_ProgInLock[0] ) + { + pClass->m_cptLock -= pClass->m_cptOne; + pClass->m_cptOne = 0; + } + + for ( int j = 1; j < 5 ; j++ ) + if ( p == pClass->m_ProgInLock[j] ) + pClass->m_cptLock--; + + pClass = pClass->m_ExNext; + } +} + + + +bool CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate) +{ + CBotToken token(name, CBotString()); + CBotClass* pClass = type.GivClass(); + + CBotVar* pVar = CBotVar::Create( name, type ); +/// pVar->SetUniqNum(CBotVar::NextUniqNum()); + pVar->SetPrivate( mPrivate ); + + if ( pClass != NULL ) + { +// pVar->SetClass(pClass); + if ( type.Eq(CBotTypClass) ) + { + // adds a new statement for the object initialization + pVar->m_InitExpr = new CBotNew() ; + CBotToken nom( pClass->GivName() ); + pVar->m_InitExpr->SetToken(&nom); + } + } + return AddItem( pVar ); +} + + +bool CBotClass::AddItem(CBotVar* pVar) +{ + pVar->SetUniqNum(++m_nbVar); + + if ( m_pVar == NULL ) m_pVar = pVar; + else m_pVar->AddNext(pVar); + + return true; +} + +void CBotClass::AddNext(CBotClass* pClass) +{ + CBotClass* p = this; + while (p->m_next != NULL) p = p->m_next; + + p->m_next = pClass; +} + +CBotString CBotClass::GivName() +{ + return m_name; +} + +CBotClass* CBotClass::GivParent() +{ + if ( this == NULL ) return NULL; + return m_pParent; +} + +bool CBotClass::IsChildOf(CBotClass* pClass) +{ + CBotClass* p = this; + while ( p != NULL ) + { + if ( p == pClass ) return true; + p = p->m_pParent; + } + return false; +} + + +CBotVar* CBotClass::GivVar() +{ + return m_pVar; +} + +CBotVar* CBotClass::GivItem(const char* name) +{ + CBotVar* p = m_pVar; + + while ( p != NULL ) + { + if ( p->GivName() == name ) return p; + p = p->GivNext(); + } + if ( m_pParent != NULL ) return m_pParent->GivItem(name); + return NULL; +} + +CBotVar* CBotClass::GivItemRef(int nIdent) +{ + CBotVar* p = m_pVar; + + while ( p != NULL ) + { + if ( p->GivUniqNum() == nIdent ) return p; + p = p->GivNext(); + } + if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent); + return NULL; +} + +bool CBotClass::IsIntrinsic() +{ + return m_bIntrinsic; +} + +CBotClass* CBotClass::Find(CBotToken* &pToken) +{ + return Find(pToken->GivString()); +} + +CBotClass* CBotClass::Find(const char* name) +{ + CBotClass* p = m_ExClass; + + while ( p != NULL ) + { + if ( p->GivName() == name ) return p; + p = p->m_ExNext; + } + + return NULL; +} + +bool CBotClass::AddFunction(const char* name, + bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception), + CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar)) +{ + // stores pointers to the two functions + CBotCallMethode* p = m_pCalls; + CBotCallMethode* pp = NULL; + + while ( p != NULL ) + { + if ( name == p->GivName() ) + { + if ( pp == NULL ) m_pCalls = p->m_next; + else pp->m_next = p->m_next; + delete p; + break; + } + pp = p; + p = p->m_next; + } + + p = new CBotCallMethode(name, rExec, rCompile); + + if (m_pCalls == NULL) m_pCalls = p; + else m_pCalls->AddNext(p); // added to the list + + return true; +} + +bool CBotClass::AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) ) +{ + m_rMaj = rMaj; + return true; +} + +// compiles a method associated with an instance of class +// the method can be declared by the user or AddFunction + +CBotTypResult CBotClass::CompileMethode(const char* name, + CBotVar* pThis, CBotVar** ppParams, + CBotCStack* pStack, long& nIdent) +{ + nIdent = 0; // forget the previous one if necessary + + // find the methods declared by AddFunction + + CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent); + if ( r.GivType() >= 0) return r; + + // find the methods declared by user + + r = m_pMethod->CompileCall(name, ppParams, nIdent); + if ( r.Eq(TX_UNDEFCALL) && m_pParent != NULL ) + return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent); + return r; +} + +// executes a method + +bool CBotClass::ExecuteMethode(long& nIdent, const char* name, + CBotVar* pThis, CBotVar** ppParams, + CBotVar* &pResult, CBotStack* &pStack, + CBotToken* pToken) +{ + int ret = m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken); + if (ret>=0) return ret; + + ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this); + return ret; +} + +// restored the execution stack + +void CBotClass::RestoreMethode(long& nIdent, const char* name, CBotVar* pThis, + CBotVar** ppParams, CBotStack* &pStack) +{ + m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, this); +} + + + + +bool CBotClass::SaveStaticState(FILE* pf) +{ + if (!WriteWord( pf, CBOTVERSION*2)) return false; + + // saves the state of static variables in classes + CBotClass* p = m_ExClass; + + while ( p != NULL ) + { + if (!WriteWord( pf, 1)) return false; + // save the name of the class + if (!WriteString( pf, p->GivName() )) return false; + + CBotVar* pv = p->GivVar(); + while( pv != NULL ) + { + if ( pv->IsStatic() ) + { + if (!WriteWord( pf, 1)) return false; + if (!WriteString( pf, pv->GivName() )) return false; + + if ( !pv->Save0State(pf)) return false; // common header + if ( !pv->Save1State(pf) ) return false; // saves as the child class + if ( !WriteWord( pf, 0)) return false; + } + pv = pv->GivNext(); + } + + if (!WriteWord( pf, 0)) return false; + p = p->m_ExNext; + } + + if (!WriteWord( pf, 0)) return false; + return true; +} + +bool CBotClass::RestoreStaticState(FILE* pf) +{ + CBotString ClassName, VarName; + CBotClass* pClass; + unsigned short w; + + if (!ReadWord( pf, w )) return false; + if ( w != CBOTVERSION*2 ) return false; + + while (true) + { + if (!ReadWord( pf, w )) return false; + if ( w == 0 ) return true; + + if (!ReadString( pf, ClassName )) return false; + pClass = Find(ClassName); + + while (true) + { + if (!ReadWord( pf, w )) return false; + if ( w == 0 ) break; + + CBotVar* pVar = NULL; + CBotVar* pv = NULL; + + if (!ReadString( pf, VarName )) return false; + if ( pClass != NULL ) pVar = pClass->GivItem(VarName); + + if (!CBotVar::RestoreState(pf, pv)) return false; // the temp variable + + if ( pVar != NULL ) pVar->Copy(pv); + delete pv; + } + } + return true; +} + + +///////////////////////////////////////////////////////////////////// + +CBotClassInst::CBotClassInst() +{ + m_next = NULL; + m_var = NULL; + m_Parameters = NULL; + m_expr = NULL; + m_hasParams = false; + m_nMethodeIdent = 0; + name = "CBotClassInst"; +} + +CBotClassInst::~CBotClassInst() +{ + delete m_var; +// delete m_next; // done by the destructor of the base class ~CBotInstr() +} + +// definition of pointer (s) to an object +// style +// CPoint A, B ; + +CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) +{ + // seeks the corresponding classes + if ( pClass == NULL ) + { + pStack->SetStartError(p->GivStart()); + pClass = CBotClass::Find(p); + if ( pClass == NULL ) + { + // not found? is bizare + pStack->SetError(TX_NOCLASS, p); + return NULL; + } + p = p->GivNext(); + } + + bool bIntrinsic = pClass->IsIntrinsic(); + CBotTypResult type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer, pClass ); + CBotClassInst* inst = (CBotClassInst*)CompileArray(p, pStack, type); + if ( inst != NULL || !pStack->IsOk() ) return inst; + + CBotCStack* pStk = pStack->TokenStack(); + + inst = new CBotClassInst(); + /// \TODO Need to be revised and fixed after adding unit tests + CBotToken token(pClass->GivName(), CBotString(), p->GivStart(), p->GivEnd()); + inst->SetToken(&token); + CBotToken* vartoken = p; + + if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) ) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = type; + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable + { + pStk->SetStartError(vartoken->GivStart()); + pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) // with any clues? + { + delete inst; // is not type CBotInt + p = vartoken; // returns to the variable name + + // compiles declaration an array + + inst = (CBotClassInst*)CBotInstArray::Compile( p, pStk, type ); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + goto suite; // no assignment, variable already created + } + + + CBotVar* var; + var = CBotVar::Create(vartoken->GivString(), type); // creates the instance +// var->SetClass(pClass); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + // its attribute a unique number + pStack->AddVar(var); // placed on the stack + + // look if there are parameters + inst->m_hasParams = (p->GivType() == ID_OPENPAR); + + CBotVar* ppVars[1000]; + inst->m_Parameters = CompileParams(p, pStk, ppVars); + if ( !pStk->IsOk() ) goto error; + + // if there are parameters, is the equivalent to the stament "new" + // CPoint A ( 0, 0 ) is equivalent to + // CPoint A = new CPoint( 0, 0 ) + +// if ( NULL != inst->m_Parameters ) + if ( inst->m_hasParams ) + { + // the constructor is there? +// CBotString noname; + CBotTypResult r = pClass->CompileMethode(pClass->GivName(), var, ppVars, pStk, inst->m_nMethodeIdent); + delete pStk->TokenStack(); // releases the supplement stack + int typ = r.GivType(); + + if (typ == TX_UNDEFCALL) + { + // si le constructeur n'existe pas + if (inst->m_Parameters != NULL) // with parameters + { + pStk->SetError(TX_NOCONST, vartoken); + goto error; + } + typ = 0; + } + + if (typ>20) + { + pStk->SetError(typ, vartoken->GivEnd()); + goto error; + } + + } + + if (IsOfType(p, ID_ASS)) // with a assignment? + { + if (inst->m_hasParams) + { + pStk->SetError(TX_ENDOF, p->GivStart()); + goto error; + } + + if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) ) + { + goto error; + } + CBotClass* result = pStk->GivClass(); + if ( !pStk->GivTypResult(1).Eq(CBotTypNullPointer) && + ( !pStk->GivTypResult(1).Eq(CBotTypPointer) || + ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } +// if ( !bIntrinsic ) var->SetPointer(pStk->GivVar()->GivPointer()); + if ( !bIntrinsic ) + { + // does not use the result on the stack, to impose the class + CBotVar* pvar = CBotVar::Create("", pClass); + var->SetPointer( pvar ); // variable already declared instance pointer + delete pvar; // removes the second pointer + } + var->SetInit(true); // marks the pointer as init + } + else if (inst->m_hasParams) + { + // creates the object on the "job" (\TODO "tas") + // with a pointer to the object + if ( !bIntrinsic ) + { + CBotVar* pvar = CBotVar::Create("", pClass); + var->SetPointer( pvar ); // variable already declared instance pointer + delete pvar; // removes the second pointer + } + var->SetInit(2); // marks the pointer as init + } +suite: + if (IsOfType(p, ID_COMMA)) // several chained definitions + { + if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compiles the following + { + return pStack->Return(inst, pStk); + } + } + + if (IsOfType(p, ID_SEP)) // complete instruction + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// declaration of the instance of a class, for example: +// CPoint A, B; + +bool CBotClassInst::Execute(CBotStack* &pj) +{ + CBotVar* pThis = NULL; + + CBotStack* pile = pj->AddStack(this);//essential for SetState() +// if ( pile == EOX ) return true; + + CBotToken* pt = &m_token; + CBotClass* pClass = CBotClass::Find(pt); + + bool bIntrincic = pClass->IsIntrinsic(); + + // creates the variable of type pointer to the object + + if ( pile->GivState()==0) + { + CBotString name = m_var->m_token.GivString(); + if ( bIntrincic ) + { + pThis = CBotVar::Create(name, CBotTypResult( CBotTypIntrinsic, pClass )); + } + else + { + pThis = CBotVar::Create(name, CBotTypResult( CBotTypPointer, pClass )); + } + + pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // its attribute as unique number + pile->AddVar(pThis); // place on the stack + pile->IncState(); + } + + if ( pThis == NULL ) pThis = pile->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent); + + if ( pile->GivState()<3) + { + // ss there an assignment or parameters (contructor) + +// CBotVarClass* pInstance = NULL; + + if ( m_expr != NULL ) + { + // evaluates the expression for the assignment + if (!m_expr->Execute(pile)) return false; + + if ( bIntrincic ) + { + CBotVar* pv = pile->GivVar(); + if ( pv == NULL || pv->GivPointer() == NULL ) + { + pile->SetError(TX_NULLPT, &m_token); + return pj->Return(pile); + } + pThis->Copy(pile->GivVar(), false); + } + else + { + CBotVarClass* pInstance; + pInstance = ((CBotVarPointer*)pile->GivVar())->GivPointer(); // value for the assignment + pThis->SetPointer(pInstance); + } + pThis->SetInit(true); + } + + else if ( m_hasParams ) + { + // evaluates the constructor of an instance + + if ( !bIntrincic && pile->GivState() == 1) + { + CBotToken* pt = &m_token; + CBotClass* pClass = CBotClass::Find(pt); + + // creates an instance of the requested class + + CBotVarClass* pInstance; + pInstance = (CBotVarClass*)CBotVar::Create("", pClass); + pThis->SetPointer(pInstance); + delete pInstance; + + pile->IncState(); + } + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluates the parameters + // and places the values ​​on the stack + // to (can) be interrupted (broken) at any time + + if ( p != NULL) while ( true ) + { + pile2 = pile2->AddStack(); // place on the stack for the results + 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; + + // creates a variable for the result + CBotVar* pResult = NULL; // constructor still void + + if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(), + pThis, ppVars, + pResult, pile2, GivToken())) return false; // interrupt + + pThis->SetInit(true); + pThis->ConstructorSet(); // indicates that the constructor has been called + pile->Return(pile2); // releases a piece of stack + +// pInstance = pThis->GivPointer(); + + } + +// if ( !bIntrincic ) pThis->SetPointer(pInstance); // a pointer to the instance + + pile->SetState(3); // finished this part + } + + if ( pile->IfStep() ) return false; + + if ( m_next2b != NULL && + !m_next2b->Execute(pile)) return false; // other (s) definition (s) + + return pj->Return( pile ); // transmits below (further) +} + + + +void CBotClassInst::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotVar* pThis = NULL; + + CBotStack* pile = pj; + if ( bMain ) pile = pj->RestoreStack(this); + if ( pile == NULL ) return; + + // creates the variable of type pointer to the object + { + CBotString name = m_var->m_token.GivString(); + pThis = pile->FindVar(name); + pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // its attribute a unique number + } + + CBotToken* pt = &m_token; + CBotClass* pClass = CBotClass::Find(pt); + bool bIntrincic = pClass->IsIntrinsic(); + + if ( bMain && pile->GivState()<3) + { + // is there an assignment or parameters (constructor) + +// CBotVarClass* pInstance = NULL; + + if ( m_expr != NULL ) + { + // evaluates the expression for the assignment + m_expr->RestoreState(pile, bMain); + return; + } + + else if ( m_hasParams ) + { + // evaluates the constructor of an instance + + if ( !bIntrincic && pile->GivState() == 1) + { + return; + } + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluates the parameters + // and the values an the stack + // for the ability to be interrupted at any time (\TODO pour pouvoir être interrompu n'importe quand) + + if ( p != NULL) while ( true ) + { + pile2 = pile2->RestoreStack(); // place on the stack for the results + if ( pile2 == NULL ) return; + + if ( pile2->GivState() == 0 ) + { + p->RestoreState(pile2, bMain); // interrupted here? + return; + } + ppVars[i++] = pile2->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + // creates a variable for the result + CBotVar* pResult = NULL; // constructor still void + + pClass->RestoreMethode(m_nMethodeIdent, pClass->GivName(), pThis, ppVars, pile2); + return; + } + } + + if ( m_next2b != NULL ) + m_next2b->RestoreState(pile, bMain); // other(s) definition(s) +} + + +// test if a procedure name is already defined somewhere + +bool CBotClass::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) +{ + CBotString name = pToken->GivString(); + + if ( CBotCall::CheckCall(name) ) return true; + + CBotFunction* pp = m_pMethod; + while ( pp != NULL ) + { + if ( pToken->GivString() == pp->GivName() ) + { + // are their parameters exactly the same? + if ( pp->CheckParam( pParam ) ) + return true; + } + pp = pp->Next(); + } + + return false; +} + |