summaryrefslogtreecommitdiffstats
path: root/src/CBot
diff options
context:
space:
mode:
authorMichał Konopacki <konopacki.m@gmail.com>2012-08-08 02:01:06 +0200
committerMichał Konopacki <konopacki.m@gmail.com>2012-08-08 02:01:06 +0200
commit0919796df7ab9025bb53ef2dc56d0888de8c7e73 (patch)
treeeb786bfb4ed3a823a2ad0c0e2c19e25696274989 /src/CBot
parent0844a0f7bdcd3184ee60aaf0e943b65c73c8c283 (diff)
downloadcolobot-0919796df7ab9025bb53ef2dc56d0888de8c7e73.tar.gz
colobot-0919796df7ab9025bb53ef2dc56d0888de8c7e73.tar.bz2
colobot-0919796df7ab9025bb53ef2dc56d0888de8c7e73.zip
Transation of comments complete
Diffstat (limited to 'src/CBot')
-rw-r--r--src/CBot/CBotAddExpr.cpp286
-rw-r--r--src/CBot/CBotCompExpr.cpp264
-rw-r--r--src/CBot/CBotDll.h2234
-rw-r--r--src/CBot/CBotFunction.cpp3291
-rw-r--r--src/CBot/CBotStack.cpp2942
-rw-r--r--src/CBot/CBotString.cpp3
-rw-r--r--src/CBot/CBotToken.h1
-rw-r--r--src/CBot/CBotTwoOpExpr.cpp1134
-rw-r--r--src/CBot/ClassFILE.cpp64
-rw-r--r--src/CBot/StringFunctions.cpp870
10 files changed, 5551 insertions, 5538 deletions
diff --git a/src/CBot/CBotAddExpr.cpp b/src/CBot/CBotAddExpr.cpp
index d94946e..8e4ed85 100644
--- a/src/CBot/CBotAddExpr.cpp
+++ b/src/CBot/CBotAddExpr.cpp
@@ -1,142 +1,144 @@
-// * 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/.///////////////////////////////////////////////////
-// expression du genre Opérande1 + Opérande2
-// Opérande1 - Opérande2
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotAddExpr::CBotAddExpr()
-{
- m_leftop =
- m_rightop = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotAddExpr"; // debug
-}
-
-CBotAddExpr::~CBotAddExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-
-// compile une instruction de type A + B
-
-CBotInstr* CBotAddExpr::Compile(CBotToken* &p, CBotStack* pStack)
-{
- CBotStack* pStk = pStack->TokenStack(); // un bout de pile svp
-
- // cherche des instructions qui peuvent convenir à gauche de l'opération + ou -
-
- CBotInstr* left = CBotMulExpr::Compile( p, pStk ); // expression A * B à gauche
- if (left == NULL) return pStack->Return(NULL, pStk); // si erreur, la transmet
-
- // est-ce qu'on a le token + ou - ensuite ?
-
- if ( p->GetType() == ID_ADD ||
- p->GetType() == ID_SUB) // plus ou moins
- {
- CBotAddExpr* inst = new CBotAddExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
- int type1, type2;
- type1 = pStack->GetType(); // de quel type le premier opérande ?
-
- p = p->Next(); // saute le token de l'opération
-
- // cherche des instructions qui peuvent convenir à droite
-
- if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression (...) à droite
- {
- // il y a un second opérande acceptable
-
- type2 = pStack->GetType(); // de quel type le résultat ?
-
- if ( type1 == type2 ) // les résultats sont-ils compatibles
- {
- // si ok, enregistre l'opérande dans l'objet
- inst->m_leftop = left;
- // et rend l'object à qui l'a demandé
- return pStack->Return(inst, pStk);
- }
- }
-
- // en cas d'erreur, libère les éléments
- delete left;
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile
- return pStack->Return(NULL, pStk);
- }
-
- // si on n'a pas affaire à une opération + ou -
- // rend à qui l'a demandé, l'opérande (de gauche) trouvé
- // à la place de l'objet "addition"
- return pStack->Return(left, pStk);
-}
-
-
-
-
-// fait l'opération d'addition ou de soustraction
-
-bool CBotAddExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pSk1 == EOX ) return TRUE;
-
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GetState() == 0 && // 1er état, évalue l'opérande de gauche
- !m_leftop->Execute(pStk1) ) return FALSE; // interrompu ici ?
-
- // passe à l'étape suivante
- pStk1->SetState(1); // prêt pour la suite
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- // qui se trouve sur la pile, justement.
-
- CBotStack* pStk2 = pStk1->AddStack(); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-
- // 2e état, évalue l'opérande de droite
- if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrompu ici ?
-
- int type1 = pStk1->GetType(); // de quels types les résultats ?
- int type2 = pStk2->GetType();
-
- // crée une variable temporaire pour y mettre le résultat
- CBotVar* result = new CBotVar( NULL, MAX(type1, type2));
-
- // fait l'opération selon la demande
- switch (GetTokenType())
- {
- case ID_ADD:
- result->Add(pStk1->GetVar(), pStk2->GetVar()); // additionne
- break;
- case ID_SUB:
- result->Sub(pStk1->GetVar(), pStk2->GetVar()); // soustrait
- break;
- }
- pStk2->SetVar(result); // met le résultat sur la pile
-
- pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk1); // transmet le résultat
-}
-
-
+// * 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/.
+
+///////////////////////////////////////////////////
+// expressions of type Operand1 + Operand2
+// Operand1 - Operand2
+
+#include "CBot.h"
+
+// various constructors
+
+CBotAddExpr::CBotAddExpr()
+{
+ m_leftop =
+ m_rightop = NULL; // NULL to be able to delete without further
+ name = "CBotAddExpr"; // debug
+}
+
+CBotAddExpr::~CBotAddExpr()
+{
+ delete m_leftop;
+ delete m_rightop;
+}
+
+
+// compile une instruction de type A + B
+
+CBotInstr* CBotAddExpr::Compile(CBotToken* &p, CBotStack* pStack)
+{
+ CBotStack* pStk = pStack->TokenStack(); // one end of stack please
+
+ // looking statements that may be suitable to the left of the operation + or -
+
+ CBotInstr* left = CBotMulExpr::Compile( p, pStk ); // expression A * B left
+ if (left == NULL) return pStack->Return(NULL, pStk); // if error, transmit
+
+ // do we have the token + or - next?
+
+ if ( p->GetType() == ID_ADD ||
+ p->GetType() == ID_SUB) // more or less
+ {
+ CBotAddExpr* inst = new CBotAddExpr(); // element for operation
+ inst->SetToken(p); // stores the operation
+
+ int type1, type2;
+ type1 = pStack->GetType(); // what kind of the first operand?
+
+ p = p->Next(); // skip the token of the operation
+
+ // looking statements that may be suitable for right
+
+ if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression (...) rigth
+ {
+ // there is an acceptable second operand
+
+ type2 = pStack->GetType(); // what kind of results?
+
+ if ( type1 == type2 ) // are the results consistent ?
+ {
+ // ok so, saves the operand in the object
+ inst->m_leftop = left;
+ // and makes the object on demand
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ // in case of error, free the elements
+ delete left;
+ delete inst;
+ // and transmits the error that is on the stack
+ return pStack->Return(NULL, pStk);
+ }
+
+ // if we are not dealing with an operation + or -
+ // goes to that requested, the operand (left) found
+ // place the object "addition"
+ return pStack->Return(left, pStk);
+}
+
+
+
+
+// operation is addition or subtraction
+
+bool CBotAddExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack
+ // or is found in case of recovery
+// if ( pSk1 == EOX ) return TRUE;
+
+
+ // according to recovery, it may be in one of two states
+
+ if ( pStk1->GetState() == 0 && // first state, evaluates the left operand
+ !m_leftop->Execute(pStk1) ) return FALSE; // interrupted here?
+
+ // passes to the next step
+ pStk1->SetState(1); // ready for further
+
+ // requires a little more stack to not touch the result of the left
+ // which is on the stack, precisely.
+
+ CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack
+ // or is found in case of recovery
+
+ // Second state, evaluates the right operand
+ if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrupted here?
+
+ int type1 = pStk1->GetType(); // what kind of results?
+ int type2 = pStk2->GetType();
+
+ // creates a temporary variable to put the result
+ CBotVar* result = new CBotVar( NULL, MAX(type1, type2));
+
+ // is the operation as requested
+ switch (GetTokenType())
+ {
+ case ID_ADD:
+ result->Add(pStk1->GetVar(), pStk2->GetVar()); // addition
+ break;
+ case ID_SUB:
+ result->Sub(pStk1->GetVar(), pStk2->GetVar()); // subtraction
+ break;
+ }
+ pStk2->SetVar(result); // puts the result on the stack
+
+ pStk1->Return(pStk2); // frees the stack
+ return pStack->Return(pStk1); // transmits the result
+}
+
+
diff --git a/src/CBot/CBotCompExpr.cpp b/src/CBot/CBotCompExpr.cpp
index 0f296d5..8ae507f 100644
--- a/src/CBot/CBotCompExpr.cpp
+++ b/src/CBot/CBotCompExpr.cpp
@@ -1,131 +1,133 @@
-// * 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/.///////////////////////////////////////////////////
-// expression du genre Opérande1 > Opérande2
-// Opérande1 != Opérande2
-// etc.
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotCompExpr::CBotCompExpr()
-{
- m_leftop =
- m_rightop = NULL;
- name = "CBotCompExpr";
-}
-
-CBotCompExpr::~CBotCompExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-fichier plus utilise;
-
-// compile une instruction de type A < B
-
-CBotInstr* CBotCompExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->AddStack();
-
- CBotInstr* left = CBotAddExpr::Compile( p, pStk ); // expression A + B à gauche
- if (left == NULL) return pStack->Return(NULL, pStk); // erreur
-
- if ( p->GetType() == ID_HI ||
- p->GetType() == ID_LO ||
- p->GetType() == ID_HS ||
- p->GetType() == ID_LS ||
- p->GetType() == ID_EQ ||
- p->GetType() == ID_NE) // les diverses comparaisons
- {
- CBotCompExpr* inst = new CBotCompExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
- int type1, type2;
- type1 = pStack->GetType();
-
- p = p->Next();
- if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression A + B à droite
- {
- type2 = pStack->GetType();
- // les résultats sont-ils compatibles
- if ( type1 == type2 )
- {
- inst->m_leftop = left;
- pStk->SetVar(new CBotVar(NULL, CBotTypBoolean));
- // le résultat est un boolean
- return pStack->Return(inst, pStk);
- }
- }
-
- delete left;
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- return pStack->Return(left, pStk);
-}
-
-
-// fait l'opération
-
-bool CBotCompExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this);
-// if ( pStk1 == EOX ) return TRUE;
-
- if ( pStk1->GetState() == 0 && !m_leftop->Execute(pStk1) ) return FALSE; // interrompu ici ?
-
- pStk1->SetState(1); // opération terminée
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- CBotStack* pStk2 = pStk1->AddStack();
-
- if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrompu ici ?
-
- int type1 = pStk1->GetType();
- int type2 = pStk2->GetType();
-
- CBotVar* result = new CBotVar( NULL, CBotTypBoolean );
-
- switch (GetTokenType())
- {
- case ID_LO:
- result->Lo(pStk1->GetVar(), pStk2->GetVar()); // inférieur
- break;
- case ID_HI:
- result->Hi(pStk1->GetVar(), pStk2->GetVar()); // supérieur
- break;
- case ID_LS:
- result->Ls(pStk1->GetVar(), pStk2->GetVar()); // inférieur ou égal
- break;
- case ID_HS:
- result->Hs(pStk1->GetVar(), pStk2->GetVar()); // supérieur ou égal
- break;
- case ID_EQ:
- result->Eq(pStk1->GetVar(), pStk2->GetVar()); // égal
- break;
- case ID_NE:
- result->Ne(pStk1->GetVar(), pStk2->GetVar()); // différent
- break;
- }
- pStk2->SetVar(result); // met le résultat sur la pile
-
- pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk1); // transmet le résultat
-}
-
+// * 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/.
+
+///////////////////////////////////////////////////
+// expression of type Opérande1 > Opérande2
+// Opérande1 != Opérande2
+// etc.
+
+#include "CBot.h"
+
+// various constructeurs
+
+CBotCompExpr::CBotCompExpr()
+{
+ m_leftop =
+ m_rightop = NULL;
+ name = "CBotCompExpr";
+}
+
+CBotCompExpr::~CBotCompExpr()
+{
+ delete m_leftop;
+ delete m_rightop;
+}
+
+fichier plus utilise;
+
+// compile instruction of type A < B
+
+CBotInstr* CBotCompExpr::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->AddStack();
+
+ CBotInstr* left = CBotAddExpr::Compile( p, pStk ); // expression A + B left
+ if (left == NULL) return pStack->Return(NULL, pStk); // error
+
+ if ( p->GetType() == ID_HI ||
+ p->GetType() == ID_LO ||
+ p->GetType() == ID_HS ||
+ p->GetType() == ID_LS ||
+ p->GetType() == ID_EQ ||
+ p->GetType() == ID_NE) // the various comparisons
+ {
+ CBotCompExpr* inst = new CBotCompExpr(); // element for operation
+ inst->SetToken(p); // stores the operation
+
+ int type1, type2;
+ type1 = pStack->GetType();
+
+ p = p->Next();
+ if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression A + B right
+ {
+ type2 = pStack->GetType();
+ // are the results compatible
+ if ( type1 == type2 )
+ {
+ inst->m_leftop = left;
+ pStk->SetVar(new CBotVar(NULL, CBotTypBoolean));
+ // the result is a boolean
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ delete left;
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ return pStack->Return(left, pStk);
+}
+
+
+// perform the operation
+
+bool CBotCompExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this);
+// if ( pStk1 == EOX ) return TRUE;
+
+ if ( pStk1->GetState() == 0 && !m_leftop->Execute(pStk1) ) return FALSE; // interrupted here ?
+
+ pStk1->SetState(1); // finished
+
+ // requires a little more stack to not touch the result of the left
+ CBotStack* pStk2 = pStk1->AddStack();
+
+ if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrupted here ?
+
+ int type1 = pStk1->GetType();
+ int type2 = pStk2->GetType();
+
+ CBotVar* result = new CBotVar( NULL, CBotTypBoolean );
+
+ switch (GetTokenType())
+ {
+ case ID_LO:
+ result->Lo(pStk1->GetVar(), pStk2->GetVar()); // lower
+ break;
+ case ID_HI:
+ result->Hi(pStk1->GetVar(), pStk2->GetVar()); // higher
+ break;
+ case ID_LS:
+ result->Ls(pStk1->GetVar(), pStk2->GetVar()); // lower or equal
+ break;
+ case ID_HS:
+ result->Hs(pStk1->GetVar(), pStk2->GetVar()); // higher of equal
+ break;
+ case ID_EQ:
+ result->Eq(pStk1->GetVar(), pStk2->GetVar()); // equal
+ break;
+ case ID_NE:
+ result->Ne(pStk1->GetVar(), pStk2->GetVar()); // not equal
+ break;
+ }
+ pStk2->SetVar(result); // puts the result on the stack
+
+ pStk1->Return(pStk2); // frees the stack
+ return pStack->Return(pStk1); // transmit the result
+}
+
diff --git a/src/CBot/CBotDll.h b/src/CBot/CBotDll.h
index 47388a6..269ef94 100644
--- a/src/CBot/CBotDll.h
+++ b/src/CBot/CBotDll.h
@@ -1,1117 +1,1117 @@
-// * 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/.
-////////////////////////////////////////////////////////////////////////
-
-#pragma once
-#ifndef _CBOTDLL_H_
-#define _CBOTDLL_H_
-/**
- * \file CBotDll.h
- * \brief Library for interpretation of CBOT language
- */
-
-#include <stdio.h>
-#include "resource.h"
-#include <map>
-#include <cstring>
-
-
-#define CBOTVERSION 104
-
-////////////////////////////////////////////////////////////////////////
-// forward declaration of needed classes
-
-class CBotToken; // program turned into "tokens
-class CBotStack; // for the execution stack
-class CBotClass; // class of object
-class CBotInstr; // instruction to be executed
-class CBotFunction; // user functions
-class CBotVar; // variables
-class CBotVarClass; // instance of class
-class CBotVarPointer; // pointer to an instance of class
-class CBotCall; // functions
-class CBotCallMethode; // methods
-class CBotDefParam; // parameter list
-class CBotCStack; // stack
-
-
-////////////////////////////////////////////////////////////////////////
-// Variables management
-////////////////////////////////////////////////////////////////////////
-
-/** \brief CBotType Defines known types. This types are modeled on Java types. Do not change the order of elements */
-enum CBotType
-{
- CBotTypVoid = 0,
- CBotTypByte = 1, //n
- CBotTypShort = 2, //n
- CBotTypChar = 3, //n
- CBotTypInt = 4,
- CBotTypLong = 5, //n
- CBotTypFloat = 6,
- CBotTypDouble = 7, //n
- CBotTypBoolean = 8,
- CBotTypString = 9,
-
- CBotTypArrayPointer = 10, // array of variables
- CBotTypArrayBody = 11, // same but creates an instance
-
- CBotTypPointer = 12, // pointer to an instance
- CBotTypNullPointer = 13, // null pointer is special
- CBotTypClass = 15,
- CBotTypIntrinsic = 16 // instance of a class intrinsic
-};
-//n = not implemented yet
-
-// for SetUserPtr when deleting an object
-#define OBJECTDELETED ((void*)-1)
-// value set before initialization
-#define OBJECTCREATED ((void*)-2)
-
-
-/** \brief CBotTypResult class to define the complete type of a result*/
-class CBotTypResult
-{
-public:
- /**
- * \brief CBotTypResult constructor for simple types (CBotTypInt to CBotTypString)
- * \param type type of created result, see CBotType
- */
- CBotTypResult(int type);
- // for simple types (CBotTypInt à CBotTypString)
-
-
- CBotTypResult(int type, const char* name);
- // for pointer types and intrinsic classes
-
- CBotTypResult(int type, CBotClass* pClass);
- // for the instance of a class
-
- CBotTypResult(int type, CBotTypResult elem);
- // for arrays of variables
-
- CBotTypResult(const CBotTypResult& typ);
- // for assignments
-
- CBotTypResult();
- // for default
-
- ~CBotTypResult();
-
- int GivType(int mode = 0) const;
- // returns type CBotType* as a result
-
- void SetType(int n);
- // modifies a type
-
- CBotClass* GivClass() const;
- // makes the pointer to the class (for CBotTypClass, CBotTypPointer)
-
- int GivLimite() const;
- // returns limit size of table (CBotTypArray)
-
- void SetLimite(int n);
- // set limit to the table
-
- void SetArray(int* max );
- // set limits for a list of dimensions (arrays of arrays)
-
- CBotTypResult& GivTypElem() const;
- // returns type of array elements (CBotTypArray)
- // rend le type des éléments du tableau (CBotTypArray)
-
- bool Compare(const CBotTypResult& typ) const;
- // compares whether the types are compatible
- bool Eq(int type) const;
- // compare type
-
- CBotTypResult& operator=(const CBotTypResult& src);
- // copy a complete type in another
-
-private:
- int m_type;
- CBotTypResult* m_pNext; // for the types of type
- CBotClass* m_pClass; // for the derivatives of class
- int m_limite; // limits of tables
- friend class CBotVarClass;
- friend class CBotVarPointer;
-};
-
-/*
-// to define a result as output, using for example
-
- // to return a simple Float
- return CBotTypResult( CBotTypFloat );
-
-
- // to return a string array
- return CBotTypResult( CBotTypArray, CBotTypResult( CBotTypString ) );
-
- // to return un array of array of "point" class
- CBotTypResult typPoint( CBotTypIntrinsic, "point" );
- CBotTypResult arrPoint( CBotTypArray, typPoint );
- return CBotTypResult( CBotTypArray, arrPoint );
-*/
-
-
-////////////////////////////////////////////////////////////////////////
-// Error Handling of compilation and execution
-////////////////////////////////////////////////////////////////////////
-
-// Here are the list of errors that can be returned by the module
-// for compilation
-
-#define CBotErrOpenPar 5000 // missing the opening parenthesis
-#define CBotErrClosePar 5001 // missing the closing parenthesis
-#define CBotErrNotBoolean 5002 // expression must be a boolean
-#define CBotErrUndefVar 5003 // undeclared variable
-#define CBotErrBadLeft 5004 // assignment impossible ( 5 = ... )
-#define CBotErrNoTerminator 5005 // semicolon expected
-#define CBotErrCaseOut 5006 // case outside a switch
-// CBotErrNoTerm 5007, plus utile
-#define CBotErrCloseBlock 5008 // missing " } "
-#define CBotErrElseWhitoutIf 5009 // else without matching if
-#define CBotErrOpenBlock 5010 // missing " { "
-#define CBotErrBadType1 5011 // wrong type for the assignment
-#define CBotErrRedefVar 5012 // redefinition of the variable
-#define CBotErrBadType2 5013 // Two operands are incompatible
-#define CBotErrUndefCall 5014 // routine undefined
-#define CBotErrNoDoubleDots 5015 // " : " expected
-// CBotErrWhile 5016, plus utile
-#define CBotErrBreakOutside 5017 // break outside of a loop
-#define CBotErrUndefLabel 5019 // label udnefined
-#define CBotErrLabel 5018 // label ne peut se mettre ici (label can not get here)
-#define CBotErrNoCase 5020 // missing " case "
-#define CBotErrBadNum 5021 // expected number
-#define CBotErrVoid 5022 // " void " not possible here
-#define CBotErrNoType 5023 // type declaration expected
-#define CBotErrNoVar 5024 // variable name expected
-#define CBotErrNoFunc 5025 // expected function name
-#define CBotErrOverParam 5026 // too many parameters
-#define CBotErrRedefFunc 5027 // this function already exists
-#define CBotErrLowParam 5028 // not enough parameters
-#define CBotErrBadParam 5029 // wrong types of parameters
-#define CBotErrNbParam 5030 // wrong number of parameters
-#define CBotErrUndefItem 5031 // element does not exist in the class
-#define CBotErrUndefClass 5032 // variable is not a class
-#define CBotErrNoConstruct 5033 // no appropriate constructor
-#define CBotErrRedefClass 5034 // class already exists
-#define CBotErrCloseIndex 5035 // " ] " expected
-#define CBotErrReserved 5036 // reserved word (for a DefineNum)
-#define CBotErrBadNew 5037 // wrong setting for new
-#define CBotErrOpenIndex 5038 // " [ " expected
-#define CBotErrBadString 5039 // expected string
-#define CBotErrBadIndex 5040 // wrong index type "[ false ]"
-#define CBotErrPrivate 5041 // protected item
-#define CBotErrNoPublic 5042 // missing word "public"
-
-// here is the list of errors that can be returned by the module
-// for the execution
-
-#define CBotErrZeroDiv 6000 // division by zero
-#define CBotErrNotInit 6001 // uninitialized variable
-#define CBotErrBadThrow 6002 // throw a negative value
-#define CBotErrNoRetVal 6003 // function did not return results
-#define CBotErrNoRun 6004 // Run() without active function
-#define CBotErrUndefFunc 6005 // calling a function that no longer exists
-#define CBotErrNotClass 6006 // this class does not exist
-#define CBotErrNull 6007 // null pointer
-#define CBotErrNan 6008 // calculation with a NAN
-#define CBotErrOutArray 6009 // index out of array
-#define CBotErrStackOver 6010 // stack overflow
-#define CBotErrDeletedPtr 6011 // pointer to an object destroyed
-
-#define CBotErrFileOpen 6012 // cannot open the file
-#define CBotErrNotOpen 6013 // channel not open
-#define CBotErrRead 6014 // error while reading
-#define CBotErrWrite 6015 // writing error
-
-
-// other values ​​may be returned
-// for example exceptions returned by external routines
-// and " throw " with any number.
-
-
-////////////////////////////////////////////////////////////////////////
-//
-// as part of MFC CString not used here.
-//
-// ( all functions are not implemented yet )
-
-/** \brief CBotString Class used to work on strings */
-class CBotString
-{
-public:
- CBotString();
- CBotString(const char* p);
- CBotString(const CBotString& p);
- ~CBotString();
-
- void Empty();
- bool IsEmpty() const;
- int GivLength();
- int Find(const char c);
- int Find(const char* lpsz);
- int ReverseFind(const char c);
- int ReverseFind(const char* lpsz);
- bool LoadString(unsigned int id);
- CBotString Mid(int nFirst, int nCount) const;
- CBotString Mid(int nFirst) const;
- CBotString Mid(int start, int lg=-1);
- CBotString Left(int nCount) const;
- CBotString Right(int nCount) const;
- int Compare(const char* lpsz) const;
- void MakeUpper();
- void MakeLower();
-
-
- /**
- * \brief Overloaded oprators to work on CBotString classes
- */
- const CBotString& operator=(const CBotString& stringSrc);
- const CBotString& operator=(const char ch);
- const CBotString& operator=(const char* pString);
- const CBotString& operator+(const CBotString& str);
- friend CBotString operator+(const CBotString& string, const char* lpsz);
-
- const CBotString& operator+=(const char ch);
- const CBotString& operator+=(const CBotString& str);
- bool operator==(const CBotString& str);
- bool operator==(const char* p);
- bool operator!=(const CBotString& str);
- bool operator!=(const char* p);
- bool operator>(const CBotString& str);
- bool operator>(const char* p);
- bool operator>=(const CBotString& str);
- bool operator>=(const char* p);
- bool operator<(const CBotString& str);
- bool operator<(const char* p);
- bool operator<=(const CBotString& str);
- bool operator<=(const char* p);
-
- operator const char*() const; // as a C string
-
-
-private:
-
- /** \brief Pointer to string */
- char* m_ptr;
-
- /** \brief Length of the string */
- int m_lg;
-
- /** \brief Keeps the string corresponding to keyword ID */
- static const std::map<EID, char *> s_keywordString;
-
- /**
- * \brief MapIdToString maps given ID to its string equivalent
- * \param id Provided identifier
- * \return string if found, else NullString
- */
- static const char * MapIdToString(EID id);
-};
-
-
-// Class used to array management
-
-class CBotStringArray : public CBotString
-{
-private:
- int m_nSize; // number of elements
- int m_nMaxSize; // reserved size
- CBotString* m_pData; // ^data
-
-public:
- CBotStringArray();
- ~CBotStringArray();
- void SetSize(int nb);
- int GivSize();
- void Add(const CBotString& str);
- CBotString& operator[](int nIndex);
-
- CBotString& ElementAt(int nIndex);
-};
-
-// different modes for GetPosition
-enum CBotGet
-{
- GetPosExtern = 1,
- GetPosNom = 2,
- GetPosParam = 3,
- GetPosBloc = 4
-};
-
-////////////////////////////////////////////////////////////////////
-// main class managing CBot program
-//
-
-class CBotProgram
-{
-private:
- CBotFunction* m_Prog; // the user-defined functions
- CBotFunction* m_pRun; // the basic function for the execution
- CBotClass* m_pClass; // classes defined in this part
- CBotStack* m_pStack; // execution stack
- CBotVar* m_pInstance; // instance of the parent class
- friend class CBotFunction;
-
- int m_ErrorCode;
- int m_ErrorStart;
- int m_ErrorEnd;
-
- long m_Ident; // associated identifier
-
-public:
- static CBotString m_DebugVarStr; // end of a debug
- bool m_bDebugDD; // idem déclanchable par robot \TODO ???
- bool m_bCompileClass;
-
-public:
- static void Init();
- // initializes the module (defined keywords for errors)
- // should be done once (and only one) at the beginning
- static
- void Free();
- // frees the static memory areas
-
- static
- int GivVersion();
- // gives the version of the library CBOT
-
-
- CBotProgram();
- CBotProgram(CBotVar* pInstance);
- ~CBotProgram();
-
- bool Compile( const char* program, CBotStringArray& ListFonctions, void* pUser = NULL);
- // compiles the program given in text
- // returns false if an error at compile
- // see GetCompileError () to retrieve the error
- // ListFonctions returns the names of functions declared as extern
- // pUser can pass a pointer to routines defined by AddFunction
-
- void SetIdent(long n);
- // associates an identifier with the instance CBotProgram
-
- long GivIdent();
- // gives the identifier
-
- int GivError();
- bool GetError(int& code, int& start, int& end);
- bool GetError(int& code, int& start, int& end, CBotProgram* &pProg);
- // if true
- // gives the error found in the compilation
- // or execution
- // delimits the start and end block where the error
- // pProg lets you know what "module" has produced runtime error
- static CBotString GivErrorText(int code);
-
-
- bool Start(const char* name);
- // defines what function should be executed
- // returns false if the funtion name is not found
- // the program does nothing, we must call Run () for this
-
- bool Run(void* pUser = NULL, int timer = -1);
- // executes the program
- // returns false if the program was suspended
- // returns true if the program ended with or without error
- // timer = 0 allows to advance step by step
-
- bool GetRunPos(const char* &FunctionName, int &start, int &end);
- // gives the position in the executing program
- // returns false if it is not running (program completion)
- // FunctionName is a pointer made to the name of the function
- // start and end position in the text of the token processing
-
- CBotVar* GivStackVars(const char* &FunctionName, int level);
- // provides the pointer to the variables on the execution stack
- // level is an input parameter, 0 for the last level, -1, -2, etc. for the other levels
- // the return value (CBotVar *) is a variable list (or NULL)
- // that can be processed as the list of parameters received by a routine
- // FunctionName gives the name of the function where are these variables
- // FunctionName == NULL means that is more in a program (depending on level)
-
- void Stop();
- // stops execution of the program
- // therefore quits "suspend" mode
-
- static
- void SetTimer(int n);
- // defines the number of steps (parts of instructions) to done
- // in Run() before rendering hand "false" \TODO avant de rendre la main "false"
-
- static
- bool AddFunction(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
- // call this to add externally (**)
- // a new function used by the program CBoT
-
- static
- bool DefineNum(const char* name, long val);
-
- bool SaveState(FILE* pf);
- // backup the execution status in the file
- // the file must have been opened with the fopen call this dll (\TODO this library??)
- // if the system crashes
- bool RestoreState(FILE* pf);
- // restores the state of execution from file
- // the compiled program must obviously be the same
-
- bool GetPosition(const char* name, int& start, int& stop,
- CBotGet modestart = GetPosExtern,
- CBotGet modestop = GetPosBloc);
- // gives the position of a routine in the original text
- // the user can select the item to find from the beginning to the end
- // see the above modes in CBotGet
-
-
- CBotFunction* GivFunctions();
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// routines for file management (* FILE)
- FILE* fOpen(const char* name, const char* mode);
- int fClose(FILE* filehandle);
- size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle);
- size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle);
-
-
-#if 0
-/*
-(**) Note:
- To define an external function, proceed as follows:
-
- a) define a routine for compilation
- this routine receive list of parameters (no values)
- and either returns a result type (CBotTyp... or 0 = void)
- or an error number
- b) define a routine for the execution
- this routine receive list of parameters (with valeurs),
- a variable to store the result (according to the given type at compile time)
-
- For example, a routine which calculates the mean of a parameter list */
-
-int cMean(CBotVar* &pVar, CBotString& ClassName)
-{
- if ( pVar == NULL ) return 6001; // there is no parameter!
-
- while ( pVar != NULL )
- {
- if ( pVar->GivType() > CBotTypDouble ) return 6002; // this is not a number
- pVar = pVar -> GivNext();
- }
-
- return CBotTypFloat; // the type of the result may depend on the parameters!
-}
-
-
-bool rMean(CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- float total = 0;
- int nb = 0;
- while (pVar != NULL)
- {
- total += pVar->GivValFloat();
- pVar = pVar->GivNext();
- nb++;
- }
- pResult->SetValFloat(total/nb); // returns the mean value
-
- return true; // operation fully completed
-}
-
-#endif
-
-/////////////////////////////////////////////////////////////////////////////////
-// Class for managing variables
-
-// may be useful to the outside of the module
-// ( it is currently not expected to be able to create these objects in outer )
-
-// results of GivInit()
-#define IS_UNDEF 0 // undefined variable
-#define IS_DEF 1 // variable defined
-#define IS_NAN 999 // variable defined as not a number
-
-// variable type SetPrivate / IsPrivate
-#define PR_PUBLIC 0 // public variable
-#define PR_READ 1 // read only
-#define PR_PROTECT 2 // protected (inheritance)
-#define PR_PRIVATE 3 // strictly private
-
-class CBotVar
-{
-protected:
- CBotToken* m_token; // the corresponding token
-
- CBotVar* m_next; // list of variables
- friend class CBotStack;
- friend class CBotCStack;
- friend class CBotInstrCall;
- friend class CBotProgram;
-
- CBotTypResult m_type; // type of value
-
- int m_binit; // not initialized?
- CBotVarClass* m_pMyThis; // ^ corresponding this element
- void* m_pUserPtr; // ^user data if necessary
- bool m_bStatic; // static element (in class)
- int m_mPrivate; // element public, protected or private?
-
- CBotInstr* m_InitExpr; // expression for the original content
- CBotInstr* m_LimExpr; // list of limits for a table
- friend class CBotClass;
- friend class CBotVarClass;
- friend class CBotVarPointer;
- friend class CBotVarArray;
-
- long m_ident; // unique identifier
- static long m_identcpt; // counter
-
-public:
- CBotVar();
-virtual ~CBotVar( ); // destructor
-
- static
- CBotVar* Create( const char* name, CBotTypResult type);
- // creates from a complete type
-
- static
- CBotVar* Create( const char* name, CBotClass* pClass);
- // creates from one instance of a known class
-
- static
- CBotVar* Create( const CBotToken* name, int type );
- static
- CBotVar* Create( const CBotToken* name, CBotTypResult type );
-
- static
- CBotVar* Create( const char* name, int type, CBotClass* pClass);
-
- static
- CBotVar* Create( CBotVar* pVar );
-
-
- void SetUserPtr(void* pUser);
- // associate a user pointer to an instance
-
- virtual void SetIdent(long UniqId);
- // associates a unique identifier to an instance
- // ( it is used to ensure that the id is unique)
-
- void* GivUserPtr();
- // makes the pointer associated with the variable
-
- CBotString GivName(); // the name of the variable, if known
- ////////////////////////////////////////////////////////////////////////////////////
- void SetName(const char* name); // changes the name of the variable
-
- int GivType(int mode = 0); // returns the base type (int) of the variable
- // TODO check it
- ////////////////////////////////////////////////////////////////////////////////////////
-
- CBotTypResult GivTypResult(int mode = 0); // returns the complete type of the variable
-
-
- CBotToken* GivToken();
- void SetType(CBotTypResult& type);
-
- void SetInit(int bInit); // is the variable in the state IS_UNDEF, IS_DEF, IS_NAN
-
- int GivInit(); // gives the state of the variable
-
- void SetStatic(bool bStatic);
- bool IsStatic();
-
- void SetPrivate(int mPrivate);
- bool IsPrivate(int mode = PR_PROTECT);
- int GivPrivate();
-
- virtual
- void ConstructorSet();
-
- void SetVal(CBotVar* var); // remprend une valeur
- // TODO remprend value
- virtual
- CBotVar* GivItem(const char* name); // returns an element of a class according to its name (*)
- virtual
- CBotVar* GivItemRef(int nIdent); // idem à partir du n° ref
- // TODO ditto from ref no.
- virtual
- CBotVar* GivItem(int row, bool bGrow = false);
-
- virtual
- CBotVar* GivItemList(); // lists the elements
-
- CBotVar* GivStaticVar(); // makes the pointer to the variable if it is static
-
- bool IsElemOfClass(const char* name);
- // said if the element belongs to the class "name"
- // makes true if the object is a subclass
-
- CBotVar* GivNext(); // next variable in the list (parameters)
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- void AddNext(CBotVar* pVar); // added to a list
-
- virtual
- void Copy(CBotVar* pSrc, bool bName = true); // makes a copy of the variable
-
- virtual void SetValInt(int val, const char* name = NULL);
- // initialized with an integer value (#)
- /////////////////////////////////////////////////////////////////////////////////
-
- virtual void SetValFloat(float val); // initialized with a real value (#)
- ////////////////////////////////////////////////////////////////////////////////
-
- virtual void SetValString(const char* p);// initialized with a string value (#)
- ////////////////////////////////////////////////////////////////////////////////
-
- virtual int GivValInt(); // request the full value (#)
- ////////////////////////////////////////////////////////////////////////
-
- virtual float GivValFloat(); // gets real value (#)
- ///////////////////////////////////////////////////////////////////////
-
- virtual
- CBotString GivValString(); // request the string value (#)
- ///////////////////////////////////////////////////////////////////////
-
- virtual void SetClass(CBotClass* pClass);
- virtual
- CBotClass* GivClass();
-
- virtual void SetPointer(CBotVar* p);
- virtual
- CBotVarClass* GivPointer();
-// virtual void SetIndirection(CBotVar* pVar);
-
- virtual void Add(CBotVar* left, CBotVar* right); // addition
- virtual void Sub(CBotVar* left, CBotVar* right); // subtraction
- virtual void Mul(CBotVar* left, CBotVar* right); // multiplication
- virtual int Div(CBotVar* left, CBotVar* right); // division
- virtual int Modulo(CBotVar* left, CBotVar* right); // remainder of division
- virtual void Power(CBotVar* left, CBotVar* right); // power
-
- virtual bool Lo(CBotVar* left, CBotVar* right);
- virtual bool Hi(CBotVar* left, CBotVar* right);
- virtual bool Ls(CBotVar* left, CBotVar* right);
- virtual bool Hs(CBotVar* left, CBotVar* right);
- virtual bool Eq(CBotVar* left, CBotVar* right);
- virtual bool Ne(CBotVar* left, CBotVar* right);
-
- virtual void And(CBotVar* left, CBotVar* right);
- virtual void Or(CBotVar* left, CBotVar* right);
- virtual void XOr(CBotVar* left, CBotVar* right);
- virtual void ASR(CBotVar* left, CBotVar* right);
- virtual void SR(CBotVar* left, CBotVar* right);
- virtual void SL(CBotVar* left, CBotVar* right);
-
- virtual void Neg();
- virtual void Not();
- virtual void Inc();
- virtual void Dec();
-
-
- virtual bool Save0State(FILE* pf);
- virtual bool Save1State(FILE* pf);
- static bool RestoreState(FILE* pf, CBotVar* &pVar);
-
- void debug();
-
-// virtual
-// CBotVar* GivMyThis();
-
- virtual
- void Maj(void* pUser = NULL, bool bContinue = true);
-
- void SetUniqNum(long n);
- long GivUniqNum();
- static long NextUniqNum();
-};
-
-/* NOTE (#)
- methods SetValInt() SetValFloat() et SetValString()
- can be called with objects which are respectively integer, real or string
- Always be sure of the type of the variable before calling these methods
-
- if ( pVar->GivType() == CBotInt() ) pVar->SetValFloat( 3.3 ); // plante !!
-
- methods GivValInt(), GivValFloat() et GivValString()
- use value conversions,
- GivValString() works on numbers (makes the corresponding string)
- but do not make GivValInt () with a string variable!
-*/
-
-
-
-////////////////////////////////////////////////////////////////////////
-// management of classes
-////////////////////////////////////////////////////////////////////////
-
-// class to define new classes in the language CBOT
-// for example to define the class CPoint (x, y)
-
-class CBotClass
-{
-private:
- static
- CBotClass* m_ExClass; // list of classes existing at a given time
- CBotClass* m_ExNext; // for this general list
- CBotClass* m_ExPrev; // for this general list
-
-private:
- CBotClass* m_pParent; // parent class
- CBotString m_name; // name of this class
- int m_nbVar; // number of variables in the chain
- CBotVar* m_pVar; // content of the class
- bool m_bIntrinsic; // intrinsic class
- CBotClass* m_next; // the string class
- CBotCallMethode* m_pCalls; // list of methods defined in external
- CBotFunction* m_pMethod; // compiled list of methods
- void (*m_rMaj) ( CBotVar* pThis, void* pUser );
- friend class CBotVarClass;
- int m_cptLock; // for Lock / UnLock
- int m_cptOne; // Lock for reentrancy
- CBotProgram* m_ProgInLock[5];// processes waiting for sync
-
-public:
- bool m_IsDef; // mark if is set or not
-
- CBotClass( const char* name,
- CBotClass* pParent, bool bIntrinsic = false ); // constructor
- // Once a class is created, it is known
- // around CBoT
- // intrinsic mode gives a class that is not managed by pointers
-
- ~CBotClass( ); // destructor
-
- bool AddFunction(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
- // this call allows to add as external (**)
- // new method used by the objects of this class
-
- bool AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) );
- // defines routine to be called to update the elements of the class
-
- bool AddItem(CBotString name, CBotTypResult type, int mPrivate = PR_PUBLIC);
- // adds an element to the class
-// bool AddItem(CBotString name, CBotClass* pClass);
- // the same for elements belonging to pClass
- bool AddItem(CBotVar* pVar);
- // adds an item by passing the pointer to an instance of a variable
- // the object is taken as is, so do not destroyed
-
-
-
- // adds an element by giving an element of type CBotVar
- void AddNext(CBotClass* pClass);
-
- CBotString GivName(); // gives the name of the class
- CBotClass* GivParent(); // gives the parent class (or NULL)
-
- // true if a class is derived (Extends) of another
- // return true also if the classes are identical
- bool IsChildOf(CBotClass* pClass);
-
- static
- CBotClass* Find(CBotToken* &pToken); // trouve une classe d'après son nom
- // return a class by it's its name
- static
- CBotClass* Find(const char* name);
-
- CBotVar* GivVar(); // return the list of variables
- CBotVar* GivItem(const char* name); // one of the variables according to its name
- CBotVar* GivItemRef(int nIdent);
-
- CBotTypResult CompileMethode(const char* name, CBotVar* pThis, CBotVar** ppParams,
- CBotCStack* pStack, long& nIdent);
-
- bool ExecuteMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotVar* &pResult, CBotStack* &pStack, CBotToken* pToken);
- void RestoreMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotStack* &pStack);
-
- // compiles a class declared by the user
- static
- CBotClass* Compile(CBotToken* &p, CBotCStack* pStack);
- static
- CBotClass* Compile1(CBotToken* &p, CBotCStack* pStack);
-
- bool CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond);
-
- bool IsIntrinsic();
- void Purge();
- static
- void Free();
-
- static
- bool SaveStaticState(FILE* pf);
-
- static
- bool RestoreStaticState(FILE* pf);
-
- bool Lock(CBotProgram* p);
- void Unlock();
- static
- void FreeLock(CBotProgram* p);
-
- bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
-
-};
-
-#define MAXDEFNUM 1000 // limited number of DefineNum
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Token management (tokens)
-
-#define TokenTypKeyWord 1 // a keyword of the language (see TokenKeyWord)
-#define TokenTypNum 2 // number
-#define TokenTypString 3 // string
-#define TokenTypVar 4 // a variable name
-#define TokenTypDef 5 // value according DefineNum
-
-#define TokenKeyWord 2000 // keywords of the language
-#define TokenKeyDeclare 2100 // keywords of declarations (int, float,..)
-#define TokenKeyVal 2200 // keywords representing the value (true, false, null, nan)
-#define TokenKeyOp 2300 // operators
-
-/** \class Responsible for token management */
-class CBotToken
-{
-private:
- static
- CBotStringArray m_ListKeyWords; // list of keywords of language
- static
- int m_ListIdKeyWords[200]; // the corresponding codes
-
- static
- CBotStringArray m_ListKeyDefine; // names defined by a DefineNum
- static
- long m_ListKeyNums[MAXDEFNUM]; // the ​​associated values
-
-private:
- CBotToken* m_next; // following in the list
- CBotToken* m_prev;
- int m_type; // type of Token
- long m_IdKeyWord; // number of the keyword if it is a
- // or value of the "define"
-
- CBotString m_Text; // word found as token
- CBotString m_Sep; // following separators
-
- int m_start; // position in the original text (program)
- int m_end; // the same for the end of the token
-
- /**
- * \brief Check whether given parameter is a keyword
- */
- static
- int GivKeyWords(const char* w); // is it a keyword?
- static
- bool GivKeyDefNum(const char* w, CBotToken* &token);
-
- /**
- * \brief Loads the list of keywords
- */
- static
- void LoadKeyWords();
-
-public:
- /**
- * \brief Constructors
- */
- CBotToken();
- CBotToken(const CBotToken* pSrc);
- CBotToken(const CBotString& mot, const CBotString& sep, int start=0, int end=0);
- CBotToken(const char* mot, const char* sep = NULL);
-
- /**
- * \brief Destructor
- */
- ~CBotToken();
- /**
- * \brief Returns the type of token
- */
- int GivType();
-
- /**
- * \brief makes the string corresponding to this token
- */
- CBotString& GivString();
-
- /**
- * \brief makes the following separator token
- */
- CBotString& GivSep();
-
- /**
- * \brief position of the beginning in the text
- */
- int GivStart();
- /**
- * \brief end position in the text
- */
- int GivEnd();
-
- /**
- * \brief gives the next token in the list
- */
- CBotToken* GivNext();
- /**
- * \brief gives the previous token in a list
- */
- CBotToken* GivPrev();
-
- /**
- * \brief transforms the entire program
- */
- static
- CBotToken* CompileTokens(const char* p, int& error);
-
- /**
- * \brief releases the list
- */
- static
- void Delete(CBotToken* pToken); // libère la liste
-
-
- // fonctions non utiles en export
- static
- bool DefineNum(const char* name, long val);
- void SetString(const char* name);
-
- void SetPos(int start, int end);
- long GivIdKey();
- /**
- * \brief adds a token (a copy)
- */
- void AddNext(CBotToken* p);
-
- /**
- * finds the next token
- */
- static
- CBotToken* NextToken(char* &program, int& error, bool first = false);
-
- const CBotToken&
- operator=(const CBotToken& src);
-
- static
- void Free();
-};
-
-
-
-#if 0
-////////////////////////////////////////////////////////////////////////
-// Examples of use
-// Definition classes and functions
-
-
-// define the global class CPoint
-// --------------------------------
- m_pClassPoint = new CBotClass("CPoint", NULL);
- // adds the component ".x"
- m_pClassPoint->AddItem("x", CBotTypResult(CBotTypFloat));
- // adds the component ".y"
- m_pClassPoint->AddItem("y", CBotTypResult(CBotTypFloat));
- // the player can then use the instructions
- // CPoint position; position.x = 12; position.y = -13.6
-
-// define class CColobotObject
-// --------------------------------
-// This class manages all the objects in the world of COLOBOT
-// the "main" user program belongs to this class
- m_pClassObject = new CBotClass("CColobotObject", m_pClassBase);
- // adds the component ".position"
- m_pClassObject->AddItem("position", m_pClassPoint);
- // adds the component ".type"
- m_pClassObject->AddItem("type", CBotTypResult(CBotTypShort));
- // adds a definition of constant
- m_pClassObject->AddConst("ROBOT", CBotTypShort, 1); // ROBOT equivalent to the value 1
- // adds the FIND routine
- m_pClassObject->AddFunction( rCompFind, rDoFind );
- // the player can now use the instructions
- // CColobotObject chose; chose = FIND( ROBOT )
-
-
-
-// define class CColobotRobot derived from CColobotObject
-// ---------------------------------------------------------
-// programs "main" associated with robots as a part of this class
- m_pClassRobot = new CBotClass("CColobotRobot", m_pClassObject);
- // add routine GOTO
- m_pClassRobot->AddFunction( rCompGoto, rDoGoto );
- // the player can now use
- // GOTO( FIND ( ROBOT ) );
-
-
-// creates an instance of the class Robot
-// ------------------------------------
-// for example a new robot which has just been manufactured
- CBotVar* m_pMonRobot = new CBotVar("MonRobot", m_pClassRobot);
-
-// compiles the program by hand for this robot
-// ------------------------------------------
- CString LeProgramme( "void main() {GOTO(0, 0); return 0;}" );
- if ( !m_pMonRobot->Compile( LeProgramme ) ) {error handling ...};
-
-// build a stack for interpreter
-// --------------------------------------
- CBotStack* pStack = new CBotStack(NULL);
-
-// executes the main program
-// -------------------------
- while( false = m_pMonRobot->Execute( "main", pStack ))
- {
- // program suspended
- // could be pass a handle to another (safeguarding pstack for the robot one)
- };
- // programme "main" finished !
-
-
-
-
-// routine that implements the GOTO (CPoint pos)
-bool rDoGoto( CBotVar* pVar, CBotVar* pResult, int& exception )
-{
- if (pVar->GivType() != CBotTypeClass ||
- pVar->IsElemOfClas("CPoint") ) { exception = 6522; return false; )
- // the parameter is not the right class?
- // in fact the control is done to the routine of compilation
-
- m_PosToGo.Copy( pVar ); // keeps the target position (object type CBotVar)
-
- // or so
- CBotVar* temp;
- temp = pVar->GivItem("x"); // is necessary for the object of type CPoint
- ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
- m_PosToGo.x = temp->GivValFloat();
-
- temp = pVar->GivItem("y"); // is necessary for the object of type CPoint
- ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
- m_PosToGo.y = temp->GivValFloat();
-
- return (m_CurentPos == m_PosToGo); // makes true if the position is reached
- // returns false if one had wait yet
-}
-
-#endif
-#endif //_CBOTDLL_H_
-
+// * 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/.
+////////////////////////////////////////////////////////////////////////
+
+#pragma once
+#ifndef _CBOTDLL_H_
+#define _CBOTDLL_H_
+/**
+ * \file CBotDll.h
+ * \brief Library for interpretation of CBOT language
+ */
+
+#include <stdio.h>
+#include "resource.h"
+#include <map>
+#include <cstring>
+
+
+#define CBOTVERSION 104
+
+////////////////////////////////////////////////////////////////////////
+// forward declaration of needed classes
+
+class CBotToken; // program turned into "tokens
+class CBotStack; // for the execution stack
+class CBotClass; // class of object
+class CBotInstr; // instruction to be executed
+class CBotFunction; // user functions
+class CBotVar; // variables
+class CBotVarClass; // instance of class
+class CBotVarPointer; // pointer to an instance of class
+class CBotCall; // functions
+class CBotCallMethode; // methods
+class CBotDefParam; // parameter list
+class CBotCStack; // stack
+
+
+////////////////////////////////////////////////////////////////////////
+// Variables management
+////////////////////////////////////////////////////////////////////////
+
+/** \brief CBotType Defines known types. This types are modeled on Java types. Do not change the order of elements */
+enum CBotType
+{
+ CBotTypVoid = 0,
+ CBotTypByte = 1, //n
+ CBotTypShort = 2, //n
+ CBotTypChar = 3, //n
+ CBotTypInt = 4,
+ CBotTypLong = 5, //n
+ CBotTypFloat = 6,
+ CBotTypDouble = 7, //n
+ CBotTypBoolean = 8,
+ CBotTypString = 9,
+
+ CBotTypArrayPointer = 10, // array of variables
+ CBotTypArrayBody = 11, // same but creates an instance
+
+ CBotTypPointer = 12, // pointer to an instance
+ CBotTypNullPointer = 13, // null pointer is special
+ CBotTypClass = 15,
+ CBotTypIntrinsic = 16 // instance of a class intrinsic
+};
+//n = not implemented yet
+
+// for SetUserPtr when deleting an object
+#define OBJECTDELETED ((void*)-1)
+// value set before initialization
+#define OBJECTCREATED ((void*)-2)
+
+
+/** \brief CBotTypResult class to define the complete type of a result*/
+class CBotTypResult
+{
+public:
+ /**
+ * \brief CBotTypResult constructor for simple types (CBotTypInt to CBotTypString)
+ * \param type type of created result, see CBotType
+ */
+ CBotTypResult(int type);
+ // for simple types (CBotTypInt à CBotTypString)
+
+
+ CBotTypResult(int type, const char* name);
+ // for pointer types and intrinsic classes
+
+ CBotTypResult(int type, CBotClass* pClass);
+ // for the instance of a class
+
+ CBotTypResult(int type, CBotTypResult elem);
+ // for arrays of variables
+
+ CBotTypResult(const CBotTypResult& typ);
+ // for assignments
+
+ CBotTypResult();
+ // for default
+
+ ~CBotTypResult();
+
+ int GivType(int mode = 0) const;
+ // returns type CBotType* as a result
+
+ void SetType(int n);
+ // modifies a type
+
+ CBotClass* GivClass() const;
+ // makes the pointer to the class (for CBotTypClass, CBotTypPointer)
+
+ int GivLimite() const;
+ // returns limit size of table (CBotTypArray)
+
+ void SetLimite(int n);
+ // set limit to the table
+
+ void SetArray(int* max );
+ // set limits for a list of dimensions (arrays of arrays)
+
+ CBotTypResult& GivTypElem() const;
+ // returns type of array elements (CBotTypArray)
+ // rend le type des éléments du tableau (CBotTypArray)
+
+ bool Compare(const CBotTypResult& typ) const;
+ // compares whether the types are compatible
+ bool Eq(int type) const;
+ // compare type
+
+ CBotTypResult& operator=(const CBotTypResult& src);
+ // copy a complete type in another
+
+private:
+ int m_type;
+ CBotTypResult* m_pNext; // for the types of type
+ CBotClass* m_pClass; // for the derivatives of class
+ int m_limite; // limits of tables
+ friend class CBotVarClass;
+ friend class CBotVarPointer;
+};
+
+/*
+// to define a result as output, using for example
+
+ // to return a simple Float
+ return CBotTypResult( CBotTypFloat );
+
+
+ // to return a string array
+ return CBotTypResult( CBotTypArray, CBotTypResult( CBotTypString ) );
+
+ // to return un array of array of "point" class
+ CBotTypResult typPoint( CBotTypIntrinsic, "point" );
+ CBotTypResult arrPoint( CBotTypArray, typPoint );
+ return CBotTypResult( CBotTypArray, arrPoint );
+*/
+
+
+////////////////////////////////////////////////////////////////////////
+// Error Handling of compilation and execution
+////////////////////////////////////////////////////////////////////////
+
+// Here are the list of errors that can be returned by the module
+// for compilation
+
+#define CBotErrOpenPar 5000 // missing the opening parenthesis
+#define CBotErrClosePar 5001 // missing the closing parenthesis
+#define CBotErrNotBoolean 5002 // expression must be a boolean
+#define CBotErrUndefVar 5003 // undeclared variable
+#define CBotErrBadLeft 5004 // assignment impossible ( 5 = ... )
+#define CBotErrNoTerminator 5005 // semicolon expected
+#define CBotErrCaseOut 5006 // case outside a switch
+// CBotErrNoTerm 5007, plus utile
+#define CBotErrCloseBlock 5008 // missing " } "
+#define CBotErrElseWhitoutIf 5009 // else without matching if
+#define CBotErrOpenBlock 5010 // missing " { "
+#define CBotErrBadType1 5011 // wrong type for the assignment
+#define CBotErrRedefVar 5012 // redefinition of the variable
+#define CBotErrBadType2 5013 // Two operands are incompatible
+#define CBotErrUndefCall 5014 // routine undefined
+#define CBotErrNoDoubleDots 5015 // " : " expected
+// CBotErrWhile 5016, plus utile
+#define CBotErrBreakOutside 5017 // break outside of a loop
+#define CBotErrUndefLabel 5019 // label udnefined
+#define CBotErrLabel 5018 // label ne peut se mettre ici (label can not get here)
+#define CBotErrNoCase 5020 // missing " case "
+#define CBotErrBadNum 5021 // expected number
+#define CBotErrVoid 5022 // " void " not possible here
+#define CBotErrNoType 5023 // type declaration expected
+#define CBotErrNoVar 5024 // variable name expected
+#define CBotErrNoFunc 5025 // expected function name
+#define CBotErrOverParam 5026 // too many parameters
+#define CBotErrRedefFunc 5027 // this function already exists
+#define CBotErrLowParam 5028 // not enough parameters
+#define CBotErrBadParam 5029 // wrong types of parameters
+#define CBotErrNbParam 5030 // wrong number of parameters
+#define CBotErrUndefItem 5031 // element does not exist in the class
+#define CBotErrUndefClass 5032 // variable is not a class
+#define CBotErrNoConstruct 5033 // no appropriate constructor
+#define CBotErrRedefClass 5034 // class already exists
+#define CBotErrCloseIndex 5035 // " ] " expected
+#define CBotErrReserved 5036 // reserved word (for a DefineNum)
+#define CBotErrBadNew 5037 // wrong setting for new
+#define CBotErrOpenIndex 5038 // " [ " expected
+#define CBotErrBadString 5039 // expected string
+#define CBotErrBadIndex 5040 // wrong index type "[ false ]"
+#define CBotErrPrivate 5041 // protected item
+#define CBotErrNoPublic 5042 // missing word "public"
+
+// here is the list of errors that can be returned by the module
+// for the execution
+
+#define CBotErrZeroDiv 6000 // division by zero
+#define CBotErrNotInit 6001 // uninitialized variable
+#define CBotErrBadThrow 6002 // throw a negative value
+#define CBotErrNoRetVal 6003 // function did not return results
+#define CBotErrNoRun 6004 // Run() without active function
+#define CBotErrUndefFunc 6005 // calling a function that no longer exists
+#define CBotErrNotClass 6006 // this class does not exist
+#define CBotErrNull 6007 // null pointer
+#define CBotErrNan 6008 // calculation with a NAN
+#define CBotErrOutArray 6009 // index out of array
+#define CBotErrStackOver 6010 // stack overflow
+#define CBotErrDeletedPtr 6011 // pointer to an object destroyed
+
+#define CBotErrFileOpen 6012 // cannot open the file
+#define CBotErrNotOpen 6013 // channel not open
+#define CBotErrRead 6014 // error while reading
+#define CBotErrWrite 6015 // writing error
+
+
+// other values ​​may be returned
+// for example exceptions returned by external routines
+// and " throw " with any number.
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// as part of MFC CString not used here.
+//
+// ( all functions are not implemented yet )
+
+/** \brief CBotString Class used to work on strings */
+class CBotString
+{
+public:
+ CBotString();
+ CBotString(const char* p);
+ CBotString(const CBotString& p);
+ ~CBotString();
+
+ void Empty();
+ bool IsEmpty() const;
+ int GivLength();
+ int Find(const char c);
+ int Find(const char* lpsz);
+ int ReverseFind(const char c);
+ int ReverseFind(const char* lpsz);
+ bool LoadString(unsigned int id);
+ CBotString Mid(int nFirst, int nCount) const;
+ CBotString Mid(int nFirst) const;
+ CBotString Mid(int start, int lg=-1);
+ CBotString Left(int nCount) const;
+ CBotString Right(int nCount) const;
+ int Compare(const char* lpsz) const;
+ void MakeUpper();
+ void MakeLower();
+
+
+ /**
+ * \brief Overloaded oprators to work on CBotString classes
+ */
+ const CBotString& operator=(const CBotString& stringSrc);
+ const CBotString& operator=(const char ch);
+ const CBotString& operator=(const char* pString);
+ const CBotString& operator+(const CBotString& str);
+ friend CBotString operator+(const CBotString& string, const char* lpsz);
+
+ const CBotString& operator+=(const char ch);
+ const CBotString& operator+=(const CBotString& str);
+ bool operator==(const CBotString& str);
+ bool operator==(const char* p);
+ bool operator!=(const CBotString& str);
+ bool operator!=(const char* p);
+ bool operator>(const CBotString& str);
+ bool operator>(const char* p);
+ bool operator>=(const CBotString& str);
+ bool operator>=(const char* p);
+ bool operator<(const CBotString& str);
+ bool operator<(const char* p);
+ bool operator<=(const CBotString& str);
+ bool operator<=(const char* p);
+
+ operator const char*() const; // as a C string
+
+
+private:
+
+ /** \brief Pointer to string */
+ char* m_ptr;
+
+ /** \brief Length of the string */
+ int m_lg;
+
+ /** \brief Keeps the string corresponding to keyword ID */
+ static const std::map<EID, char *> s_keywordString;
+
+ /**
+ * \brief MapIdToString maps given ID to its string equivalent
+ * \param id Provided identifier
+ * \return string if found, else NullString
+ */
+ static const char * MapIdToString(EID id);
+};
+
+
+// Class used to array management
+
+class CBotStringArray : public CBotString
+{
+private:
+ int m_nSize; // number of elements
+ int m_nMaxSize; // reserved size
+ CBotString* m_pData; // ^data
+
+public:
+ CBotStringArray();
+ ~CBotStringArray();
+ void SetSize(int nb);
+ int GivSize();
+ void Add(const CBotString& str);
+ CBotString& operator[](int nIndex);
+
+ CBotString& ElementAt(int nIndex);
+};
+
+// different modes for GetPosition
+enum CBotGet
+{
+ GetPosExtern = 1,
+ GetPosNom = 2,
+ GetPosParam = 3,
+ GetPosBloc = 4
+};
+
+////////////////////////////////////////////////////////////////////
+// main class managing CBot program
+//
+
+class CBotProgram
+{
+private:
+ CBotFunction* m_Prog; // the user-defined functions
+ CBotFunction* m_pRun; // the basic function for the execution
+ CBotClass* m_pClass; // classes defined in this part
+ CBotStack* m_pStack; // execution stack
+ CBotVar* m_pInstance; // instance of the parent class
+ friend class CBotFunction;
+
+ int m_ErrorCode;
+ int m_ErrorStart;
+ int m_ErrorEnd;
+
+ long m_Ident; // associated identifier
+
+public:
+ static CBotString m_DebugVarStr; // end of a debug
+ bool m_bDebugDD; // idem déclanchable par robot \TODO ???
+ bool m_bCompileClass;
+
+public:
+ static void Init();
+ // initializes the module (defined keywords for errors)
+ // should be done once (and only one) at the beginning
+ static
+ void Free();
+ // frees the static memory areas
+
+ static
+ int GivVersion();
+ // gives the version of the library CBOT
+
+
+ CBotProgram();
+ CBotProgram(CBotVar* pInstance);
+ ~CBotProgram();
+
+ bool Compile( const char* program, CBotStringArray& ListFonctions, void* pUser = NULL);
+ // compiles the program given in text
+ // returns false if an error at compile
+ // see GetCompileError () to retrieve the error
+ // ListFonctions returns the names of functions declared as extern
+ // pUser can pass a pointer to routines defined by AddFunction
+
+ void SetIdent(long n);
+ // associates an identifier with the instance CBotProgram
+
+ long GivIdent();
+ // gives the identifier
+
+ int GivError();
+ bool GetError(int& code, int& start, int& end);
+ bool GetError(int& code, int& start, int& end, CBotProgram* &pProg);
+ // if true
+ // gives the error found in the compilation
+ // or execution
+ // delimits the start and end block where the error
+ // pProg lets you know what "module" has produced runtime error
+ static CBotString GivErrorText(int code);
+
+
+ bool Start(const char* name);
+ // defines what function should be executed
+ // returns false if the funtion name is not found
+ // the program does nothing, we must call Run () for this
+
+ bool Run(void* pUser = NULL, int timer = -1);
+ // executes the program
+ // returns false if the program was suspended
+ // returns true if the program ended with or without error
+ // timer = 0 allows to advance step by step
+
+ bool GetRunPos(const char* &FunctionName, int &start, int &end);
+ // gives the position in the executing program
+ // returns false if it is not running (program completion)
+ // FunctionName is a pointer made to the name of the function
+ // start and end position in the text of the token processing
+
+ CBotVar* GivStackVars(const char* &FunctionName, int level);
+ // provides the pointer to the variables on the execution stack
+ // level is an input parameter, 0 for the last level, -1, -2, etc. for the other levels
+ // the return value (CBotVar *) is a variable list (or NULL)
+ // that can be processed as the list of parameters received by a routine
+ // FunctionName gives the name of the function where are these variables
+ // FunctionName == NULL means that is more in a program (depending on level)
+
+ void Stop();
+ // stops execution of the program
+ // therefore quits "suspend" mode
+
+ static
+ void SetTimer(int n);
+ // defines the number of steps (parts of instructions) to done
+ // in Run() before rendering hand "false" \TODO avant de rendre la main "false"
+
+ static
+ bool AddFunction(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
+ // call this to add externally (**)
+ // a new function used by the program CBoT
+
+ static
+ bool DefineNum(const char* name, long val);
+
+ bool SaveState(FILE* pf);
+ // backup the execution status in the file
+ // the file must have been opened with the fopen call this dll (\TODO this library??)
+ // if the system crashes
+ bool RestoreState(FILE* pf);
+ // restores the state of execution from file
+ // the compiled program must obviously be the same
+
+ bool GetPosition(const char* name, int& start, int& stop,
+ CBotGet modestart = GetPosExtern,
+ CBotGet modestop = GetPosBloc);
+ // gives the position of a routine in the original text
+ // the user can select the item to find from the beginning to the end
+ // see the above modes in CBotGet
+
+
+ CBotFunction* GivFunctions();
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// routines for file management (* FILE)
+ FILE* fOpen(const char* name, const char* mode);
+ int fClose(FILE* filehandle);
+ size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle);
+ size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle);
+
+
+#if 0
+/*
+(**) Note:
+ To define an external function, proceed as follows:
+
+ a) define a routine for compilation
+ this routine receive list of parameters (no values)
+ and either returns a result type (CBotTyp... or 0 = void)
+ or an error number
+ b) define a routine for the execution
+ this routine receive list of parameters (with valeurs),
+ a variable to store the result (according to the given type at compile time)
+
+ For example, a routine which calculates the mean of a parameter list */
+
+int cMean(CBotVar* &pVar, CBotString& ClassName)
+{
+ if ( pVar == NULL ) return 6001; // there is no parameter!
+
+ while ( pVar != NULL )
+ {
+ if ( pVar->GivType() > CBotTypDouble ) return 6002; // this is not a number
+ pVar = pVar -> GivNext();
+ }
+
+ return CBotTypFloat; // the type of the result may depend on the parameters!
+}
+
+
+bool rMean(CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ float total = 0;
+ int nb = 0;
+ while (pVar != NULL)
+ {
+ total += pVar->GivValFloat();
+ pVar = pVar->GivNext();
+ nb++;
+ }
+ pResult->SetValFloat(total/nb); // returns the mean value
+
+ return true; // operation fully completed
+}
+
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////
+// Class for managing variables
+
+// may be useful to the outside of the module
+// ( it is currently not expected to be able to create these objects in outer )
+
+// results of GivInit()
+#define IS_UNDEF 0 // undefined variable
+#define IS_DEF 1 // variable defined
+#define IS_NAN 999 // variable defined as not a number
+
+// variable type SetPrivate / IsPrivate
+#define PR_PUBLIC 0 // public variable
+#define PR_READ 1 // read only
+#define PR_PROTECT 2 // protected (inheritance)
+#define PR_PRIVATE 3 // strictly private
+
+class CBotVar
+{
+protected:
+ CBotToken* m_token; // the corresponding token
+
+ CBotVar* m_next; // list of variables
+ friend class CBotStack;
+ friend class CBotCStack;
+ friend class CBotInstrCall;
+ friend class CBotProgram;
+
+ CBotTypResult m_type; // type of value
+
+ int m_binit; // not initialized?
+ CBotVarClass* m_pMyThis; // ^ corresponding this element
+ void* m_pUserPtr; // ^user data if necessary
+ bool m_bStatic; // static element (in class)
+ int m_mPrivate; // element public, protected or private?
+
+ CBotInstr* m_InitExpr; // expression for the original content
+ CBotInstr* m_LimExpr; // list of limits for a table
+ friend class CBotClass;
+ friend class CBotVarClass;
+ friend class CBotVarPointer;
+ friend class CBotVarArray;
+
+ long m_ident; // unique identifier
+ static long m_identcpt; // counter
+
+public:
+ CBotVar();
+virtual ~CBotVar( ); // destructor
+
+ static
+ CBotVar* Create( const char* name, CBotTypResult type);
+ // creates from a complete type
+
+ static
+ CBotVar* Create( const char* name, CBotClass* pClass);
+ // creates from one instance of a known class
+
+ static
+ CBotVar* Create( const CBotToken* name, int type );
+ static
+ CBotVar* Create( const CBotToken* name, CBotTypResult type );
+
+ static
+ CBotVar* Create( const char* name, int type, CBotClass* pClass);
+
+ static
+ CBotVar* Create( CBotVar* pVar );
+
+
+ void SetUserPtr(void* pUser);
+ // associate a user pointer to an instance
+
+ virtual void SetIdent(long UniqId);
+ // associates a unique identifier to an instance
+ // ( it is used to ensure that the id is unique)
+
+ void* GivUserPtr();
+ // makes the pointer associated with the variable
+
+ CBotString GivName(); // the name of the variable, if known
+ ////////////////////////////////////////////////////////////////////////////////////
+ void SetName(const char* name); // changes the name of the variable
+
+ int GivType(int mode = 0); // returns the base type (int) of the variable
+ // TODO check it
+ ////////////////////////////////////////////////////////////////////////////////////////
+
+ CBotTypResult GivTypResult(int mode = 0); // returns the complete type of the variable
+
+
+ CBotToken* GivToken();
+ void SetType(CBotTypResult& type);
+
+ void SetInit(int bInit); // is the variable in the state IS_UNDEF, IS_DEF, IS_NAN
+
+ int GivInit(); // gives the state of the variable
+
+ void SetStatic(bool bStatic);
+ bool IsStatic();
+
+ void SetPrivate(int mPrivate);
+ bool IsPrivate(int mode = PR_PROTECT);
+ int GivPrivate();
+
+ virtual
+ void ConstructorSet();
+
+ void SetVal(CBotVar* var); // remprend une valeur
+ // TODO remprend value
+ virtual
+ CBotVar* GivItem(const char* name); // returns an element of a class according to its name (*)
+ virtual
+ CBotVar* GivItemRef(int nIdent); // idem à partir du n° ref
+ // TODO ditto from ref no.
+ virtual
+ CBotVar* GivItem(int row, bool bGrow = false);
+
+ virtual
+ CBotVar* GivItemList(); // lists the elements
+
+ CBotVar* GivStaticVar(); // makes the pointer to the variable if it is static
+
+ bool IsElemOfClass(const char* name);
+ // said if the element belongs to the class "name"
+ // makes true if the object is a subclass
+
+ CBotVar* GivNext(); // next variable in the list (parameters)
+ ////////////////////////////////////////////////////////////////////////////////////////////
+
+ void AddNext(CBotVar* pVar); // added to a list
+
+ virtual
+ void Copy(CBotVar* pSrc, bool bName = true); // makes a copy of the variable
+
+ virtual void SetValInt(int val, const char* name = NULL);
+ // initialized with an integer value (#)
+ /////////////////////////////////////////////////////////////////////////////////
+
+ virtual void SetValFloat(float val); // initialized with a real value (#)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ virtual void SetValString(const char* p);// initialized with a string value (#)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ virtual int GivValInt(); // request the full value (#)
+ ////////////////////////////////////////////////////////////////////////
+
+ virtual float GivValFloat(); // gets real value (#)
+ ///////////////////////////////////////////////////////////////////////
+
+ virtual
+ CBotString GivValString(); // request the string value (#)
+ ///////////////////////////////////////////////////////////////////////
+
+ virtual void SetClass(CBotClass* pClass);
+ virtual
+ CBotClass* GivClass();
+
+ virtual void SetPointer(CBotVar* p);
+ virtual
+ CBotVarClass* GivPointer();
+// virtual void SetIndirection(CBotVar* pVar);
+
+ virtual void Add(CBotVar* left, CBotVar* right); // addition
+ virtual void Sub(CBotVar* left, CBotVar* right); // subtraction
+ virtual void Mul(CBotVar* left, CBotVar* right); // multiplication
+ virtual int Div(CBotVar* left, CBotVar* right); // division
+ virtual int Modulo(CBotVar* left, CBotVar* right); // remainder of division
+ virtual void Power(CBotVar* left, CBotVar* right); // power
+
+ virtual bool Lo(CBotVar* left, CBotVar* right);
+ virtual bool Hi(CBotVar* left, CBotVar* right);
+ virtual bool Ls(CBotVar* left, CBotVar* right);
+ virtual bool Hs(CBotVar* left, CBotVar* right);
+ virtual bool Eq(CBotVar* left, CBotVar* right);
+ virtual bool Ne(CBotVar* left, CBotVar* right);
+
+ virtual void And(CBotVar* left, CBotVar* right);
+ virtual void Or(CBotVar* left, CBotVar* right);
+ virtual void XOr(CBotVar* left, CBotVar* right);
+ virtual void ASR(CBotVar* left, CBotVar* right);
+ virtual void SR(CBotVar* left, CBotVar* right);
+ virtual void SL(CBotVar* left, CBotVar* right);
+
+ virtual void Neg();
+ virtual void Not();
+ virtual void Inc();
+ virtual void Dec();
+
+
+ virtual bool Save0State(FILE* pf);
+ virtual bool Save1State(FILE* pf);
+ static bool RestoreState(FILE* pf, CBotVar* &pVar);
+
+ void debug();
+
+// virtual
+// CBotVar* GivMyThis();
+
+ virtual
+ void Maj(void* pUser = NULL, bool bContinue = true);
+
+ void SetUniqNum(long n);
+ long GivUniqNum();
+ static long NextUniqNum();
+};
+
+/* NOTE (#)
+ methods SetValInt() SetValFloat() et SetValString()
+ can be called with objects which are respectively integer, real or string
+ Always be sure of the type of the variable before calling these methods
+
+ if ( pVar->GivType() == CBotInt() ) pVar->SetValFloat( 3.3 ); // plante !!
+
+ methods GivValInt(), GivValFloat() et GivValString()
+ use value conversions,
+ GivValString() works on numbers (makes the corresponding string)
+ but do not make GivValInt () with a string variable!
+*/
+
+
+
+////////////////////////////////////////////////////////////////////////
+// management of classes
+////////////////////////////////////////////////////////////////////////
+
+// class to define new classes in the language CBOT
+// for example to define the class CPoint (x, y)
+
+class CBotClass
+{
+private:
+ static
+ CBotClass* m_ExClass; // list of classes existing at a given time
+ CBotClass* m_ExNext; // for this general list
+ CBotClass* m_ExPrev; // for this general list
+
+private:
+ CBotClass* m_pParent; // parent class
+ CBotString m_name; // name of this class
+ int m_nbVar; // number of variables in the chain
+ CBotVar* m_pVar; // content of the class
+ bool m_bIntrinsic; // intrinsic class
+ CBotClass* m_next; // the string class
+ CBotCallMethode* m_pCalls; // list of methods defined in external
+ CBotFunction* m_pMethod; // compiled list of methods
+ void (*m_rMaj) ( CBotVar* pThis, void* pUser );
+ friend class CBotVarClass;
+ int m_cptLock; // for Lock / UnLock
+ int m_cptOne; // Lock for reentrancy
+ CBotProgram* m_ProgInLock[5];// processes waiting for sync
+
+public:
+ bool m_IsDef; // mark if is set or not
+
+ CBotClass( const char* name,
+ CBotClass* pParent, bool bIntrinsic = false ); // constructor
+ // Once a class is created, it is known
+ // around CBoT
+ // intrinsic mode gives a class that is not managed by pointers
+
+ ~CBotClass( ); // destructor
+
+ bool AddFunction(const char* name,
+ bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
+ CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
+ // this call allows to add as external (**)
+ // new method used by the objects of this class
+
+ bool AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) );
+ // defines routine to be called to update the elements of the class
+
+ bool AddItem(CBotString name, CBotTypResult type, int mPrivate = PR_PUBLIC);
+ // adds an element to the class
+// bool AddItem(CBotString name, CBotClass* pClass);
+ // the same for elements belonging to pClass
+ bool AddItem(CBotVar* pVar);
+ // adds an item by passing the pointer to an instance of a variable
+ // the object is taken as is, so do not destroyed
+
+
+
+ // adds an element by giving an element of type CBotVar
+ void AddNext(CBotClass* pClass);
+
+ CBotString GivName(); // gives the name of the class
+ CBotClass* GivParent(); // gives the parent class (or NULL)
+
+ // true if a class is derived (Extends) of another
+ // return true also if the classes are identical
+ bool IsChildOf(CBotClass* pClass);
+
+ static
+ CBotClass* Find(CBotToken* &pToken); // trouve une classe d'après son nom
+ // return a class by it's its name
+ static
+ CBotClass* Find(const char* name);
+
+ CBotVar* GivVar(); // return the list of variables
+ CBotVar* GivItem(const char* name); // one of the variables according to its name
+ CBotVar* GivItemRef(int nIdent);
+
+ CBotTypResult CompileMethode(const char* name, CBotVar* pThis, CBotVar** ppParams,
+ CBotCStack* pStack, long& nIdent);
+
+ bool ExecuteMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotVar* &pResult, CBotStack* &pStack, CBotToken* pToken);
+ void RestoreMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotStack* &pStack);
+
+ // compiles a class declared by the user
+ static
+ CBotClass* Compile(CBotToken* &p, CBotCStack* pStack);
+ static
+ CBotClass* Compile1(CBotToken* &p, CBotCStack* pStack);
+
+ bool CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond);
+
+ bool IsIntrinsic();
+ void Purge();
+ static
+ void Free();
+
+ static
+ bool SaveStaticState(FILE* pf);
+
+ static
+ bool RestoreStaticState(FILE* pf);
+
+ bool Lock(CBotProgram* p);
+ void Unlock();
+ static
+ void FreeLock(CBotProgram* p);
+
+ bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
+
+};
+
+#define MAXDEFNUM 1000 // limited number of DefineNum
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Token management (tokens)
+
+#define TokenTypKeyWord 1 // a keyword of the language (see TokenKeyWord)
+#define TokenTypNum 2 // number
+#define TokenTypString 3 // string
+#define TokenTypVar 4 // a variable name
+#define TokenTypDef 5 // value according DefineNum
+
+#define TokenKeyWord 2000 // keywords of the language
+#define TokenKeyDeclare 2100 // keywords of declarations (int, float,..)
+#define TokenKeyVal 2200 // keywords representing the value (true, false, null, nan)
+#define TokenKeyOp 2300 // operators
+
+/** \class Responsible for token management */
+class CBotToken
+{
+private:
+ static
+ CBotStringArray m_ListKeyWords; // list of keywords of language
+ static
+ int m_ListIdKeyWords[200]; // the corresponding codes
+
+ static
+ CBotStringArray m_ListKeyDefine; // names defined by a DefineNum
+ static
+ long m_ListKeyNums[MAXDEFNUM]; // the ​​associated values
+
+private:
+ CBotToken* m_next; // following in the list
+ CBotToken* m_prev;
+ int m_type; // type of Token
+ long m_IdKeyWord; // number of the keyword if it is a
+ // or value of the "define"
+
+ CBotString m_Text; // word found as token
+ CBotString m_Sep; // following separators
+
+ int m_start; // position in the original text (program)
+ int m_end; // the same for the end of the token
+
+ /**
+ * \brief Check whether given parameter is a keyword
+ */
+ static
+ int GivKeyWords(const char* w); // is it a keyword?
+ static
+ bool GivKeyDefNum(const char* w, CBotToken* &token);
+
+ /**
+ * \brief Loads the list of keywords
+ */
+ static
+ void LoadKeyWords();
+
+public:
+ /**
+ * \brief Constructors
+ */
+ CBotToken();
+ CBotToken(const CBotToken* pSrc);
+ CBotToken(const CBotString& mot, const CBotString& sep, int start=0, int end=0);
+ CBotToken(const char* mot, const char* sep = NULL);
+
+ /**
+ * \brief Destructor
+ */
+ ~CBotToken();
+ /**
+ * \brief Returns the type of token
+ */
+ int GivType();
+
+ /**
+ * \brief makes the string corresponding to this token
+ */
+ CBotString& GivString();
+
+ /**
+ * \brief makes the following separator token
+ */
+ CBotString& GivSep();
+
+ /**
+ * \brief position of the beginning in the text
+ */
+ int GivStart();
+ /**
+ * \brief end position in the text
+ */
+ int GivEnd();
+
+ /**
+ * \brief gives the next token in the list
+ */
+ CBotToken* GivNext();
+ /**
+ * \brief gives the previous token in a list
+ */
+ CBotToken* GivPrev();
+
+ /**
+ * \brief transforms the entire program
+ */
+ static
+ CBotToken* CompileTokens(const char* p, int& error);
+
+ /**
+ * \brief releases the list
+ */
+ static
+ void Delete(CBotToken* pToken); // libère la liste
+
+
+ // fonctions non utiles en export
+ static
+ bool DefineNum(const char* name, long val);
+ void SetString(const char* name);
+
+ void SetPos(int start, int end);
+ long GivIdKey();
+ /**
+ * \brief adds a token (a copy)
+ */
+ void AddNext(CBotToken* p);
+
+ /**
+ * finds the next token
+ */
+ static
+ CBotToken* NextToken(char* &program, int& error, bool first = false);
+
+ const CBotToken&
+ operator=(const CBotToken& src);
+
+ static
+ void Free();
+};
+
+
+
+#if 0
+////////////////////////////////////////////////////////////////////////
+// Examples of use
+// Definition classes and functions
+
+
+// define the global class CPoint
+// --------------------------------
+ m_pClassPoint = new CBotClass("CPoint", NULL);
+ // adds the component ".x"
+ m_pClassPoint->AddItem("x", CBotTypResult(CBotTypFloat));
+ // adds the component ".y"
+ m_pClassPoint->AddItem("y", CBotTypResult(CBotTypFloat));
+ // the player can then use the instructions
+ // CPoint position; position.x = 12; position.y = -13.6
+
+// define class CColobotObject
+// --------------------------------
+// This class manages all the objects in the world of COLOBOT
+// the "main" user program belongs to this class
+ m_pClassObject = new CBotClass("CColobotObject", m_pClassBase);
+ // adds the component ".position"
+ m_pClassObject->AddItem("position", m_pClassPoint);
+ // adds the component ".type"
+ m_pClassObject->AddItem("type", CBotTypResult(CBotTypShort));
+ // adds a definition of constant
+ m_pClassObject->AddConst("ROBOT", CBotTypShort, 1); // ROBOT equivalent to the value 1
+ // adds the FIND routine
+ m_pClassObject->AddFunction( rCompFind, rDoFind );
+ // the player can now use the instructions
+ // CColobotObject chose; chose = FIND( ROBOT )
+
+
+
+// define class CColobotRobot derived from CColobotObject
+// ---------------------------------------------------------
+// programs "main" associated with robots as a part of this class
+ m_pClassRobot = new CBotClass("CColobotRobot", m_pClassObject);
+ // add routine GOTO
+ m_pClassRobot->AddFunction( rCompGoto, rDoGoto );
+ // the player can now use
+ // GOTO( FIND ( ROBOT ) );
+
+
+// creates an instance of the class Robot
+// ------------------------------------
+// for example a new robot which has just been manufactured
+ CBotVar* m_pMonRobot = new CBotVar("MonRobot", m_pClassRobot);
+
+// compiles the program by hand for this robot
+// ------------------------------------------
+ CString LeProgramme( "void main() {GOTO(0, 0); return 0;}" );
+ if ( !m_pMonRobot->Compile( LeProgramme ) ) {error handling ...};
+
+// build a stack for interpreter
+// --------------------------------------
+ CBotStack* pStack = new CBotStack(NULL);
+
+// executes the main program
+// -------------------------
+ while( false = m_pMonRobot->Execute( "main", pStack ))
+ {
+ // program suspended
+ // could be pass a handle to another (safeguarding pstack for the robot one)
+ };
+ // programme "main" finished !
+
+
+
+
+// routine that implements the GOTO (CPoint pos)
+bool rDoGoto( CBotVar* pVar, CBotVar* pResult, int& exception )
+{
+ if (pVar->GivType() != CBotTypeClass ||
+ pVar->IsElemOfClas("CPoint") ) { exception = 6522; return false; )
+ // the parameter is not the right class?
+ // in fact the control is done to the routine of compilation
+
+ m_PosToGo.Copy( pVar ); // keeps the target position (object type CBotVar)
+
+ // or so
+ CBotVar* temp;
+ temp = pVar->GivItem("x"); // is necessary for the object of type CPoint
+ ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
+ m_PosToGo.x = temp->GivValFloat();
+
+ temp = pVar->GivItem("y"); // is necessary for the object of type CPoint
+ ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
+ m_PosToGo.y = temp->GivValFloat();
+
+ return (m_CurentPos == m_PosToGo); // makes true if the position is reached
+ // returns false if one had wait yet
+}
+
+#endif
+#endif //_CBOTDLL_H_
+
diff --git a/src/CBot/CBotFunction.cpp b/src/CBot/CBotFunction.cpp
index 363b939..756c6cb 100644
--- a/src/CBot/CBotFunction.cpp
+++ b/src/CBot/CBotFunction.cpp
@@ -1,1644 +1,1647 @@
-// * 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 des diverses fonctions déclarées par l'utilisateur
-//
-
-#include "CBot.h"
-
-// les divers constructeurs / destructeurs
-// pour libérer tout selon l'arbre établi
-CBotFunction::CBotFunction()
-{
- m_Param = NULL; // liste des paramètres vide
- m_Block = NULL; // le bloc d'instructions
- m_next = NULL; // les fonctions peuvent être chaînées
- m_bPublic = false; // fonction non publique
- m_bExtern = false; // fonction non externe
- m_nextpublic = NULL;
- m_prevpublic = NULL;
- m_pProg = NULL;
-// m_nThisIdent = 0;
- m_nFuncIdent = 0;
- m_bSynchro = false;
-}
-
-CBotFunction* CBotFunction::m_listPublic = NULL;
-
-CBotFunction::~CBotFunction()
-{
- delete m_Param; // liste des paramètres vide
- delete m_Block; // le bloc d'instructions
- delete m_next;
-
- // enlève de la liste publique s'il y a lieu
- if ( m_bPublic )
- {
- if ( m_nextpublic != NULL )
- {
- m_nextpublic->m_prevpublic = m_prevpublic;
- }
- if ( m_prevpublic != NULL)
- {
- m_prevpublic->m_nextpublic = m_nextpublic;
- }
- else
- {
- // si prev = next = null peut ne pas être dans la liste !
- if ( m_listPublic == this ) m_listPublic = m_nextpublic;
- }
- }
-}
-
-bool CBotFunction::IsPublic()
-{
- return m_bPublic;
-}
-
-bool CBotFunction::IsExtern()
-{
- return m_bExtern;
-}
-
-bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop)
-{
- start = m_extern.GivStart();
- stop = m_closeblk.GivEnd();
-
- if (modestart == GetPosExtern)
- {
- start = m_extern.GivStart();
- }
- if (modestop == GetPosExtern)
- {
- stop = m_extern.GivEnd();
- }
- if (modestart == GetPosNom)
- {
- start = m_token.GivStart();
- }
- if (modestop == GetPosNom)
- {
- stop = m_token.GivEnd();
- }
- if (modestart == GetPosParam)
- {
- start = m_openpar.GivStart();
- }
- if (modestop == GetPosParam)
- {
- stop = m_closepar.GivEnd();
- }
- if (modestart == GetPosBloc)
- {
- start = m_openblk.GivStart();
- }
- if (modestop == GetPosBloc)
- {
- stop = m_closeblk.GivEnd();
- }
-
- return true;
-}
-
-
-CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
-{
- while ( IsOfType( p, ID_OPBRK ) )
- {
- if ( !IsOfType( p, ID_CLBRK ) )
- {
- pile->SetError(TX_CLBRK, p->GivStart());
- return CBotTypResult( -1 );
- }
- type = CBotTypResult( CBotTypArrayPointer, type );
- }
- return type;
-}
-
-CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
-{
- CBotClass* pClass = NULL;
-
- switch (p->GivType())
- {
- case ID_INT:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
- case ID_FLOAT:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
- case ID_BOOLEAN:
- case ID_BOOL:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypBoolean ));
- case ID_STRING:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypString ));
- case ID_VOID:
- p = p->GivNext();
- return CBotTypResult( 0 );
-
- case TokenTypVar:
- pClass = CBotClass::Find(p);
- if ( pClass != NULL)
- {
- p = p->GivNext();
- return ArrayType(p, pile,
- pClass->IsIntrinsic() ?
- CBotTypResult( CBotTypIntrinsic, pClass ) :
- CBotTypResult( CBotTypPointer, pClass ) );
- }
- }
- return CBotTypResult( -1 );
-}
-
-// compile une nouvelle fonction
-// bLocal permet de mettre la déclaration des paramètres au même niveau
-// que le éléments appartenant à la classe pour les méthodes
-CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal)
-{
- CBotToken* pp;
- CBotFunction* func = finput;
- if ( func == NULL ) func = new CBotFunction();
-
- CBotCStack* pStk = pStack->TokenStack(p, bLocal);
-
-// func->m_nFuncIdent = CBotVar::NextUniqNum();
-
- while (true)
- {
- if ( IsOfType(p, ID_PUBLIC) )
- {
- func->m_bPublic = true;
- continue;
- }
- pp = p;
- if ( IsOfType(p, ID_EXTERN) )
- {
- func->m_extern = pp; // pour la position du mot "extern"
- func->m_bExtern = true;
-// func->m_bPublic = true; // donc aussi publique!
- continue;
- }
- break;
- }
-
- func->m_retToken = *p;
-// CBotClass* pClass;
- func->m_retTyp = TypeParam(p, pStk); // type du résultat
-
- if (func->m_retTyp.GivType() >= 0)
- {
- CBotToken* pp = p;
- func->m_token = *p;
-
- if ( IsOfType(p, ID_NOT) )
- {
- CBotToken d("~" + p->GivString());
- func->m_token = d;
- }
-
- // un nom de fonction est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe
- {
- func->m_MasterClass = pp->GivString();
- CBotClass* pClass = CBotClass::Find(pp);
- if ( pClass == NULL ) goto bad;
-
-// pp = p;
- func->m_token = *p;
- if (!IsOfType(p, TokenTypVar)) goto bad;
-
- }
- func->m_openpar = p;
- func->m_Param = CBotDefParam::Compile( p, pStk );
- func->m_closepar = p->GivPrev();
- if (pStk->IsOk())
- {
- pStk->SetRetType(func->m_retTyp); // pour savoir de quel type les return
-
- if (!func->m_MasterClass.IsEmpty())
- {
- // rend "this" connu
- CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass ));
- pThis->SetInit(2);
-// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() va pas
- pThis->SetUniqNum(-2);
- pStk->AddVar(pThis);
-
- // initialise les variables selon This
- // n'enregistre que le pointeur à la première,
- // le reste est chainé
- CBotVar* pv = pThis->GivItemList();
-// int num = 1;
- while (pv != NULL)
- {
- CBotVar* pcopy = CBotVar::Create(pv);
-// pcopy->SetInit(2);
- pcopy->Copy(pv);
- pcopy->SetPrivate(pv->GivPrivate());
-// pcopy->SetUniqNum(pv->GivUniqNum()); //num++);
- pStk->AddVar(pcopy);
- pv = pv->GivNext();
- }
- }
-
- // et compile le bloc d'instruction qui suit
- func->m_openblk = p;
- func->m_Block = CBotBlock::Compile(p, pStk, false);
- func->m_closeblk = p->GivPrev();
- if ( pStk->IsOk() )
- {
- if ( func->m_bPublic ) // fonction publique, la rend connue pour tous
- {
- CBotFunction::AddPublic(func);
- }
- return pStack->ReturnFunc(func, pStk);
- }
- }
- }
-bad:
- pStk->SetError(TX_NOFONC, p);
- }
- pStk->SetError(TX_NOTYP, p);
- if ( finput == NULL ) delete func;
- return pStack->ReturnFunc(NULL, pStk);
-}
-
-// pré-compile une nouvelle fonction
-CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
-{
- CBotFunction* func = new CBotFunction();
- func->m_nFuncIdent = CBotVar::NextUniqNum();
-
- CBotCStack* pStk = pStack->TokenStack(p, true);
-
- while (true)
- {
- if ( IsOfType(p, ID_PUBLIC) )
- {
- // func->m_bPublic = true; // sera fait en passe 2
- continue;
- }
- if ( IsOfType(p, ID_EXTERN) )
- {
- func->m_bExtern = true;
- continue;
- }
- break;
- }
-
- func->m_retToken = *p;
- func->m_retTyp = TypeParam(p, pStack); // type du résultat
-
- if (func->m_retTyp.GivType() >= 0)
- {
- CBotToken* pp = p;
- func->m_token = *p;
- // un nom de fonction est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe
- {
- func->m_MasterClass = pp->GivString();
- CBotClass* pClass = CBotClass::Find(pp);
- if ( pClass == NULL )
- {
- pStk->SetError(TX_NOCLASS, pp);
- goto bad;
- }
-
- pp = p;
- func->m_token = *p;
- if (!IsOfType(p, TokenTypVar)) goto bad;
-
- }
- func->m_Param = CBotDefParam::Compile( p, pStk );
- if (pStk->IsOk())
- {
- // regarde si la fonction existe ailleurs
- if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) &&
- ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) )
- {
- if (IsOfType(p, ID_OPBLK))
- {
- int level = 1;
- // et saute le bloc d'instructions qui suit
- do
- {
- int type = p->GivType();
- p = p->GivNext();
- if (type == ID_OPBLK) level++;
- if (type == ID_CLBLK) level--;
- }
- while (level > 0 && p != NULL);
-
- return pStack->ReturnFunc(func, pStk);
- }
- pStk->SetError(TX_OPENBLK, p);
- }
- }
- pStk->SetError(TX_REDEF, pp);
- }
-bad:
- pStk->SetError(TX_NOFONC, p);
- }
- pStk->SetError(TX_NOTYP, p);
- delete func;
- return pStack->ReturnFunc(NULL, pStk);
-}
-
-#ifdef _DEBUG
-static int xx = 0;
-#endif
-
-bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
-{
- CBotStack* pile = pj->AddStack(this, 2); // un bout de pile local à cette fonction
-// if ( pile == EOX ) return true;
-
- pile->SetBotCall(m_pProg); // bases pour les routines
-
- if ( pile->GivState() == 0 )
- {
- if ( !m_Param->Execute(ppVars, pile) ) return false; // défini les paramètres
- pile->IncState();
- }
-
- if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() )
- {
- // rend "this" connu
- CBotVar* pThis ;
- if ( pInstance == NULL )
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass ));
- pThis->SetInit(2);
- }
- else
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass ));
- pThis->SetPointer(pInstance);
- pThis->SetInit(2);
- }
-
-// pThis->SetUniqNum(m_nThisIdent);
- pThis->SetUniqNum(-2);
- pile->AddVar(pThis);
-
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return false;
-
- if ( !m_Block->Execute(pile) )
- {
- if ( pile->GivError() < 0 )
- pile->SetError( 0 );
- else
- return false;
- }
-
- return pj->Return(pile);
-}
-
-
-void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
-{
- CBotStack* pile = pj->RestoreStack(this); // un bout de pile local à cette fonction
- if ( pile == NULL ) return;
- CBotStack* pile2 = pile;
-
- pile->SetBotCall(m_pProg); // bases pour les routines
-
- if ( pile->GivBlock() < 2 )
- {
- CBotStack* pile2 = pile->RestoreStack(NULL); // un bout de pile local à cette fonction
- if ( pile2 == NULL ) return;
- pile->SetState(pile->GivState() + pile2->GivState());
- pile2->Delete();
- }
-
- m_Param->RestoreState(pile2, true); // les paramètres
-
- if ( !m_MasterClass.IsEmpty() )
- {
- CBotVar* pThis = pile->FindVar("this");
- pThis->SetInit(2);
- pThis->SetUniqNum(-2);
- }
-
- m_Block->RestoreState(pile2, true);
-}
-
-void CBotFunction::AddNext(CBotFunction* p)
-{
- CBotFunction* pp = this;
- while (pp->m_next != NULL) pp = pp->m_next;
-
- pp->m_next = p;
-}
-
-
-CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent)
-{
- nIdent = 0;
- CBotTypResult type;
-
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
- return type;
-}
-
-
-// trouve une fonction selon son identificateur unique
-// si l'identificateur n'est pas trouvé, cherche selon le nom et les paramètres
-
-CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic)
-{
- TypeOrError.SetType(TX_UNDEFCALL); // pas de routine de ce nom
- CBotFunction* pt;
-
- if ( nIdent )
- {
- if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- TypeOrError = pt->m_retTyp;
- return pt;
- }
- }
-
- // recherche dans la liste des fonctions publiques
-
- for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- TypeOrError = pt->m_retTyp;
- return pt;
- }
- }
- }
-
- if ( name == NULL ) return NULL;
-
- int delta = 99999; // cherche la signature la plus faible
- CBotFunction* pFunc = NULL; // la meilleure fonction trouvée
-
- if ( this != NULL )
- {
- for ( pt = this ; pt != NULL ; pt = pt->m_next )
- {
- if ( pt->m_token.GivString() == name )
- {
- int i = 0;
- int alpha = 0; // signature des paramètres
- // les paramètres sont-ils compatibles ?
- CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus
- CBotVar* pw = ppVars[i++]; // liste des paramètres fournis
- while ( pv != NULL && pw != NULL)
- {
- if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
- {
- if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
- break;
- }
- int d = pv->GivType() - pw->GivType(2);
- alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !!
-
- pv = pv->GivNext();
- pw = ppVars[i++];
- }
- if ( pw != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
- continue; // trop de paramètres
- }
- if ( pv != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
- continue; // pas assez de paramètres
- }
-
- if (alpha == 0) // signature parfaite
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // une meilleur signature ?
- {
- pFunc = pt;
- delta = alpha;
- }
- }
- }
- }
-
- if ( bPublic )
- {
- for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
- {
- if ( pt->m_token.GivString() == name )
- {
- int i = 0;
- int alpha = 0; // signature des paramètres
- // les paramètres sont-ils compatibles ?
- CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus
- CBotVar* pw = ppVars[i++]; // liste des paramètres fournis
- while ( pv != NULL && pw != NULL)
- {
- if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
- {
- if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
- break;
- }
- int d = pv->GivType() - pw->GivType(2);
- alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !!
-
- pv = pv->GivNext();
- pw = ppVars[i++];
- }
- if ( pw != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
- continue; // trop de paramètres
- }
- if ( pv != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
- continue; // pas assez de paramètres
- }
-
- if (alpha == 0) // signature parfaite
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // une meilleur signature ?
- {
- pFunc = pt;
- delta = alpha;
- }
- }
- }
- }
-
- if ( pFunc != NULL )
- {
- nIdent = pFunc->m_nFuncIdent;
- TypeOrError = pFunc->m_retTyp;
- return pFunc;
- }
- return NULL;
-}
-
-
-// fait un appel à une fonction
-
-int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
-{
- CBotTypResult type;
- CBotFunction* pt = NULL;
-
- pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- CBotStack* pStk1 = pStack->AddStack(pt, 2); // pour mettre "this"
-// if ( pStk1 == EOX ) return true;
-
- pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- if ( pStk1->IfStep() ) return false;
-
- CBotStack* pStk3 = pStk1->AddStack(NULL, true); // paramètres
-
- // prépare les paramètres sur la pile
-
- if ( pStk1->GivState() == 0 )
- {
- if ( !pt->m_MasterClass.IsEmpty() )
- {
- CBotVar* pInstance = m_pProg->m_pInstance;
- // rend "this" connu
- CBotVar* pThis ;
- if ( pInstance == NULL )
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass ));
- pThis->SetInit(2);
- }
- else
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass ));
- pThis->SetPointer(pInstance);
- pThis->SetInit(2);
- }
-
- pThis->SetUniqNum(-2);
- pStk1->AddVar(pThis);
-
- }
-
- // initialise les variables selon paramètres
- pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu
-
- pStk1->IncState();
- }
-
- // finalement exécute la fonction trouvée
-
- if ( !pStk3->GivRetVar( // remet le résultat sur la pile
- pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu
- {
- if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
- {
-#ifdef _DEBUG
- if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return false;
-#endif
- pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure
- }
- return false; // interrompu !
- }
-
- return pStack->Return( pStk3 );
- }
- return -1;
-}
-
-void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack)
-{
- CBotTypResult type;
- CBotFunction* pt = NULL;
- CBotStack* pStk1;
- CBotStack* pStk3;
-
- // recherche la fonction pour remettre l'identificateur ok
-
- pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- pStk1 = pStack->RestoreStack(pt);
- if ( pStk1 == NULL ) return;
-
- pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- if ( pStk1->GivBlock() < 2 )
- {
- CBotStack* pStk2 = pStk1->RestoreStack(NULL); // plus utilisé
- if ( pStk2 == NULL ) return;
- pStk3 = pStk2->RestoreStack(NULL);
- if ( pStk3 == NULL ) return;
- }
- else
- {
- pStk3 = pStk1->RestoreStack(NULL);
- if ( pStk3 == NULL ) return;
- }
-
- // prépare les paramètres sur la pile
-
- {
- if ( !pt->m_MasterClass.IsEmpty() )
- {
- CBotVar* pInstance = m_pProg->m_pInstance;
- // rend "this" connu
- CBotVar* pThis = pStk1->FindVar("this");
- pThis->SetInit(2);
- pThis->SetUniqNum(-2);
- }
- }
-
- if ( pStk1->GivState() == 0 )
- {
- pt->m_Param->RestoreState(pStk3, true);
- return;
- }
-
- // initialise les variables selon paramètres
- pt->m_Param->RestoreState(pStk3, false);
- pt->m_Block->RestoreState(pStk3, true);
- }
-}
-
-
-
-// fait un appel d'une méthode
-// note : this est déjà sur la pile, le pointeur pThis est juste là pour simplifier
-
-int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
-{
- CBotTypResult type;
- CBotProgram* pProgCurrent = pStack->GivBotCall();
-
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false);
-
- if ( pt != NULL )
- {
-// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack);
-
- CBotStack* pStk = pStack->AddStack(pt, 2);
-// if ( pStk == EOX ) return true;
-
- pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module
- CBotStack* pStk3 = pStk->AddStack(NULL, true); // pour mettre les paramètres passés
-
- // prépare les paramètres sur la pile
-
- if ( pStk->GivState() == 0 )
- {
- // met la variable "this" sur la pile
- CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
- pthis->Copy(pThis, false);
- pthis->SetUniqNum(-2); // valeur spéciale
- pStk->AddVar(pthis);
-
- CBotClass* pClass = pThis->GivClass()->GivParent();
- if ( pClass )
- {
- // met la variable "super" sur la pile
- CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer);
- psuper->Copy(pThis, false); // en fait identique à "this"
- psuper->SetUniqNum(-3); // valeur spéciale
- pStk->AddVar(psuper);
- }
- // initialise les variables selon paramètres
- pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu
- pStk->IncState();
- }
-
- if ( pStk->GivState() == 1 )
- {
- if ( pt->m_bSynchro )
- {
- CBotProgram* pProgBase = pStk->GivBotCall(true);
- if ( !pClass->Lock(pProgBase) ) return false; // attend de pouvoir
- }
- pStk->IncState();
- }
- // finalement appelle la fonction trouvée
-
- if ( !pStk3->GivRetVar( // remet le résultat sur la pile
- pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu
- {
- if ( !pStk3->IsOk() )
- {
- if ( pt->m_bSynchro )
- {
- pClass->Unlock(); // libère la fonction
- }
-
- if ( pt->m_pProg != pProgCurrent )
- {
- pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure
- }
- }
- return false; // interrompu !
- }
-
- if ( pt->m_bSynchro )
- {
- pClass->Unlock(); // libère la fonction
- }
-
- return pStack->Return( pStk3 );
- }
- return -1;
-}
-
-void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
-{
- CBotTypResult type;
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- CBotStack* pStk = pStack->RestoreStack(pt);
- if ( pStk == NULL ) return;
- pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- CBotVar* pthis = pStk->FindVar("this");
- pthis->SetUniqNum(-2);
-
- CBotStack* pStk3 = pStk->RestoreStack(NULL); // pour mettre les paramètres passés
- if ( pStk3 == NULL ) return;
-
- pt->m_Param->RestoreState(pStk3, true); // les paramètres
-
- if ( pStk->GivState() > 1 && // vérouillage est effectif ?
- pt->m_bSynchro )
- {
- CBotProgram* pProgBase = pStk->GivBotCall(true);
- pClass->Lock(pProgBase); // vérouille la classe
- }
-
- // finalement appelle la fonction trouvée
-
- pt->m_Block->RestoreState(pStk3, true); // interrompu !
- }
-}
-
-// regarde si la "signature" des paramètres est identique
-bool CBotFunction::CheckParam(CBotDefParam* pParam)
-{
- CBotDefParam* pp = m_Param;
- while ( pp != NULL && pParam != NULL )
- {
- CBotTypResult type1 = pp->GivType();
- CBotTypResult type2 = pParam->GivType();
- if ( !type1.Compare(type2) ) return false;
- pp = pp->GivNext();
- pParam = pParam->GivNext();
- }
- return ( pp == NULL && pParam == NULL );
-}
-
-CBotString CBotFunction::GivName()
-{
- return m_token.GivString();
-}
-
-CBotString CBotFunction::GivParams()
-{
- if ( m_Param == NULL ) return CBotString("()");
-
- CBotString params = "( ";
- CBotDefParam* p = m_Param; // liste des paramètres
-
- while (p != NULL)
- {
- params += p->GivParamString();
- p = p->GivNext();
- if ( p != NULL ) params += ", ";
- }
-
- params += " )";
- return params;
-}
-
-CBotFunction* CBotFunction::Next()
-{
- return m_next;
-}
-
-void CBotFunction::AddPublic(CBotFunction* func)
-{
- if ( m_listPublic != NULL )
- {
- func->m_nextpublic = m_listPublic;
- m_listPublic->m_prevpublic = func;
- }
- m_listPublic = func;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////
-// gestion des paramètres
-
-
-CBotDefParam::CBotDefParam()
-{
- m_next = NULL;
- m_nIdent = 0;
-}
-
-CBotDefParam::~CBotDefParam()
-{
- delete m_next;
-}
-
-
-// compile une liste de paramètres
-CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- // surtout pas de pStack->TokenStack ici
- // les variables déclarées doivent rester visibles par la suite
-
- pStack->SetStartError(p->GivStart());
-
- if (IsOfType(p, ID_OPENPAR))
- {
- CBotDefParam* list = NULL;
-
- while (!IsOfType(p, ID_CLOSEPAR))
- {
- CBotDefParam* param = new CBotDefParam();
- if (list == NULL) list = param;
- else list->AddNext(param); // ajoute à la liste
-
- CBotClass* pClass = NULL;//= CBotClass::Find(p);
- param->m_typename = p->GivString();
- CBotTypResult type = param->m_type = TypeParam(p, pStack);
-// if ( type == CBotTypPointer ) type = CBotTypClass; // il faut créer un nouvel objet
-
- if (param->m_type.GivType() > 0)
- {
- CBotToken* pp = p;
- param->m_token = *p;
- if (pStack->IsOk() && IsOfType(p, TokenTypVar) )
- {
-
- // variable déjà déclarée ?
- if (pStack->CheckVarLocal(pp))
- {
- pStack->SetError(TX_REDEFVAR, pp);
- break;
- }
-
- if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
- CBotVar* var = CBotVar::Create(pp->GivString(), type); // crée la variable
-// if ( pClass ) var->SetClass(pClass);
- var->SetInit(2); // la marque initialisée
- param->m_nIdent = CBotVar::NextUniqNum();
- var->SetUniqNum(param->m_nIdent);
- pStack->AddVar(var); // la place sur la pile
-
- if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR)
- continue;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStack->SetError(TX_NOTYP, p);
- delete list;
- return NULL;
- }
- return list;
- }
- pStack->SetError(TX_OPENPAR, p->GivStart());
- return NULL;
-}
-
-void CBotDefParam::AddNext(CBotDefParam* p)
-{
- CBotDefParam* pp = this;
- while (pp->m_next != NULL) pp = pp->m_next;
-
- pp->m_next = p;
-}
-
-
-bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
-{
- int i = 0;
- CBotDefParam* p = this;
-
- while ( p != NULL )
- {
- // crée une variable locale sur la pile
- CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type);
-
- // procède ainsi pour faire la transformation des types :
- if ( ppVars != NULL && ppVars[i] != NULL )
- {
- switch (p->m_type.GivType())
- {
- case CBotTypInt:
- newvar->SetValInt(ppVars[i]->GivValInt());
- break;
- case CBotTypFloat:
- newvar->SetValFloat(ppVars[i]->GivValFloat());
- break;
- case CBotTypString:
- newvar->SetValString(ppVars[i]->GivValString());
- break;
- case CBotTypBoolean:
- newvar->SetValInt(ppVars[i]->GivValInt());
- break;
- case CBotTypIntrinsic:
- ((CBotVarClass*)newvar)->Copy(ppVars[i], false);
- break;
- case CBotTypPointer:
- case CBotTypArrayPointer:
- {
- newvar->SetPointer(ppVars[i]->GivPointer());
- }
- break;
- default:
- ASM_TRAP();
- }
- }
- newvar->SetUniqNum(p->m_nIdent);
- pj->AddVar(newvar); // place la variable
- p = p->m_next;
- i++;
- }
-
- return true;
-}
-
-void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
-{
- int i = 0;
- CBotDefParam* p = this;
-
- while ( p != NULL )
- {
- // crée une variable locale sur la pile
- CBotVar* var = pj->FindVar(p->m_token.GivString());
- var->SetUniqNum(p->m_nIdent);
- p = p->m_next;
- }
-}
-
-int CBotDefParam::GivType()
-{
- return m_type.GivType();
-}
-
-CBotTypResult CBotDefParam::GivTypResult()
-{
- return m_type;
-}
-
-CBotDefParam* CBotDefParam::GivNext()
-{
- return m_next;
-}
-
-CBotString CBotDefParam::GivParamString()
-{
- CBotString param;
-
- param = m_typename;
- param += ' ';
-
- param += m_token.GivString();
- return param;
-}
-
-
-
-//////////////////////////////////////////////////////////////////////////
-// retour des paramètres
-
-CBotReturn::CBotReturn()
-{
- m_Instr = NULL;
- name = "CBotReturn"; // debug
-}
-
-CBotReturn::~CBotReturn()
-{
- delete m_Instr;
-}
-
-CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
-
- if (!IsOfType(p, ID_RETURN)) return NULL; // ne devrait jamais arriver
-
- CBotReturn* inst = new CBotReturn(); // crée l'objet
- inst->SetToken( pp );
-
- CBotTypResult type = pStack->GivRetType();
-
- if ( type.GivType() == 0 ) // retourne void ?
- {
- if ( IsOfType( p, ID_SEP ) ) return inst;
- pStack->SetError( TX_BADTYPE, pp );
- return NULL;
- }
-
- inst->m_Instr = CBotExpression::Compile(p, pStack);
- if ( pStack->IsOk() )
- {
- CBotTypResult retType = pStack->GivTypResult(2);
- if (TypeCompatible(retType, type, ID_ASS))
- {
- if ( IsOfType( p, ID_SEP ) )
- return inst;
-
- pStack->SetError(TX_ENDOF, p->GivStart());
- }
- pStack->SetError(TX_BADTYPE, p->GivStart());
- }
-
- delete inst;
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-bool CBotReturn::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return true;
-
- if ( pile->GivState() == 0 )
- {
- if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // évalue le résultat
- // le résultat est sur la pile
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return false;
-
- pile->SetBreak(3, CBotString());
- return pj->Return(pile);
-}
-
-void CBotReturn::RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState() == 0 )
- {
- if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // évalue le résultat
- return;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Les appels à ces fonctions
-
-CBotInstrCall::CBotInstrCall()
-{
- m_Parameters = NULL;
- m_nFuncIdent = 0;
- name = "CBotInstrCall";
-}
-
-CBotInstrCall::~CBotInstrCall()
-{
- delete m_Parameters;
-}
-
-CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotVar* ppVars[1000];
-
- int i = 0;
-
- CBotToken* pp = p;
- p = p->GivNext();
-
- pStack->SetStartError(p->GivStart());
- CBotCStack* pile = pStack;
-
- if ( IsOfType(p, ID_OPENPAR) )
- {
- int start, end;
- CBotInstrCall* inst = new CBotInstrCall();
- inst->SetToken(pp);
-
- // compile la liste des paramètres
- if (!IsOfType(p, ID_CLOSEPAR)) while (true)
- {
- start = p->GivStart();
- pile = pile->TokenStack(); // garde les résultats sur la pile
-
- CBotInstr* param = CBotExpression::Compile(p, pile);
- end = p->GivStart();
- if ( inst->m_Parameters == NULL ) inst->m_Parameters = param;
- else inst->m_Parameters->AddNext(param); // construit la liste
-
- if ( !pile->IsOk() )
- {
- delete inst;
- return pStack->Return(NULL, pile);
- }
-
- if ( param != NULL )
- {
- if ( pile->GivTypResult().Eq(99) )
- {
- delete pStack->TokenStack();
- pStack->SetError(TX_VOID, p->GivStart());
- delete inst;
- return NULL;
- }
- ppVars[i] = pile->GivVar();
- ppVars[i]->GivToken()->SetPos(start, end);
- i++;
-
- if (IsOfType(p, ID_COMMA)) continue; // saute la virgule
- if (IsOfType(p, ID_CLOSEPAR)) break;
- }
-
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- delete pStack->TokenStack();
- delete inst;
- return NULL;
- }
- ppVars[i] = NULL;
-
- // la routine est-elle connue ?
-// CBotClass* pClass = NULL;
- inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent);
- if ( inst->m_typRes.GivType() >= 20 )
- {
-// if (pVar2!=NULL) pp = pVar2->RetToken();
- pStack->SetError( inst->m_typRes.GivType(), pp );
- delete pStack->TokenStack();
- delete inst;
- return NULL;
- }
-
- delete pStack->TokenStack();
- if ( inst->m_typRes.GivType() > 0 )
- {
- CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
- pStack->SetVar(pRes); // pour connaître le type du résultat
- }
- else pStack->SetVar(NULL); // routine retourne void
-
- return inst;
- }
- p = pp;
- delete pStack->TokenStack();
- return NULL;
-}
-
-bool CBotInstrCall::Execute(CBotStack* &pj)
-{
- CBotVar* ppVars[1000];
- CBotStack* pile = pj->AddStack(this);
- if ( pile->StackOver() ) return pj->Return( pile );
-
- CBotStack* pile1 = 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 )
- {
- pile = pile->AddStack(); // de la place sur la pile pour les résultats
- if ( pile->GivState() == 0 )
- {
- if (!p->Execute(pile)) return false; // interrompu ici ?
- pile->SetState(1); // marque spéciale pour reconnaîre les paramètres
- }
- ppVars[i++] = pile->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotStack* pile2 = pile->AddStack();
- if ( pile2->IfStep() ) return false;
-
- if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return false; // interrompu
-
- return pj->Return(pile2); // libère toute la pile
-}
-
-void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- CBotStack* pile1 = pile;
-
- int i = 0;
- CBotVar* ppVars[1000];
- 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 )
- {
- pile = pile->RestoreStack(); // de la place sur la pile pour les résultats
- if ( pile == NULL ) return;
- if ( pile->GivState() == 0 )
- {
- p->RestoreState(pile, bMain); // interrompu ici !
- return;
- }
- ppVars[i++] = pile->GivVar(); // construit la liste des paramètres
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotStack* pile2 = pile->RestoreStack();
- if ( pile2 == NULL ) return;
-
- pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// déclaration des classes par l'utilisateur
-
-// pré-compile une nouvelle class
-// l'analyse est complète à l'execption du corps des routines
-
-CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
-{
- if ( !IsOfType(p, ID_PUBLIC) )
- {
- pStack->SetError(TX_NOPUBLIC, p);
- return NULL;
- }
-
- if ( !IsOfType(p, ID_CLASS) ) return NULL;
-
- CBotString name = p->GivString();
-
- CBotClass* pOld = CBotClass::Find(name);
- if ( pOld != NULL && pOld->m_IsDef )
- {
- pStack->SetError( TX_REDEFCLASS, p );
- return NULL;
- }
-
- // un nom pour la classe est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- CBotClass* pPapa = NULL;
- if ( IsOfType( p, ID_EXTENDS ) )
- {
- CBotString name = p->GivString();
- pPapa = CBotClass::Find(name);
-
- if (!IsOfType(p, TokenTypVar) || pPapa == NULL )
- {
- pStack->SetError( TX_NOCLASS, p );
- return NULL;
- }
- }
- CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld;
- classe->Purge(); // vide les anciennes définitions
- classe->m_IsDef = false; // définition en cours
-
- if ( !IsOfType( p, ID_OPBLK) )
- {
- pStack->SetError(TX_OPENBLK, p);
- return NULL;
- }
-
- while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
- {
- classe->CompileDefItem(p, pStack, false);
- }
-
- if (pStack->IsOk()) return classe;
- }
- pStack->SetError(TX_ENDOF, p);
- return NULL;
-}
-
-bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
-{
- bool bStatic = false;
- int mProtect = PR_PUBLIC;
- bool bSynchro = false;
-
- while (IsOfType(p, ID_SEP)) ;
-
- CBotTypResult type( -1 );
-
- if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true;
- CBotToken* pBase = p;
-
- if ( IsOfType(p, ID_STATIC) ) bStatic = true;
- if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC;
- if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE;
- if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT;
- if ( IsOfType(p, ID_STATIC) ) bStatic = true;
-
-// CBotClass* pClass = NULL;
- type = TypeParam(p, pStack); // type du résultat
-
- if ( type.Eq(-1) )
- {
- pStack->SetError(TX_NOTYP, p);
- return false;
- }
-
- while (pStack->IsOk())
- {
- CBotToken* pp = p;
- IsOfType(p, ID_NOT); // saute le ~ éventuel (destructeur)
-
- if (IsOfType(p, TokenTypVar))
- {
- CBotInstr* limites = NULL;
- while ( IsOfType( p, ID_OPBRK ) ) // un tableau ?
- {
- CBotInstr* i = NULL;
-
- if ( p->GivType() != ID_CLBRK )
- i = CBotExpression::Compile( p, pStack ); // expression pour la valeur
- else
- i = new CBotEmpty(); // spécial si pas de formule
-
- type = CBotTypResult(CBotTypArrayPointer, type);
-
- if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) )
- {
- pStack->SetError(TX_CLBRK, p->GivStart());
- return false;
- }
-
-/* CBotVar* pv = pStack->GivVar();
- if ( pv->GivType()>= CBotTypBoolean )
- {
- pStack->SetError(TX_BADTYPE, p->GivStart());
- return false;
- }*/
-
- if (limites == NULL) limites = i;
- else limites->AddNext3(i);
- }
-
- if ( p->GivType() == ID_OPENPAR )
- {
- if ( !bSecond )
- {
- p = pBase;
- CBotFunction* f =
- CBotFunction::Compile1(p, pStack, this);
-
- if ( f == NULL ) return false;
-
- if (m_pMethod == NULL) m_pMethod = f;
- else m_pMethod->AddNext(f);
- }
- else
- {
- // retrouve la méthode précompilée en passe 1
- CBotFunction* pf = m_pMethod;
- CBotFunction* prev = NULL;
- while ( pf != NULL )
- {
- if (pf->GivName() == pp->GivString()) break;
- prev = pf;
- pf = pf->Next();
- }
-
- bool bConstructor = (pp->GivString() == GivName());
- CBotCStack* pile = pStack->TokenStack(NULL, true);
-
- // rend "this" connu
- CBotToken TokenThis(CBotString("this"), CBotString());
- CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) );
- pThis->SetUniqNum(-2);
- pile->AddVar(pThis);
-
- if ( m_pParent )
- {
- // rend "super" connu
- CBotToken TokenSuper(CBotString("super"), CBotString());
- CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) );
- pThis->SetUniqNum(-3);
- pile->AddVar(pThis);
- }
-
-// int num = 1;
- CBotClass* my = this;
- while (my != NULL)
- {
- // place une copie des varibles de la classe (this) sur la pile
- CBotVar* pv = my->m_pVar;
- while (pv != NULL)
- {
- CBotVar* pcopy = CBotVar::Create(pv);
- pcopy->SetInit(!bConstructor || pv->IsStatic());
- pcopy->SetUniqNum(pv->GivUniqNum());
- pile->AddVar(pcopy);
- pv = pv->GivNext();
- }
- my = my->m_pParent;
- }
-
- // compile une méthode
- p = pBase;
- CBotFunction* f =
- CBotFunction::Compile(p, pile, NULL/*, false*/);
-
- if ( f != NULL )
- {
- f->m_pProg = pStack->GivBotCall();
- f->m_bSynchro = bSynchro;
- // remplace l'élément dans la chaîne
- f->m_next = pf->m_next;
- pf->m_next = NULL;
- delete pf;
- if (prev == NULL) m_pMethod = f;
- else prev->m_next = f;
- }
- pStack->Return(NULL, pile);
- }
-
- return pStack->IsOk();
- }
-
- // définition d'un élément
- if (type.Eq(0))
- {
- pStack->SetError(TX_ENDOF, p);
- return false;
- }
-
- CBotInstr* i = NULL;
- if ( IsOfType(p, ID_ASS ) )
- {
- if ( type.Eq(CBotTypArrayPointer) )
- {
- i = CBotListArray::Compile(p, pStack, type.GivTypElem());
- }
- else
- {
- // il y a une assignation à calculer
- i = CBotTwoOpExpr::Compile(p, pStack);
- }
- if ( !pStack->IsOk() ) return false;
- }
-
-
- if ( !bSecond )
- {
- CBotVar* pv = CBotVar::Create(pp->GivString(), type);
- pv -> SetStatic( bStatic );
- pv -> SetPrivate( mProtect );
-
- AddItem( pv );
-
- pv->m_InitExpr = i;
- pv->m_LimExpr = limites;
-
-
- if ( pv->IsStatic() && pv->m_InitExpr != NULL )
- {
- CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante
- while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // évalue l'expression sans timer
- pv->SetVal( pile->GivVar() ) ;
- pile->Delete();
- }
- }
- else
- delete i;
-
- if ( IsOfType(p, ID_COMMA) ) continue;
- if ( IsOfType(p, ID_SEP) ) break;
- }
- pStack->SetError(TX_ENDOF, p);
- }
- return pStack->IsOk();
-}
-
-
-CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- if ( !IsOfType(p, ID_PUBLIC) ) return NULL;
- if ( !IsOfType(p, ID_CLASS) ) return NULL;
-
- CBotString name = p->GivString();
-
- // un nom pour la classe est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- // la classe à été créée par Compile1
- CBotClass* pOld = CBotClass::Find(name);
-
- if ( IsOfType( p, ID_EXTENDS ) )
- {
- IsOfType(p, TokenTypVar); // forcément
- }
- IsOfType( p, ID_OPBLK); // forcément
-
- while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
- {
- pOld->CompileDefItem(p, pStack, true);
- }
-
- pOld->m_IsDef = true; // définition terminée
- if (pStack->IsOk()) return pOld;
- }
- pStack->SetError(TX_ENDOF, p);
- return NULL;
-}
+// * 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 functions declared by the user
+//
+
+#include "CBot.h"
+
+// various constructors / destructors
+// \TODO translation:to liberate all according to esteblished tree
+// pour libérer tout selon l'arbre établi
+CBotFunction::CBotFunction()
+{
+ m_Param = NULL; // empty parameter list
+ m_Block = NULL; // the instruction block
+ m_next = NULL; // functions can be chained
+ m_bPublic = false; // function not public
+ m_bExtern = false; // function not extern
+ m_nextpublic = NULL;
+ m_prevpublic = NULL;
+ m_pProg = NULL;
+// m_nThisIdent = 0;
+ m_nFuncIdent = 0;
+ m_bSynchro = false;
+}
+
+CBotFunction* CBotFunction::m_listPublic = NULL;
+
+CBotFunction::~CBotFunction()
+{
+ delete m_Param; // empty parameter list
+ delete m_Block; // the instruction block
+ delete m_next;
+
+ // remove public list if there is
+ if ( m_bPublic )
+ {
+ if ( m_nextpublic != NULL )
+ {
+ m_nextpublic->m_prevpublic = m_prevpublic;
+ }
+ if ( m_prevpublic != NULL)
+ {
+ m_prevpublic->m_nextpublic = m_nextpublic;
+ }
+ else
+ {
+ // if prev = next = null may not be in the list!
+ if ( m_listPublic == this ) m_listPublic = m_nextpublic;
+ }
+ }
+}
+
+bool CBotFunction::IsPublic()
+{
+ return m_bPublic;
+}
+
+bool CBotFunction::IsExtern()
+{
+ return m_bExtern;
+}
+
+bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop)
+{
+ start = m_extern.GivStart();
+ stop = m_closeblk.GivEnd();
+
+ if (modestart == GetPosExtern)
+ {
+ start = m_extern.GivStart();
+ }
+ if (modestop == GetPosExtern)
+ {
+ stop = m_extern.GivEnd();
+ }
+ if (modestart == GetPosNom)
+ {
+ start = m_token.GivStart();
+ }
+ if (modestop == GetPosNom)
+ {
+ stop = m_token.GivEnd();
+ }
+ if (modestart == GetPosParam)
+ {
+ start = m_openpar.GivStart();
+ }
+ if (modestop == GetPosParam)
+ {
+ stop = m_closepar.GivEnd();
+ }
+ if (modestart == GetPosBloc)
+ {
+ start = m_openblk.GivStart();
+ }
+ if (modestop == GetPosBloc)
+ {
+ stop = m_closeblk.GivEnd();
+ }
+
+ return true;
+}
+
+
+CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
+{
+ while ( IsOfType( p, ID_OPBRK ) )
+ {
+ if ( !IsOfType( p, ID_CLBRK ) )
+ {
+ pile->SetError(TX_CLBRK, p->GivStart());
+ return CBotTypResult( -1 );
+ }
+ type = CBotTypResult( CBotTypArrayPointer, type );
+ }
+ return type;
+}
+
+CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
+{
+ CBotClass* pClass = NULL;
+
+ switch (p->GivType())
+ {
+ case ID_INT:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
+ case ID_FLOAT:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
+ case ID_BOOLEAN:
+ case ID_BOOL:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypBoolean ));
+ case ID_STRING:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypString ));
+ case ID_VOID:
+ p = p->GivNext();
+ return CBotTypResult( 0 );
+
+ case TokenTypVar:
+ pClass = CBotClass::Find(p);
+ if ( pClass != NULL)
+ {
+ p = p->GivNext();
+ return ArrayType(p, pile,
+ pClass->IsIntrinsic() ?
+ CBotTypResult( CBotTypIntrinsic, pClass ) :
+ CBotTypResult( CBotTypPointer, pClass ) );
+ }
+ }
+ return CBotTypResult( -1 );
+}
+
+// compiles a new function
+// bLocal allows of the declaration of parameters on the same level
+// as the elements belonging to the class for methods
+CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal)
+{
+ CBotToken* pp;
+ CBotFunction* func = finput;
+ if ( func == NULL ) func = new CBotFunction();
+
+ CBotCStack* pStk = pStack->TokenStack(p, bLocal);
+
+// func->m_nFuncIdent = CBotVar::NextUniqNum();
+
+ while (true)
+ {
+ if ( IsOfType(p, ID_PUBLIC) )
+ {
+ func->m_bPublic = true;
+ continue;
+ }
+ pp = p;
+ if ( IsOfType(p, ID_EXTERN) )
+ {
+ func->m_extern = pp; // for the position of the word "extern"
+ func->m_bExtern = true;
+// func->m_bPublic = true; // therefore also public!
+ continue;
+ }
+ break;
+ }
+
+ func->m_retToken = *p;
+// CBotClass* pClass;
+ func->m_retTyp = TypeParam(p, pStk); // type of the result
+
+ if (func->m_retTyp.GivType() >= 0)
+ {
+ CBotToken* pp = p;
+ func->m_token = *p;
+
+ if ( IsOfType(p, ID_NOT) )
+ {
+ CBotToken d("~" + p->GivString());
+ func->m_token = d;
+ }
+
+ // un nom de fonction est-il là ?
+ if (IsOfType(p, TokenTypVar))
+ {
+ if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
+ {
+ func->m_MasterClass = pp->GivString();
+ CBotClass* pClass = CBotClass::Find(pp);
+ if ( pClass == NULL ) goto bad;
+
+// pp = p;
+ func->m_token = *p;
+ if (!IsOfType(p, TokenTypVar)) goto bad;
+
+ }
+ func->m_openpar = p;
+ func->m_Param = CBotDefParam::Compile( p, pStk );
+ func->m_closepar = p->GivPrev();
+ if (pStk->IsOk())
+ {
+ pStk->SetRetType(func->m_retTyp); // for knowledge what type returns
+
+ if (!func->m_MasterClass.IsEmpty())
+ {
+ // return "this" known
+ CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass ));
+ pThis->SetInit(2);
+// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() will not
+ pThis->SetUniqNum(-2);
+ pStk->AddVar(pThis);
+
+ // initialize variables acording to This
+ // only saves the pointer to the first,
+ // the rest is chained
+ CBotVar* pv = pThis->GivItemList();
+// int num = 1;
+ while (pv != NULL)
+ {
+ CBotVar* pcopy = CBotVar::Create(pv);
+// pcopy->SetInit(2);
+ pcopy->Copy(pv);
+ pcopy->SetPrivate(pv->GivPrivate());
+// pcopy->SetUniqNum(pv->GivUniqNum()); //num++);
+ pStk->AddVar(pcopy);
+ pv = pv->GivNext();
+ }
+ }
+
+ // and compiles the following instruction block
+ func->m_openblk = p;
+ func->m_Block = CBotBlock::Compile(p, pStk, false);
+ func->m_closeblk = p->GivPrev();
+ if ( pStk->IsOk() )
+ {
+ if ( func->m_bPublic ) // public function, return known for all
+ {
+ CBotFunction::AddPublic(func);
+ }
+ return pStack->ReturnFunc(func, pStk);
+ }
+ }
+ }
+bad:
+ pStk->SetError(TX_NOFONC, p);
+ }
+ pStk->SetError(TX_NOTYP, p);
+ if ( finput == NULL ) delete func;
+ return pStack->ReturnFunc(NULL, pStk);
+}
+
+// pre-compile a new function
+CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
+{
+ CBotFunction* func = new CBotFunction();
+ func->m_nFuncIdent = CBotVar::NextUniqNum();
+
+ CBotCStack* pStk = pStack->TokenStack(p, true);
+
+ while (true)
+ {
+ if ( IsOfType(p, ID_PUBLIC) )
+ {
+ // func->m_bPublic = true; // will be done in two passes
+ continue;
+ }
+ if ( IsOfType(p, ID_EXTERN) )
+ {
+ func->m_bExtern = true;
+ continue;
+ }
+ break;
+ }
+
+ func->m_retToken = *p;
+ func->m_retTyp = TypeParam(p, pStack); // type of the result
+
+ if (func->m_retTyp.GivType() >= 0)
+ {
+ CBotToken* pp = p;
+ func->m_token = *p;
+ // un nom de fonction est-il là ?
+ if (IsOfType(p, TokenTypVar))
+ {
+ if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
+ {
+ func->m_MasterClass = pp->GivString();
+ CBotClass* pClass = CBotClass::Find(pp);
+ if ( pClass == NULL )
+ {
+ pStk->SetError(TX_NOCLASS, pp);
+ goto bad;
+ }
+
+ pp = p;
+ func->m_token = *p;
+ if (!IsOfType(p, TokenTypVar)) goto bad;
+
+ }
+ func->m_Param = CBotDefParam::Compile( p, pStk );
+ if (pStk->IsOk())
+ {
+ // looks if the function exists elsewhere
+ if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) &&
+ ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) )
+ {
+ if (IsOfType(p, ID_OPBLK))
+ {
+ int level = 1;
+ // and skips the following instruction block
+ do
+ {
+ int type = p->GivType();
+ p = p->GivNext();
+ if (type == ID_OPBLK) level++;
+ if (type == ID_CLBLK) level--;
+ }
+ while (level > 0 && p != NULL);
+
+ return pStack->ReturnFunc(func, pStk);
+ }
+ pStk->SetError(TX_OPENBLK, p);
+ }
+ }
+ pStk->SetError(TX_REDEF, pp);
+ }
+bad:
+ pStk->SetError(TX_NOFONC, p);
+ }
+ pStk->SetError(TX_NOTYP, p);
+ delete func;
+ return pStack->ReturnFunc(NULL, pStk);
+}
+
+#ifdef _DEBUG
+static int xx = 0;
+#endif
+
+bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
+{
+ CBotStack* pile = pj->AddStack(this, 2); // one end of stack local to this function
+// if ( pile == EOX ) return true;
+
+ pile->SetBotCall(m_pProg); // bases for routines
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( !m_Param->Execute(ppVars, pile) ) return false; // define parameters
+ pile->IncState();
+ }
+
+ if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() )
+ {
+ // makes "this" known
+ CBotVar* pThis ;
+ if ( pInstance == NULL )
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass ));
+ pThis->SetInit(2);
+ }
+ else
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass ));
+ pThis->SetPointer(pInstance);
+ pThis->SetInit(2);
+ }
+
+// pThis->SetUniqNum(m_nThisIdent);
+ pThis->SetUniqNum(-2);
+ pile->AddVar(pThis);
+
+ pile->IncState();
+ }
+
+ if ( pile->IfStep() ) return false;
+
+ if ( !m_Block->Execute(pile) )
+ {
+ if ( pile->GivError() < 0 )
+ pile->SetError( 0 );
+ else
+ return false;
+ }
+
+ return pj->Return(pile);
+}
+
+
+void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
+{
+ CBotStack* pile = pj->RestoreStack(this); // one end of stack local to this function
+ if ( pile == NULL ) return;
+ CBotStack* pile2 = pile;
+
+ pile->SetBotCall(m_pProg); // bases for routines
+
+ if ( pile->GivBlock() < 2 )
+ {
+ CBotStack* pile2 = pile->RestoreStack(NULL); // one end of stack local to this function
+ if ( pile2 == NULL ) return;
+ pile->SetState(pile->GivState() + pile2->GivState());
+ pile2->Delete();
+ }
+
+ m_Param->RestoreState(pile2, true); // parameters
+
+ if ( !m_MasterClass.IsEmpty() )
+ {
+ CBotVar* pThis = pile->FindVar("this");
+ pThis->SetInit(2);
+ pThis->SetUniqNum(-2);
+ }
+
+ m_Block->RestoreState(pile2, true);
+}
+
+void CBotFunction::AddNext(CBotFunction* p)
+{
+ CBotFunction* pp = this;
+ while (pp->m_next != NULL) pp = pp->m_next;
+
+ pp->m_next = p;
+}
+
+
+CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent)
+{
+ nIdent = 0;
+ CBotTypResult type;
+
+ CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+ return type;
+}
+
+
+// is a function according to its unique identifier
+// if the identifier is not found, looking by name and parameters
+
+CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic)
+{
+ TypeOrError.SetType(TX_UNDEFCALL); // no routine of the name
+ CBotFunction* pt;
+
+ if ( nIdent )
+ {
+ if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+ }
+
+ // search the list of public functions
+
+ for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+ }
+ }
+
+ if ( name == NULL ) return NULL;
+
+ int delta = 99999; // seeks the lowest signature
+ CBotFunction* pFunc = NULL; // the best function found
+
+ if ( this != NULL )
+ {
+ for ( pt = this ; pt != NULL ; pt = pt->m_next )
+ {
+ if ( pt->m_token.GivString() == name )
+ {
+ int i = 0;
+ int alpha = 0; // signature of parameters
+ // parameters are compatible?
+ CBotDefParam* pv = pt->m_Param; // expected list of parameters
+ CBotVar* pw = ppVars[i++]; // provided list parameter
+ while ( pv != NULL && pw != NULL)
+ {
+ if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
+ {
+ if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
+ break;
+ }
+ int d = pv->GivType() - pw->GivType(2);
+ alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+
+ pv = pv->GivNext();
+ pw = ppVars[i++];
+ }
+ if ( pw != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
+ continue; // too many parameters
+ }
+ if ( pv != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
+ continue; // not enough parameters
+ }
+
+ if (alpha == 0) // perfect signature
+ {
+ nIdent = pt->m_nFuncIdent;
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+
+ if ( alpha < delta ) // a better signature?
+ {
+ pFunc = pt;
+ delta = alpha;
+ }
+ }
+ }
+ }
+
+ if ( bPublic )
+ {
+ for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
+ {
+ if ( pt->m_token.GivString() == name )
+ {
+ int i = 0;
+ int alpha = 0; // signature of parameters
+ // parameters sont-ils compatibles ?
+ CBotDefParam* pv = pt->m_Param; // list of expected parameters
+ CBotVar* pw = ppVars[i++]; // list of provided parameters
+ while ( pv != NULL && pw != NULL)
+ {
+ if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
+ {
+ if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
+ break;
+ }
+ int d = pv->GivType() - pw->GivType(2);
+ alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+
+ pv = pv->GivNext();
+ pw = ppVars[i++];
+ }
+ if ( pw != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
+ continue; // to many parameters
+ }
+ if ( pv != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
+ continue; // not enough parameters
+ }
+
+ if (alpha == 0) // perfect signature
+ {
+ nIdent = pt->m_nFuncIdent;
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+
+ if ( alpha < delta ) // a better signature?
+ {
+ pFunc = pt;
+ delta = alpha;
+ }
+ }
+ }
+ }
+
+ if ( pFunc != NULL )
+ {
+ nIdent = pFunc->m_nFuncIdent;
+ TypeOrError = pFunc->m_retTyp;
+ return pFunc;
+ }
+ return NULL;
+}
+
+
+// fait un appel à une fonction
+
+int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
+{
+ CBotTypResult type;
+ CBotFunction* pt = NULL;
+
+ pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+
+ if ( pt != NULL )
+ {
+ CBotStack* pStk1 = pStack->AddStack(pt, 2); // to put "this"
+// if ( pStk1 == EOX ) return true;
+
+ pStk1->SetBotCall(pt->m_pProg); // it may have changed module
+
+ if ( pStk1->IfStep() ) return false;
+
+ CBotStack* pStk3 = pStk1->AddStack(NULL, true); // parameters
+
+ // preparing parameters on the stack
+
+ if ( pStk1->GivState() == 0 )
+ {
+ if ( !pt->m_MasterClass.IsEmpty() )
+ {
+ CBotVar* pInstance = m_pProg->m_pInstance;
+ // make "this" known
+ CBotVar* pThis ;
+ if ( pInstance == NULL )
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass ));
+ pThis->SetInit(2);
+ }
+ else
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass ));
+ pThis->SetPointer(pInstance);
+ pThis->SetInit(2);
+ }
+
+ pThis->SetUniqNum(-2);
+ pStk1->AddVar(pThis);
+
+ }
+
+ // initializes the variables as parameters
+ pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted
+
+ pStk1->IncState();
+ }
+
+ // finally execution of the found function
+
+ if ( !pStk3->GivRetVar( // puts the result on the stack
+ pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted
+ {
+ if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
+ {
+#ifdef _DEBUG
+ if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return false;
+#endif
+ pStk3->SetPosError(pToken); // indicates the error on the procedure call
+ }
+ return false; // interrupt !
+ }
+
+ return pStack->Return( pStk3 );
+ }
+ return -1;
+}
+
+void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack)
+{
+ CBotTypResult type;
+ CBotFunction* pt = NULL;
+ CBotStack* pStk1;
+ CBotStack* pStk3;
+
+ // search function to return the ok identifier
+
+ pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+
+ if ( pt != NULL )
+ {
+ pStk1 = pStack->RestoreStack(pt);
+ if ( pStk1 == NULL ) return;
+
+ pStk1->SetBotCall(pt->m_pProg); // it may have changed module
+
+ if ( pStk1->GivBlock() < 2 )
+ {
+ CBotStack* pStk2 = pStk1->RestoreStack(NULL); // used more
+ if ( pStk2 == NULL ) return;
+ pStk3 = pStk2->RestoreStack(NULL);
+ if ( pStk3 == NULL ) return;
+ }
+ else
+ {
+ pStk3 = pStk1->RestoreStack(NULL);
+ if ( pStk3 == NULL ) return;
+ }
+
+ // preparing parameters on the stack
+
+ {
+ if ( !pt->m_MasterClass.IsEmpty() )
+ {
+ CBotVar* pInstance = m_pProg->m_pInstance;
+ // make "this" known
+ CBotVar* pThis = pStk1->FindVar("this");
+ pThis->SetInit(2);
+ pThis->SetUniqNum(-2);
+ }
+ }
+
+ if ( pStk1->GivState() == 0 )
+ {
+ pt->m_Param->RestoreState(pStk3, true);
+ return;
+ }
+
+ // initializes the variables as parameters
+ pt->m_Param->RestoreState(pStk3, false);
+ pt->m_Block->RestoreState(pStk3, true);
+ }
+}
+
+
+
+// makes call of a method
+// note: this is already on the stack, the pointer pThis is just to simplify
+
+int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
+{
+ CBotTypResult type;
+ CBotProgram* pProgCurrent = pStack->GivBotCall();
+
+ CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false);
+
+ if ( pt != NULL )
+ {
+// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack);
+
+ CBotStack* pStk = pStack->AddStack(pt, 2);
+// if ( pStk == EOX ) return true;
+
+ pStk->SetBotCall(pt->m_pProg); // it may have changed module
+ CBotStack* pStk3 = pStk->AddStack(NULL, true); // to set parameters passed
+
+ // preparing parameters on the stack
+
+ if ( pStk->GivState() == 0 )
+ {
+ // sets the variable "this" on the stack
+ CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
+ pthis->Copy(pThis, false);
+ pthis->SetUniqNum(-2); // special value
+ pStk->AddVar(pthis);
+
+ CBotClass* pClass = pThis->GivClass()->GivParent();
+ if ( pClass )
+ {
+ // sets the variable "super" on the stack
+ CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer);
+ psuper->Copy(pThis, false); // in fact identical to "this"
+ psuper->SetUniqNum(-3); // special value
+ pStk->AddVar(psuper);
+ }
+ // initializes the variables as parameters
+ pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted
+ pStk->IncState();
+ }
+
+ if ( pStk->GivState() == 1 )
+ {
+ if ( pt->m_bSynchro )
+ {
+ CBotProgram* pProgBase = pStk->GivBotCall(true);
+ if ( !pClass->Lock(pProgBase) ) return false; // expected to power \TODO attend de pouvoir
+ }
+ pStk->IncState();
+ }
+ // finally calls the found function
+
+ if ( !pStk3->GivRetVar( // puts the result on the stack
+ pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted
+ {
+ if ( !pStk3->IsOk() )
+ {
+ if ( pt->m_bSynchro )
+ {
+ pClass->Unlock(); // release function
+ }
+
+ if ( pt->m_pProg != pProgCurrent )
+ {
+ pStk3->SetPosError(pToken); // indicates the error on the procedure call
+ }
+ }
+ return false; // interrupt !
+ }
+
+ if ( pt->m_bSynchro )
+ {
+ pClass->Unlock(); // release function
+ }
+
+ return pStack->Return( pStk3 );
+ }
+ return -1;
+}
+
+void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
+{
+ CBotTypResult type;
+ CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+
+ if ( pt != NULL )
+ {
+ CBotStack* pStk = pStack->RestoreStack(pt);
+ if ( pStk == NULL ) return;
+ pStk->SetBotCall(pt->m_pProg); // it may have changed module
+
+ CBotVar* pthis = pStk->FindVar("this");
+ pthis->SetUniqNum(-2);
+
+ CBotStack* pStk3 = pStk->RestoreStack(NULL); // to set parameters passed
+ if ( pStk3 == NULL ) return;
+
+ pt->m_Param->RestoreState(pStk3, true); // parameters
+
+ if ( pStk->GivState() > 1 && // latching is effective?
+ pt->m_bSynchro )
+ {
+ CBotProgram* pProgBase = pStk->GivBotCall(true);
+ pClass->Lock(pProgBase); // locks the class
+ }
+
+ // finally calls the found function
+
+ pt->m_Block->RestoreState(pStk3, true); // interrupt !
+ }
+}
+
+// see if the "signature" of parameters is identical
+bool CBotFunction::CheckParam(CBotDefParam* pParam)
+{
+ CBotDefParam* pp = m_Param;
+ while ( pp != NULL && pParam != NULL )
+ {
+ CBotTypResult type1 = pp->GivType();
+ CBotTypResult type2 = pParam->GivType();
+ if ( !type1.Compare(type2) ) return false;
+ pp = pp->GivNext();
+ pParam = pParam->GivNext();
+ }
+ return ( pp == NULL && pParam == NULL );
+}
+
+CBotString CBotFunction::GivName()
+{
+ return m_token.GivString();
+}
+
+CBotString CBotFunction::GivParams()
+{
+ if ( m_Param == NULL ) return CBotString("()");
+
+ CBotString params = "( ";
+ CBotDefParam* p = m_Param; // list of parameters
+
+ while (p != NULL)
+ {
+ params += p->GivParamString();
+ p = p->GivNext();
+ if ( p != NULL ) params += ", ";
+ }
+
+ params += " )";
+ return params;
+}
+
+CBotFunction* CBotFunction::Next()
+{
+ return m_next;
+}
+
+void CBotFunction::AddPublic(CBotFunction* func)
+{
+ if ( m_listPublic != NULL )
+ {
+ func->m_nextpublic = m_listPublic;
+ m_listPublic->m_prevpublic = func;
+ }
+ m_listPublic = func;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// management of parameters
+
+
+CBotDefParam::CBotDefParam()
+{
+ m_next = NULL;
+ m_nIdent = 0;
+}
+
+CBotDefParam::~CBotDefParam()
+{
+ delete m_next;
+}
+
+
+// compiles a list of parameters
+CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ // mainly not pStack->TokenStack here
+ // declared variables must remain visible thereafter
+
+ pStack->SetStartError(p->GivStart());
+
+ if (IsOfType(p, ID_OPENPAR))
+ {
+ CBotDefParam* list = NULL;
+
+ while (!IsOfType(p, ID_CLOSEPAR))
+ {
+ CBotDefParam* param = new CBotDefParam();
+ if (list == NULL) list = param;
+ else list->AddNext(param); // added to the list
+
+ CBotClass* pClass = NULL;//= CBotClass::Find(p);
+ param->m_typename = p->GivString();
+ CBotTypResult type = param->m_type = TypeParam(p, pStack);
+// if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object
+
+ if (param->m_type.GivType() > 0)
+ {
+ CBotToken* pp = p;
+ param->m_token = *p;
+ if (pStack->IsOk() && IsOfType(p, TokenTypVar) )
+ {
+
+ // variable already declared?
+ if (pStack->CheckVarLocal(pp))
+ {
+ pStack->SetError(TX_REDEFVAR, pp);
+ break;
+ }
+
+ if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
+ CBotVar* var = CBotVar::Create(pp->GivString(), type); // creates the variable
+// if ( pClass ) var->SetClass(pClass);
+ var->SetInit(2); // mark initialized
+ param->m_nIdent = CBotVar::NextUniqNum();
+ var->SetUniqNum(param->m_nIdent);
+ pStack->AddVar(var); // place on the stack
+
+ if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR)
+ continue;
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ pStack->SetError(TX_NOTYP, p);
+ delete list;
+ return NULL;
+ }
+ return list;
+ }
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ return NULL;
+}
+
+void CBotDefParam::AddNext(CBotDefParam* p)
+{
+ CBotDefParam* pp = this;
+ while (pp->m_next != NULL) pp = pp->m_next;
+
+ pp->m_next = p;
+}
+
+
+bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
+{
+ int i = 0;
+ CBotDefParam* p = this;
+
+ while ( p != NULL )
+ {
+ // creates a local variable on the stack
+ CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type);
+
+ // serves to make the transformation of types:
+ if ( ppVars != NULL && ppVars[i] != NULL )
+ {
+ switch (p->m_type.GivType())
+ {
+ case CBotTypInt:
+ newvar->SetValInt(ppVars[i]->GivValInt());
+ break;
+ case CBotTypFloat:
+ newvar->SetValFloat(ppVars[i]->GivValFloat());
+ break;
+ case CBotTypString:
+ newvar->SetValString(ppVars[i]->GivValString());
+ break;
+ case CBotTypBoolean:
+ newvar->SetValInt(ppVars[i]->GivValInt());
+ break;
+ case CBotTypIntrinsic:
+ ((CBotVarClass*)newvar)->Copy(ppVars[i], false);
+ break;
+ case CBotTypPointer:
+ case CBotTypArrayPointer:
+ {
+ newvar->SetPointer(ppVars[i]->GivPointer());
+ }
+ break;
+ default:
+ ASM_TRAP();
+ }
+ }
+ newvar->SetUniqNum(p->m_nIdent);
+ pj->AddVar(newvar); // add a variable
+ p = p->m_next;
+ i++;
+ }
+
+ return true;
+}
+
+void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
+{
+ int i = 0;
+ CBotDefParam* p = this;
+
+ while ( p != NULL )
+ {
+ // creates a local variable on the stack
+ CBotVar* var = pj->FindVar(p->m_token.GivString());
+ var->SetUniqNum(p->m_nIdent);
+ p = p->m_next;
+ }
+}
+
+int CBotDefParam::GivType()
+{
+ return m_type.GivType();
+}
+
+CBotTypResult CBotDefParam::GivTypResult()
+{
+ return m_type;
+}
+
+CBotDefParam* CBotDefParam::GivNext()
+{
+ return m_next;
+}
+
+CBotString CBotDefParam::GivParamString()
+{
+ CBotString param;
+
+ param = m_typename;
+ param += ' ';
+
+ param += m_token.GivString();
+ return param;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// return parameters
+
+CBotReturn::CBotReturn()
+{
+ m_Instr = NULL;
+ name = "CBotReturn"; // debug
+}
+
+CBotReturn::~CBotReturn()
+{
+ delete m_Instr;
+}
+
+CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p;
+
+ if (!IsOfType(p, ID_RETURN)) return NULL; // should never happen
+
+ CBotReturn* inst = new CBotReturn(); // creates the object
+ inst->SetToken( pp );
+
+ CBotTypResult type = pStack->GivRetType();
+
+ if ( type.GivType() == 0 ) // returned void ?
+ {
+ if ( IsOfType( p, ID_SEP ) ) return inst;
+ pStack->SetError( TX_BADTYPE, pp );
+ return NULL;
+ }
+
+ inst->m_Instr = CBotExpression::Compile(p, pStack);
+ if ( pStack->IsOk() )
+ {
+ CBotTypResult retType = pStack->GivTypResult(2);
+ if (TypeCompatible(retType, type, ID_ASS))
+ {
+ if ( IsOfType( p, ID_SEP ) )
+ return inst;
+
+ pStack->SetError(TX_ENDOF, p->GivStart());
+ }
+ pStack->SetError(TX_BADTYPE, p->GivStart());
+ }
+
+ delete inst;
+ return NULL; // no object, the error is on the stack
+}
+
+bool CBotReturn::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+// if ( pile == EOX ) return true;
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // evaluate the result
+ // the result is on the stack
+ pile->IncState();
+ }
+
+ if ( pile->IfStep() ) return false;
+
+ pile->SetBreak(3, CBotString());
+ return pj->Return(pile);
+}
+
+void CBotReturn::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pile = pj->RestoreStack(this);
+ if ( pile == NULL ) return;
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // evaluate the result
+ return;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Calls of these functions
+
+CBotInstrCall::CBotInstrCall()
+{
+ m_Parameters = NULL;
+ m_nFuncIdent = 0;
+ name = "CBotInstrCall";
+}
+
+CBotInstrCall::~CBotInstrCall()
+{
+ delete m_Parameters;
+}
+
+CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotVar* ppVars[1000];
+
+ int i = 0;
+
+ CBotToken* pp = p;
+ p = p->GivNext();
+
+ pStack->SetStartError(p->GivStart());
+ CBotCStack* pile = pStack;
+
+ if ( IsOfType(p, ID_OPENPAR) )
+ {
+ int start, end;
+ CBotInstrCall* inst = new CBotInstrCall();
+ inst->SetToken(pp);
+
+ // compile la list of parameters
+ if (!IsOfType(p, ID_CLOSEPAR)) while (true)
+ {
+ start = p->GivStart();
+ pile = pile->TokenStack(); // keeps the results on the stack
+
+ CBotInstr* param = CBotExpression::Compile(p, pile);
+ end = p->GivStart();
+ if ( inst->m_Parameters == NULL ) inst->m_Parameters = param;
+ else inst->m_Parameters->AddNext(param); // constructs the list
+
+ if ( !pile->IsOk() )
+ {
+ delete inst;
+ return pStack->Return(NULL, pile);
+ }
+
+ if ( param != NULL )
+ {
+ if ( pile->GivTypResult().Eq(99) )
+ {
+ delete pStack->TokenStack();
+ pStack->SetError(TX_VOID, p->GivStart());
+ delete inst;
+ 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();
+ delete inst;
+ return NULL;
+ }
+ ppVars[i] = NULL;
+
+ // the routine is known?
+// CBotClass* pClass = NULL;
+ inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent);
+ if ( inst->m_typRes.GivType() >= 20 )
+ {
+// if (pVar2!=NULL) pp = pVar2->RetToken();
+ pStack->SetError( inst->m_typRes.GivType(), pp );
+ delete pStack->TokenStack();
+ delete inst;
+ return NULL;
+ }
+
+ delete pStack->TokenStack();
+ if ( inst->m_typRes.GivType() > 0 )
+ {
+ CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
+ pStack->SetVar(pRes); // for knowing the type of the result
+ }
+ else pStack->SetVar(NULL); // routine returns void
+
+ return inst;
+ }
+ p = pp;
+ delete pStack->TokenStack();
+ return NULL;
+}
+
+bool CBotInstrCall::Execute(CBotStack* &pj)
+{
+ CBotVar* ppVars[1000];
+ CBotStack* pile = pj->AddStack(this);
+ if ( pile->StackOver() ) return pj->Return( pile );
+
+ CBotStack* pile1 = pile;
+
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluates parameters
+ // and places the values ​​on the stack
+ // for allow of interruption at any time
+ if ( p != NULL) while ( true )
+ {
+ pile = pile->AddStack(); // place on the stack for the results
+ if ( pile->GivState() == 0 )
+ {
+ if (!p->Execute(pile)) return false; // interrupted here?
+ pile->SetState(1); // mark as special for reknowed parameters \TODO marque spéciale pour reconnaîre parameters
+ }
+ ppVars[i++] = pile->GivVar();
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ CBotStack* pile2 = pile->AddStack();
+ if ( pile2->IfStep() ) return false;
+
+ if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return false; // interrupt
+
+ return pj->Return(pile2); // release the entire stack
+}
+
+void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if ( pile == NULL ) return;
+
+ CBotStack* pile1 = pile;
+
+ int i = 0;
+ CBotVar* ppVars[1000];
+ CBotInstr* p = m_Parameters;
+ // evaluate parameters
+ // and place the values on the stack
+ // for allow of interruption at any time
+ if ( p != NULL) while ( true )
+ {
+ pile = pile->RestoreStack(); // place on the stack for the results
+ if ( pile == NULL ) return;
+ if ( pile->GivState() == 0 )
+ {
+ p->RestoreState(pile, bMain); // interrupt here!
+ return;
+ }
+ ppVars[i++] = pile->GivVar(); // constructs the list of parameters
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ CBotStack* pile2 = pile->RestoreStack();
+ if ( pile2 == NULL ) return;
+
+ pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// statement of user classes
+
+// pre-compile a new class
+// analysis is complete except the body of routines
+
+CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
+{
+ if ( !IsOfType(p, ID_PUBLIC) )
+ {
+ pStack->SetError(TX_NOPUBLIC, p);
+ return NULL;
+ }
+
+ if ( !IsOfType(p, ID_CLASS) ) return NULL;
+
+ CBotString name = p->GivString();
+
+ CBotClass* pOld = CBotClass::Find(name);
+ if ( pOld != NULL && pOld->m_IsDef )
+ {
+ pStack->SetError( TX_REDEFCLASS, p );
+ return NULL;
+ }
+
+ // a name of the class is there?
+ if (IsOfType(p, TokenTypVar))
+ {
+ CBotClass* pPapa = NULL;
+ if ( IsOfType( p, ID_EXTENDS ) )
+ {
+ CBotString name = p->GivString();
+ pPapa = CBotClass::Find(name);
+
+ if (!IsOfType(p, TokenTypVar) || pPapa == NULL )
+ {
+ pStack->SetError( TX_NOCLASS, p );
+ return NULL;
+ }
+ }
+ CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld;
+ classe->Purge(); // emptythe old definitions
+ classe->m_IsDef = false; // current definition
+
+ if ( !IsOfType( p, ID_OPBLK) )
+ {
+ pStack->SetError(TX_OPENBLK, p);
+ return NULL;
+ }
+
+ while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
+ {
+ classe->CompileDefItem(p, pStack, false);
+ }
+
+ if (pStack->IsOk()) return classe;
+ }
+ pStack->SetError(TX_ENDOF, p);
+ return NULL;
+}
+
+bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
+{
+ bool bStatic = false;
+ int mProtect = PR_PUBLIC;
+ bool bSynchro = false;
+
+ while (IsOfType(p, ID_SEP)) ;
+
+ CBotTypResult type( -1 );
+
+ if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true;
+ CBotToken* pBase = p;
+
+ if ( IsOfType(p, ID_STATIC) ) bStatic = true;
+ if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC;
+ if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE;
+ if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT;
+ if ( IsOfType(p, ID_STATIC) ) bStatic = true;
+
+// CBotClass* pClass = NULL;
+ type = TypeParam(p, pStack); // type of the result
+
+ if ( type.Eq(-1) )
+ {
+ pStack->SetError(TX_NOTYP, p);
+ return false;
+ }
+
+ while (pStack->IsOk())
+ {
+ CBotToken* pp = p;
+ IsOfType(p, ID_NOT); // skips ~ eventual (destructor)
+
+ if (IsOfType(p, TokenTypVar))
+ {
+ CBotInstr* limites = NULL;
+ while ( IsOfType( p, ID_OPBRK ) ) // a table?
+ {
+ CBotInstr* i = NULL;
+
+ if ( p->GivType() != ID_CLBRK )
+ i = CBotExpression::Compile( p, pStack ); // expression for the value
+ else
+ i = new CBotEmpty(); // special if not a formula
+
+ type = CBotTypResult(CBotTypArrayPointer, type);
+
+ if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) )
+ {
+ pStack->SetError(TX_CLBRK, p->GivStart());
+ return false;
+ }
+
+/* CBotVar* pv = pStack->GivVar();
+ if ( pv->GivType()>= CBotTypBoolean )
+ {
+ pStack->SetError(TX_BADTYPE, p->GivStart());
+ return false;
+ }*/
+
+ if (limites == NULL) limites = i;
+ else limites->AddNext3(i);
+ }
+
+ if ( p->GivType() == ID_OPENPAR )
+ {
+ if ( !bSecond )
+ {
+ p = pBase;
+ CBotFunction* f =
+ CBotFunction::Compile1(p, pStack, this);
+
+ if ( f == NULL ) return false;
+
+ if (m_pMethod == NULL) m_pMethod = f;
+ else m_pMethod->AddNext(f);
+ }
+ else
+ {
+ // return a method precompiled in pass 1
+ CBotFunction* pf = m_pMethod;
+ CBotFunction* prev = NULL;
+ while ( pf != NULL )
+ {
+ if (pf->GivName() == pp->GivString()) break;
+ prev = pf;
+ pf = pf->Next();
+ }
+
+ bool bConstructor = (pp->GivString() == GivName());
+ CBotCStack* pile = pStack->TokenStack(NULL, true);
+
+ // make "this" known
+ CBotToken TokenThis(CBotString("this"), CBotString());
+ CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) );
+ pThis->SetUniqNum(-2);
+ pile->AddVar(pThis);
+
+ if ( m_pParent )
+ {
+ // makes "super" known
+ CBotToken TokenSuper(CBotString("super"), CBotString());
+ CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) );
+ pThis->SetUniqNum(-3);
+ pile->AddVar(pThis);
+ }
+
+// int num = 1;
+ CBotClass* my = this;
+ while (my != NULL)
+ {
+ // places a copy of variables of a class (this) on a stack
+ CBotVar* pv = my->m_pVar;
+ while (pv != NULL)
+ {
+ CBotVar* pcopy = CBotVar::Create(pv);
+ pcopy->SetInit(!bConstructor || pv->IsStatic());
+ pcopy->SetUniqNum(pv->GivUniqNum());
+ pile->AddVar(pcopy);
+ pv = pv->GivNext();
+ }
+ my = my->m_pParent;
+ }
+
+ // compiles a method
+ p = pBase;
+ CBotFunction* f =
+ CBotFunction::Compile(p, pile, NULL/*, false*/);
+
+ if ( f != NULL )
+ {
+ f->m_pProg = pStack->GivBotCall();
+ f->m_bSynchro = bSynchro;
+ // replaces the element in the chain
+ f->m_next = pf->m_next;
+ pf->m_next = NULL;
+ delete pf;
+ if (prev == NULL) m_pMethod = f;
+ else prev->m_next = f;
+ }
+ pStack->Return(NULL, pile);
+ }
+
+ return pStack->IsOk();
+ }
+
+ // definition of an element
+ if (type.Eq(0))
+ {
+ pStack->SetError(TX_ENDOF, p);
+ return false;
+ }
+
+ CBotInstr* i = NULL;
+ if ( IsOfType(p, ID_ASS ) )
+ {
+ if ( type.Eq(CBotTypArrayPointer) )
+ {
+ i = CBotListArray::Compile(p, pStack, type.GivTypElem());
+ }
+ else
+ {
+ // it has an assignmet to calculate
+ i = CBotTwoOpExpr::Compile(p, pStack);
+ }
+ if ( !pStack->IsOk() ) return false;
+ }
+
+
+ if ( !bSecond )
+ {
+ CBotVar* pv = CBotVar::Create(pp->GivString(), type);
+ pv -> SetStatic( bStatic );
+ pv -> SetPrivate( mProtect );
+
+ AddItem( pv );
+
+ pv->m_InitExpr = i;
+ pv->m_LimExpr = limites;
+
+
+ if ( pv->IsStatic() && pv->m_InitExpr != NULL )
+ {
+ CBotStack* pile = CBotStack::FirstStack(); // independent stack
+ while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer
+ pv->SetVal( pile->GivVar() ) ;
+ pile->Delete();
+ }
+ }
+ else
+ delete i;
+
+ if ( IsOfType(p, ID_COMMA) ) continue;
+ if ( IsOfType(p, ID_SEP) ) break;
+ }
+ pStack->SetError(TX_ENDOF, p);
+ }
+ return pStack->IsOk();
+}
+
+
+CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ if ( !IsOfType(p, ID_PUBLIC) ) return NULL;
+ if ( !IsOfType(p, ID_CLASS) ) return NULL;
+
+ CBotString name = p->GivString();
+
+ // a name for the class is there?
+ if (IsOfType(p, TokenTypVar))
+ {
+ // the class was created by Compile1
+ CBotClass* pOld = CBotClass::Find(name);
+
+ if ( IsOfType( p, ID_EXTENDS ) )
+ {
+ IsOfType(p, TokenTypVar); // necessarily
+ }
+ IsOfType( p, ID_OPBLK); // necessarily
+
+ while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
+ {
+ pOld->CompileDefItem(p, pStack, true);
+ }
+
+ pOld->m_IsDef = true; // complete definition
+ if (pStack->IsOk()) return pOld;
+ }
+ pStack->SetError(TX_ENDOF, p);
+ return NULL;
+}
diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp
index 419798f..ddb26c6 100644
--- a/src/CBot/CBotStack.cpp
+++ b/src/CBot/CBotStack.cpp
@@ -1,1471 +1,1471 @@
-// * 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 the stack
-
-
-#include "CBot.h"
-#include <cstdlib>
-#include <cstring>
-
-
-#define ITIMER 100
-
-////////////////////////////////////////////////////////////////////////////
-// gestion de la pile d'exécution
-////////////////////////////////////////////////////////////////////////////
-
-int CBotStack::m_initimer = ITIMER;
-int CBotStack::m_timer = 0;
-CBotVar* CBotStack::m_retvar = NULL;
-int CBotStack::m_error = 0;
-int CBotStack::m_start = 0;
-int CBotStack::m_end = 0;
-CBotString CBotStack::m_labelBreak="";
-void* CBotStack::m_pUser = NULL;
-
-#if STACKMEM
-
-CBotStack* CBotStack::FirstStack()
-{
- CBotStack* p;
-
- long size = sizeof(CBotStack);
- size *= (MAXSTACK+10);
-
- // demande une tranche mémoire pour la pile
- p = (CBotStack*)malloc(size);
-
- // la vide totalement
- memset(p, 0, size);
-
- p-> m_bBlock = true;
- m_timer = m_initimer; // met le timer au début
-
- CBotStack* pp = p;
- pp += MAXSTACK;
- int i;
- for ( i = 0 ; i< 10 ; i++ )
- {
- pp->m_bOver = true;
- pp ++;
- }
-#ifdef _DEBUG
- int n = 1;
- pp = p;
- for ( i = 0 ; i< MAXSTACK+10 ; i++ )
- {
- pp->m_index = n++;
- pp ++;
- }
-#endif
-
- m_error = 0; // évite des blocages car m_error est static
- return p;
-}
-
-CBotStack::CBotStack(CBotStack* ppapa)
-{
- // constructor must exist or the destructor is never called!
- ASM_TRAP();
-}
-
-CBotStack::~CBotStack()
-{
- ASM_TRAP(); // utiliser Delete() à la place
-}
-
-void CBotStack::Delete()
-{
- if ( this == NULL || this == EOX ) return;
-
- m_next->Delete();
- m_next2->Delete();
-
- if (m_prev != NULL)
- {
- if ( m_prev->m_next == this )
- m_prev->m_next = NULL; // enlève de la chaîne
-
- if ( m_prev->m_next2 == this )
- m_prev->m_next2 = NULL; // enlève de la chaîne
- }
-
- delete m_var;
- delete m_listVar;
-
- CBotStack* p = m_prev;
- bool bOver = m_bOver;
-#ifdef _DEBUG
- int n = m_index;
-#endif
-
- // efface le bloc libéré
- memset(this, 0, sizeof(CBotStack));
- m_bOver = bOver;
-#ifdef _DEBUG
- m_index = n;
-#endif
-
- if ( p == NULL )
- free( this );
-}
-
-
-// routine optimisée
-CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- return m_next; // reprise dans une pile existante
- }
-
-#ifdef _DEBUG
- int n = 0;
-#endif
- CBotStack* p = this;
- do
- {
- p ++;
-#ifdef _DEBUG
- n ++;
-#endif
- }
- while ( p->m_prev != NULL );
-
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_instr = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- p->m_prev = this;
- p->m_state = 0;
- p->m_call = NULL;
- p->m_bFunc = false;
- return p;
-}
-
-CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- if ( m_next == EOX )
- {
- m_next = NULL;
- return EOX;
- }
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = AddStack(NULL, bBlock);
- p->m_call = instr;
- p->m_bFunc = 2; // spécial
- return p;
-}
-
-CBotStack* CBotStack::AddStack2(bool bBlock)
-{
- if (m_next2 != NULL)
- {
- m_next2->m_prog = m_prog; // spécial évite un RestoreStack2
- return m_next2; // reprise dans une pile existante
- }
-
- CBotStack* p = this;
- do
- {
- p ++;
- }
- while ( p->m_prev != NULL );
-
- m_next2 = p; // chaîne l'élément
- p->m_prev = this;
- p->m_bBlock = bBlock;
- p->m_prog = m_prog;
- p->m_step = 0;
- return p;
-}
-
-bool CBotStack::GivBlock()
-{
- return m_bBlock;
-}
-
-bool CBotStack::Return(CBotStack* pfils)
-{
- if ( pfils == this ) return true; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- m_next->Delete();m_next = NULL; // libère la pile au dessus
- m_next2->Delete();m_next2 = NULL; // aussi la seconde pile (catch)
-
- return (m_error == 0); // interrompu si erreur
-}
-
-bool CBotStack::ReturnKeep(CBotStack* pfils)
-{
- if ( pfils == this ) return true; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- return (m_error == 0); // interrompu si erreur
-}
-
-bool CBotStack::StackOver()
-{
- if (!m_bOver) return false;
- m_error = TX_STACKOVER;
- return true;
-}
-
-#else
-
-CBotStack::CBotStack(CBotStack* ppapa)
-{
- m_next = NULL;
- m_next2 = NULL;
- m_prev = ppapa;
-
- m_bBlock = (ppapa == NULL) ? true : false;
-
- m_state = 0;
- m_step = 1;
-
- if (ppapa == NULL) m_timer = m_initimer; // met le timer au début
-
- m_listVar = NULL;
- m_bDontDelete = false;
-
- m_var = NULL;
- m_prog = NULL;
- m_instr = NULL;
- m_call = NULL;
- m_bFunc = false;
-}
-
-// destructeur
-CBotStack::~CBotStack()
-{
- if ( m_next != EOX) delete m_next;
- delete m_next2;
- if (m_prev != NULL && m_prev->m_next == this )
- m_prev->m_next = NULL; // enlève de la chaîne
-
- delete m_var;
- if ( !m_bDontDelete ) delete m_listVar;
-}
-
-// routine à optimiser
-CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = new CBotStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_instr = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- return p;
-}
-
-CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- if ( m_next == EOX )
- {
- m_next = NULL;
- return EOX;
- }
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = new CBotStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_call = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- p->m_bFunc = 2; // spécial
- return p;
-}
-
-CBotStack* CBotStack::AddStack2(bool bBlock)
-{
- if (m_next2 != NULL)
- {
- m_next2->m_prog = m_prog; // spécial évite un RestoreStack2
- return m_next2; // reprise dans une pile existante
- }
-
- CBotStack* p = new CBotStack(this);
- m_next2 = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_prog = m_prog;
- p->m_step = 0;
-
- return p;
-}
-
-bool CBotStack::Return(CBotStack* pfils)
-{
- if ( pfils == this ) return true; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruite la variable
-
- if ( m_next != EOX ) delete m_next; // libère la pile au dessus
- delete m_next2;m_next2 = NULL; // aussi la seconde pile (catch)
-
- return (m_error == 0); // interrompu si erreur
-}
-
-bool CBotStack::StackOver()
-{
- return false; // pas de test de débordement dans cette version
-}
-
-#endif
-
-void CBotStack::Reset(void* pUser)
-{
- m_timer = m_initimer; // remet le timer
- m_error = 0;
-// m_start = 0;
-// m_end = 0;
- m_labelBreak.Empty();
- m_pUser = pUser;
-}
-
-
-
-
-CBotStack* CBotStack::RestoreStack(CBotInstr* instr)
-{
- if (m_next != NULL)
- {
- m_next->m_instr = instr; // réinit (si reprise après restitution)
- m_next->m_prog = m_prog;
- return m_next; // reprise dans une pile existante
- }
- return NULL;
-}
-
-CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr)
-{
- CBotStack* p = RestoreStack();
- p->m_call = instr;
- return p;
-}
-
-
-
-// routine pour l'exécution pas à pas
-bool CBotStack::IfStep()
-{
- if ( m_initimer > 0 || m_step++ > 0 ) return false;
- return true;
-}
-
-
-bool CBotStack::BreakReturn(CBotStack* pfils, const char* name)
-{
- if ( m_error>=0 ) return false; // sortie normale
- if ( m_error==-3 ) return false; // sortie normale (return en cours)
-
- if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name))
- return false; // c'est pas pour moi
-
- m_error = 0;
- m_labelBreak.Empty();
- return Return(pfils);
-}
-
-bool CBotStack::IfContinue(int state, const char* name)
-{
- if ( m_error != -2 ) return false;
-
- if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name))
- return false; // c'est pas pour moi
-
- m_state = state; // où reprendre ?
- m_error = 0;
- m_labelBreak.Empty();
- if ( m_next != EOX ) m_next->Delete(); // purge la pile au dessus
- return true;
-}
-
-void CBotStack::SetBreak(int val, const char* name)
-{
- m_error = -val; // réagit comme une Exception
- m_labelBreak = name;
- if (val == 3) // pour un return
- {
- m_retvar = m_var;
- m_var = NULL;
- }
-}
-
-// remet sur la pile la valeur calculée par le dernier CBotReturn
-
-bool CBotStack::GivRetVar(bool bRet)
-{
- if (m_error == -3)
- {
- if ( m_var ) delete m_var;
- m_var = m_retvar;
- m_retvar = NULL;
- m_error = 0;
- return true;
- }
- return bRet; // interrompu par autre chose que return
-}
-
-int CBotStack::GivError(int& start, int& end)
-{
- start = m_start;
- end = m_end;
- return m_error;
-}
-
-
-int CBotStack::GivType(int mode)
-{
- if (m_var == NULL) return -1;
- return m_var->GivType(mode);
-}
-
-CBotTypResult CBotStack::GivTypResult(int mode)
-{
- if (m_var == NULL) return -1;
- return m_var->GivTypResult(mode);
-}
-
-void CBotStack::SetType(CBotTypResult& type)
-{
- if (m_var == NULL) return;
- m_var->SetType( type );
-}
-
-
-CBotVar* CBotStack::FindVar(CBotToken* &pToken, bool bUpdate, bool bModif)
-{
- CBotStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivName() == name)
- {
- if ( bUpdate )
- pp->Maj(m_pUser, false);
-
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotStack::FindVar(const char* name)
-{
- CBotStack* p = this;
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivName() == name)
- {
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotStack::FindVar(long ident, bool bUpdate, bool bModif)
-{
- CBotStack* p = this;
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivUniqNum() == ident)
- {
- if ( bUpdate )
- pp->Maj(m_pUser, false);
-
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-
-CBotVar* CBotStack::FindVar(CBotToken& Token, bool bUpdate, bool bModif)
-{
- CBotToken* pt = &Token;
- return FindVar(pt, bUpdate, bModif);
-}
-
-
-CBotVar* CBotStack::CopyVar(CBotToken& Token, bool bUpdate)
-{
- CBotVar* pVar = FindVar( Token, bUpdate );
-
- if ( pVar == NULL) return NULL;
-
- CBotVar* pCopy = CBotVar::Create(pVar);
- pCopy->Copy(pVar);
- return pCopy;
-}
-
-
-bool CBotStack::SetState(int n, int limite)
-{
- m_state = n;
-
- m_timer--; // décompte les opérations
- return ( m_timer > limite ); // interrompu si timer passé
-}
-
-bool CBotStack::IncState(int limite)
-{
- m_state++;
-
- m_timer--; // décompte les opérations
- return ( m_timer > limite ); // interrompu si timer passé
-}
-
-
-void CBotStack::SetError(int n, CBotToken* token)
-{
- if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante
- m_error = n;
- if (token != NULL)
- {
- m_start = token->GivStart();
- m_end = token->GivEnd();
- }
-}
-
-void CBotStack::ResetError(int n, int start, int end)
-{
- m_error = n;
- m_start = start;
- m_end = end;
-}
-
-void CBotStack::SetPosError(CBotToken* token)
-{
- m_start = token->GivStart();
- m_end = token->GivEnd();
-}
-
-void CBotStack::SetTimer(int n)
-{
- m_initimer = n;
-}
-
-bool CBotStack::Execute()
-{
- CBotCall* instr = NULL; // instruction la plus élevée
- CBotStack* pile;
-
- CBotStack* p = this;
-
- while (p != NULL)
- {
- if ( p->m_next2 != NULL ) break;
- if ( p->m_call != NULL )
- {
- instr = p->m_call;
- pile = p->m_prev ;
- }
- p = p->m_next;
- }
-
- if ( instr == NULL ) return true; // exécution normale demandée
-
- if (!instr->Run(pile)) return false; // exécution à partir de là
-
-#if STACKMEM
- pile->m_next->Delete();
-#else
- delete pile->m_next;
-#endif
-
- pile->m_next = EOX; // spécial pour reprise
- return true;
-}
-
-// met sur le stack le pointeur à une variable
-void CBotStack::SetVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
- m_var = var;
-}
-
-// met sur le stack une copie d'une variable
-void CBotStack::SetCopyVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
-
- m_var = CBotVar::Create("", var->GivTypResult(2));
- m_var->Copy( var );
-}
-
-CBotVar* CBotStack::GivVar()
-{
- return m_var;
-}
-
-CBotVar* CBotStack::GivPtVar()
-{
- CBotVar* p = m_var;
- m_var = NULL; // ne sera pas détruit donc
- return p;
-}
-
-CBotVar* CBotStack::GivCopyVar()
-{
- if (m_var == NULL) return NULL;
- CBotVar* v = CBotVar::Create("", m_var->GivType());
- v->Copy( m_var );
- return v;
-}
-
-long CBotStack::GivVal()
-{
- if (m_var == NULL) return 0;
- return m_var->GivValInt();
-}
-
-
-
-
-void CBotStack::AddVar(CBotVar* pVar)
-{
- CBotStack* p = this;
-
- // revient sur l'élement père
- while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
-
- if ( p == NULL ) return;
-
-/// p->m_bDontDelete = bDontDelete;
-
- CBotVar** pp = &p->m_listVar;
- while ( *pp != NULL ) pp = &(*pp)->m_next;
-
- *pp = pVar; // ajoute à la suite
-
-#ifdef _DEBUG
- if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
-#endif
-}
-
-/*void CBotStack::RestoreVar(CBotVar* pVar)
-{
- if ( !m_bDontDelete ) __asm int 3;
- delete m_listVar;
- m_listVar = pVar; // remplace directement
-}*/
-
-void CBotStack::SetBotCall(CBotProgram* p)
-{
- m_prog = p;
- m_bFunc = true;
-}
-
-CBotProgram* CBotStack::GivBotCall(bool bFirst)
-{
- if ( ! bFirst ) return m_prog;
- CBotStack* p = this;
- while ( p->m_prev != NULL ) p = p->m_prev;
- return p->m_prog;
-}
-
-void* CBotStack::GivPUser()
-{
- return m_pUser;
-}
-
-
-bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype)
-{
- CBotTypResult res;
-
- // cherche d'abord selon l'identificateur
-
- res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype );
- if (res.GivType() >= 0) return res.GivType();
-
- res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token );
- if (res.GivType() >= 0) return res.GivType();
-
- // si pas trouvé (recompilé ?) cherche selon le nom
-
- nIdent = 0;
- res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype );
- if (res.GivType() >= 0) return res.GivType();
-
- res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token );
- if (res.GivType() >= 0) return res.GivType();
-
- SetError(TX_NOCALL, token);
- return true;
-}
-
-void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
-{
- if ( m_next == NULL ) return;
-
- if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) )
- m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this );
-}
-
-
-bool SaveVar(FILE* pf, CBotVar* pVar)
-{
- while ( true )
- {
- if ( pVar == NULL )
- {
- return WriteWord(pf, 0); // met un terminateur
- }
-
- if ( !pVar->Save0State(pf)) return false; // entête commune
- if ( !pVar->Save1State(pf) ) return false; // sauve selon la classe fille
-
- pVar = pVar->GivNext();
- }
-}
-
-void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end)
-{
- CBotProgram* prog = m_prog; // programme courrant
-
- CBotInstr* funct = NULL; // fonction trouvée
- CBotInstr* instr = NULL; // instruction la plus élevée
-
- CBotStack* p = this;
-
- while (p->m_next != NULL)
- {
- if ( p->m_instr != NULL ) instr = p->m_instr;
- if ( p->m_bFunc == 1 ) funct = p->m_instr;
- if ( p->m_next->m_prog != prog ) break ;
-
- if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
- else p = p->m_next;
- }
-
- if ( p->m_instr != NULL ) instr = p->m_instr;
- if ( p->m_bFunc == 1 ) funct = p->m_instr;
-
- if ( funct == NULL ) return;
-
- CBotToken* t = funct->GivToken();
- FunctionName = t->GivString();
-
-// if ( p->m_instr != NULL ) instr = p->m_instr;
-
- t = instr->GivToken();
- start = t->GivStart();
- end = t->GivEnd();
-}
-
-CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level)
-{
- CBotProgram* prog = m_prog; // programme courrant
- FunctionName = NULL;
-
- // remonte la pile dans le module courant
- CBotStack* p = this;
-
- while (p->m_next != NULL)
- {
- if ( p->m_next->m_prog != prog ) break ;
-
- if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
- else p = p->m_next;
- }
-
-
- // descend sur les éléments de block
- while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
-
- while ( p != NULL && level++ < 0 )
- {
- p = p->m_prev;
- while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
- }
-
- if ( p == NULL ) return NULL;
-
- // recherche le nom de la fonction courante
- CBotStack* pp = p;
- while ( pp != NULL )
- {
- if ( pp->m_bFunc == 1 ) break;
- pp = pp->m_prev;
- }
-
- if ( pp == NULL || pp->m_instr == NULL ) return NULL;
-
- CBotToken* t = pp->m_instr->GivToken();
- FunctionName = t->GivString();
-
- return p->m_listVar;
-}
-
-bool CBotStack::SaveState(FILE* pf)
-{
- if ( this == NULL ) // fin de l'arbre ?
- {
- return WriteWord(pf, 0); // met un terminateur
- }
-
- if ( m_next2 != NULL )
- {
- if (!WriteWord(pf, 2)) return false; // une marque de poursuite
- if (!m_next2->SaveState(pf)) return false;
- }
- else
- {
- if (!WriteWord(pf, 1)) return false; // une marque de poursuite
- }
- if (!WriteWord(pf, m_bBlock)) return false; // est-ce un bloc local
- if (!WriteWord(pf, m_state)) return false; // dans quel état
- if (!WriteWord(pf, 0)) return false; // par compatibilité m_bDontDelete
- if (!WriteWord(pf, m_step)) return false; // dans quel état
-
-
- if (!SaveVar(pf, m_var)) return false; // le résultat courant
- if (!SaveVar(pf, m_listVar)) return false; // les variables locales
-
- return m_next->SaveState(pf); // enregistre la suite
-}
-
-
-bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
-{
- unsigned short w;
-
- pStack = NULL;
- if (!ReadWord(pf, w)) return false;
- if ( w == 0 ) return true;
-
-#if STACKMEM
- if ( this == NULL ) pStack = FirstStack();
- else pStack = AddStack();
-#else
- pStack = new CBotStack(this);
-#endif
-
- if ( w == 2 )
- {
- if (!pStack->RestoreState(pf, pStack->m_next2)) return false;
- }
-
- if (!ReadWord(pf, w)) return false; // est-ce un bloc local
- pStack->m_bBlock = w;
-
- if (!ReadWord(pf, w)) return false; // dans quel état j'ère ?
- pStack->SetState((short)w); // dans le bon état
-
- if (!ReadWord(pf, w)) return false; // dont delete ?
- // plus utilisé
-
- if (!ReadWord(pf, w)) return false; // pas à pas
- pStack->m_step = w;
-
- if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // la variable temp
- if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// les variables locales
-
- return pStack->RestoreState(pf, pStack->m_next);
-}
-
-
-bool CBotVar::Save0State(FILE* pf)
-{
- if (!WriteWord(pf, 100+m_mPrivate))return false; // variable privée ?
- if (!WriteWord(pf, m_bStatic))return false; // variable static ?
- if (!WriteWord(pf, m_type.GivType()))return false; // enregiste le type (toujours non nul)
- if (!WriteWord(pf, m_binit))return false; // variable définie ?
- return WriteString(pf, m_token->GivString()); // et le nom de la variable
-}
-
-bool CBotVarInt::Save0State(FILE* pf)
-{
- if ( !m_defnum.IsEmpty() )
- {
- if(!WriteWord(pf, 200 )) return false; // marqueur spécial
- if(!WriteString(pf, m_defnum)) return false; // nom de la valeur
- }
-
- return CBotVar::Save0State(pf);
-}
-
-bool CBotVarInt::Save1State(FILE* pf)
-{
- return WriteWord(pf, m_val); // la valeur de la variable
-}
-
-bool CBotVarBoolean::Save1State(FILE* pf)
-{
- return WriteWord(pf, m_val); // la valeur de la variable
-}
-
-bool CBotVarFloat::Save1State(FILE* pf)
-{
- return WriteFloat(pf, m_val); // la valeur de la variable
-}
-
-bool CBotVarString::Save1State(FILE* pf)
-{
- return WriteString(pf, m_val); // la valeur de la variable
-}
-
-
-
-bool CBotVarClass::Save1State(FILE* pf)
-{
- if ( !WriteType(pf, m_type) ) return false;
- if ( !WriteLong(pf, m_ItemIdent) ) return false;
-
- return SaveVar(pf, m_pVar); // contenu de l'objet
-}
-
-bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
-{
- unsigned short w, wi, prv, st;
- float ww;
- CBotString name, s;
-
- delete pVar;
-
- pVar = NULL;
- CBotVar* pNew = NULL;
- CBotVar* pPrev = NULL;
-
- while ( true ) // recupère toute une liste
- {
- if (!ReadWord(pf, w)) return false; // privé ou type ?
- if ( w == 0 ) return true;
-
- CBotString defnum;
- if ( w == 200 )
- {
- if (!ReadString(pf, defnum)) return false; // nombre avec un identifiant
- if (!ReadWord(pf, w)) return false; // type
- }
-
- prv = 100; st = 0;
- if ( w >= 100 )
- {
- prv = w;
- if (!ReadWord(pf, st)) return false; // statique
- if (!ReadWord(pf, w)) return false; // type
- }
-
- if ( w == CBotTypClass ) w = CBotTypIntrinsic; // forcément intrinsèque
-
- if (!ReadWord(pf, wi)) return false; // init ?
-
- if (!ReadString(pf, name)) return false; // nom de la variable
-
- CBotToken token(name, CBotString());
-
- switch (w)
- {
- case CBotTypInt:
- case CBotTypBoolean:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadWord(pf, w)) return false;
- pNew->SetValInt((short)w, defnum);
- break;
- case CBotTypFloat:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadFloat(pf, ww)) return false;
- pNew->SetValFloat(ww);
- break;
- case CBotTypString:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadString(pf, s)) return false;
- pNew->SetValString(s);
- break;
-
- // restitue un objet intrinsic ou un élément d'un array
- case CBotTypIntrinsic:
- case CBotTypArrayBody:
- {
- CBotTypResult r;
- long id;
- if (!ReadType(pf, r)) return false; // type complet
- if (!ReadLong(pf, id) ) return false;
-
-// if (!ReadString(pf, s)) return false;
- {
- CBotVar* p = NULL;
- if ( id ) p = CBotVarClass::Find(id) ;
-
- pNew = new CBotVarClass(&token, r); // crée directement une instance
- // attention cptuse = 0
- if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return false;
- pNew->SetIdent(id);
-
- if ( p != NULL )
- {
- delete pNew;
- pNew = p; // reprend l'élément connu
- }
- }
- }
- break;
-
- case CBotTypPointer:
- case CBotTypNullPointer:
- if (!ReadString(pf, s)) return false;
- {
- pNew = CBotVar::Create(&token, CBotTypResult(w, s));// crée une variable
- CBotVarClass* p = NULL;
- long id;
- ReadLong(pf, id);
-// if ( id ) p = CBotVarClass::Find(id); // retrouve l'instance ( fait par RestoreInstance )
-
- // restitue une copie de l'instance d'origine
- CBotVar* pInstance = NULL;
- if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
- ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus
-
-// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // plutôt celui-ci !
-
- }
- break;
-
- case CBotTypArrayPointer:
- {
- CBotTypResult r;
- if (!ReadType(pf, r)) return false;
-
- pNew = CBotVar::Create(&token, r); // crée une variable
-
- // restitue une copie de l'instance d'origine
- CBotVar* pInstance = NULL;
- if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
- ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus
- }
- break;
- default:
- ASM_TRAP();
- }
-
- if ( pPrev != NULL ) pPrev->m_next = pNew;
- if ( pVar == NULL ) pVar = pNew;
-
- pNew->m_binit = wi; // pNew->SetInit(wi);
- pNew->SetStatic(st);
- pNew->SetPrivate(prv-100);
- pPrev = pNew;
- }
- return true;
-}
-
-
-
-
-////////////////////////////////////////////////////////////////////////////
-// gestion de la pile à la compilation
-////////////////////////////////////////////////////////////////////////////
-
-CBotProgram* CBotCStack::m_prog = NULL; // init la variable statique
-int CBotCStack::m_error = 0;
-int CBotCStack::m_end = 0;
-CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0);
-//CBotToken* CBotCStack::m_retClass= NULL;
-
-
-CBotCStack::CBotCStack(CBotCStack* ppapa)
-{
- m_next = NULL;
- m_prev = ppapa;
-
- if (ppapa == NULL)
- {
- m_error = 0;
- m_start = 0;
- m_end = 0;
- m_bBlock = true;
- }
- else
- {
- m_start = ppapa->m_start;
- m_bBlock = false;
- }
-
- m_listVar = NULL;
- m_var = NULL;
-}
-
-// destructeur
-CBotCStack::~CBotCStack()
-{
- if (m_next != NULL) delete m_next;
- if (m_prev != NULL) m_prev->m_next = NULL; // enlève de la chaîne
-
- delete m_var;
- delete m_listVar;
-}
-
-// utilisé uniquement à la compilation
-CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock)
-{
- if (m_next != NULL) return m_next; // reprise dans une pile existante
-
- CBotCStack* p = new CBotCStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
-
- if (pToken != NULL) p->SetStartError(pToken->GivStart());
-
- return p;
-}
-
-
-CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils)
-{
- if ( pfils == this ) return inst;
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- if (m_error)
- {
- m_start = pfils->m_start; // récupère la position de l'erreur
- m_end = pfils->m_end;
- }
-
- delete pfils;
- return inst;
-}
-
-CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils)
-{
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- if (m_error)
- {
- m_start = pfils->m_start; // récupère la position de l'erreur
- m_end = pfils->m_end;
- }
-
- delete pfils;
- return inst;
-}
-
-int CBotCStack::GivError(int& start, int& end)
-{
- start = m_start;
- end = m_end;
- return m_error;
-}
-
-int CBotCStack::GivError()
-{
- return m_error;
-}
-
-// type d'instruction sur la pile
-CBotTypResult CBotCStack::GivTypResult(int mode)
-{
- if (m_var == NULL)
- return CBotTypResult(99);
- return m_var->GivTypResult(mode);
-}
-
-// type d'instruction sur la pile
-int CBotCStack::GivType(int mode)
-{
- if (m_var == NULL)
- return 99;
- return m_var->GivType(mode);
-}
-
-// pointeur sur la pile est de quelle classe ?
-CBotClass* CBotCStack::GivClass()
-{
- if ( m_var == NULL )
- return NULL;
- if ( m_var->GivType(1) != CBotTypPointer ) return NULL;
-
- return m_var->GivClass();
-}
-
-// type d'instruction sur la pile
-void CBotCStack::SetType(CBotTypResult& type)
-{
- if (m_var == NULL) return;
- m_var->SetType( type );
-}
-
-// cherche une variable sur la pile
-// le token peut être une suite de TokenTypVar (objet d'une classe)
-// ou un pointeur dans le source
-
-CBotVar* CBotCStack::FindVar(CBotToken* &pToken)
-{
- CBotCStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (name == pp->GivName())
- {
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotCStack::FindVar(CBotToken& Token)
-{
- CBotToken* pt = &Token;
- return FindVar(pt);
-}
-
-CBotVar* CBotCStack::CopyVar(CBotToken& Token)
-{
- CBotVar* pVar = FindVar( Token );
-
- if ( pVar == NULL) return NULL;
-
- CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() );
- pCopy->Copy(pVar);
- return pCopy;
-}
-
-bool CBotCStack::IsOk()
-{
- return (m_error == 0);
-}
-
-
-void CBotCStack::SetStartError( int pos )
-{
- if ( m_error != 0) return; // ne change pas une erreur déjà existante
- m_start = pos;
-}
-
-void CBotCStack::SetError(int n, int pos)
-{
- if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante
- m_error = n;
- m_end = pos;
-}
-
-void CBotCStack::SetError(int n, CBotToken* p)
-{
- if (m_error) return; // ne change pas une erreur déjà existante
- m_error = n;
- m_start = p->GivStart();
- m_end = p->GivEnd();
-}
-
-void CBotCStack::ResetError(int n, int start, int end)
-{
- m_error = n;
- m_start = start;
- m_end = end;
-}
-
-bool CBotCStack::NextToken(CBotToken* &p)
-{
- CBotToken* pp = p;
-
- p = p->GivNext();
- if (p!=NULL) return true;
-
- SetError(TX_ENDOF, pp->GivEnd());
- return false;
-}
-
-void CBotCStack::SetBotCall(CBotProgram* p)
-{
- m_prog = p;
-}
-
-CBotProgram* CBotCStack::GivBotCall()
-{
- return m_prog;
-}
-
-void CBotCStack::SetRetType(CBotTypResult& type)
-{
- m_retTyp = type;
-}
-
-CBotTypResult CBotCStack::GivRetType()
-{
- return m_retTyp;
-}
-
-void CBotCStack::SetVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
- m_var = var;
-}
-
-// met sur le stack une copie d'une variable
-void CBotCStack::SetCopyVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
-
- if ( var == NULL ) return;
- m_var = CBotVar::Create("", var->GivTypResult(2));
- m_var->Copy( var );
-}
-
-CBotVar* CBotCStack::GivVar()
-{
- return m_var;
-}
-
-void CBotCStack::AddVar(CBotVar* pVar)
-{
- CBotCStack* p = this;
-
- // revient sur l'élement père
- while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
-
- if ( p == NULL ) return;
-
- CBotVar** pp = &p->m_listVar;
- while ( *pp != NULL ) pp = &(*pp)->m_next;
-
- *pp = pVar; // ajoute à la suite
-
-#ifdef _DEBUG
- if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
-#endif
-}
-
-// test si une variable est déjà définie localement
-
-bool CBotCStack::CheckVarLocal(CBotToken* &pToken)
-{
- CBotCStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (name == pp->GivName())
- return true;
- pp = pp->m_next;
- }
- if ( p->m_bBlock ) return false;
- p = p->m_prev;
- }
- return false;
-}
-
-CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent)
-{
- nIdent = 0;
- CBotTypResult val(-1);
-
- val = CBotCall::CompileCall(p, ppVars, this, nIdent);
- if (val.GivType() < 0)
- {
- val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent);
- if ( val.GivType() < 0 )
- {
- // pVar = NULL; // l'erreur n'est pas sur un paramètre en particulier
- SetError( -val.GivType(), p );
- val.SetType(-val.GivType());
- return val;
- }
- }
- return val;
-}
-
-// test si un nom de procédure est déjà défini quelque part
-
-bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
-{
- CBotString name = pToken->GivString();
-
- if ( CBotCall::CheckCall(name) ) return true;
-
- CBotFunction* pp = m_prog->GivFunctions();
- 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();
- }
-
- pp = CBotFunction::m_listPublic;
- 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->m_nextpublic;
- }
-
- 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 the stack
+
+
+#include "CBot.h"
+#include <cstdlib>
+#include <cstring>
+
+
+#define ITIMER 100
+
+////////////////////////////////////////////////////////////////////////////
+// management of a execution of a stack
+////////////////////////////////////////////////////////////////////////////
+
+int CBotStack::m_initimer = ITIMER;
+int CBotStack::m_timer = 0;
+CBotVar* CBotStack::m_retvar = NULL;
+int CBotStack::m_error = 0;
+int CBotStack::m_start = 0;
+int CBotStack::m_end = 0;
+CBotString CBotStack::m_labelBreak="";
+void* CBotStack::m_pUser = NULL;
+
+#if STACKMEM
+
+CBotStack* CBotStack::FirstStack()
+{
+ CBotStack* p;
+
+ long size = sizeof(CBotStack);
+ size *= (MAXSTACK+10);
+
+ // request a slice of memory for the stack
+ p = (CBotStack*)malloc(size);
+
+ // completely empty
+ memset(p, 0, size);
+
+ p-> m_bBlock = true;
+ m_timer = m_initimer; // sets the timer at the beginning
+
+ CBotStack* pp = p;
+ pp += MAXSTACK;
+ int i;
+ for ( i = 0 ; i< 10 ; i++ )
+ {
+ pp->m_bOver = true;
+ pp ++;
+ }
+#ifdef _DEBUG
+ int n = 1;
+ pp = p;
+ for ( i = 0 ; i< MAXSTACK+10 ; i++ )
+ {
+ pp->m_index = n++;
+ pp ++;
+ }
+#endif
+
+ m_error = 0; // avoids deadlocks because m_error is static
+ return p;
+}
+
+CBotStack::CBotStack(CBotStack* ppapa)
+{
+ // constructor must exist or the destructor is never called!
+ ASM_TRAP();
+}
+
+CBotStack::~CBotStack()
+{
+ ASM_TRAP(); // use Delete () instead
+}
+
+void CBotStack::Delete()
+{
+ if ( this == NULL || this == EOX ) return;
+
+ m_next->Delete();
+ m_next2->Delete();
+
+ if (m_prev != NULL)
+ {
+ if ( m_prev->m_next == this )
+ m_prev->m_next = NULL; // removes chain
+
+ if ( m_prev->m_next2 == this )
+ m_prev->m_next2 = NULL; // removes chain
+ }
+
+ delete m_var;
+ delete m_listVar;
+
+ CBotStack* p = m_prev;
+ bool bOver = m_bOver;
+#ifdef _DEBUG
+ int n = m_index;
+#endif
+
+ // clears the freed block
+ memset(this, 0, sizeof(CBotStack));
+ m_bOver = bOver;
+#ifdef _DEBUG
+ m_index = n;
+#endif
+
+ if ( p == NULL )
+ free( this );
+}
+
+
+// routine improved
+CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ return m_next; // included in an existing stack
+ }
+
+#ifdef _DEBUG
+ int n = 0;
+#endif
+ CBotStack* p = this;
+ do
+ {
+ p ++;
+#ifdef _DEBUG
+ n ++;
+#endif
+ }
+ while ( p->m_prev != NULL );
+
+ m_next = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_instr = instr;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ p->m_prev = this;
+ p->m_state = 0;
+ p->m_call = NULL;
+ p->m_bFunc = false;
+ return p;
+}
+
+CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ if ( m_next == EOX )
+ {
+ m_next = NULL;
+ return EOX;
+ }
+ return m_next; // included in an existing stack
+ }
+ CBotStack* p = AddStack(NULL, bBlock);
+ p->m_call = instr;
+ p->m_bFunc = 2; // special
+ return p;
+}
+
+CBotStack* CBotStack::AddStack2(bool bBlock)
+{
+ if (m_next2 != NULL)
+ {
+ m_next2->m_prog = m_prog; // special avoids RestoreStack2
+ return m_next2; // included in an existing stack
+ }
+
+ CBotStack* p = this;
+ do
+ {
+ p ++;
+ }
+ while ( p->m_prev != NULL );
+
+ m_next2 = p; // chain an element
+ p->m_prev = this;
+ p->m_bBlock = bBlock;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ return p;
+}
+
+bool CBotStack::GivBlock()
+{
+ return m_bBlock;
+}
+
+bool CBotStack::Return(CBotStack* pfils)
+{
+ if ( pfils == this ) return true; // special
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ m_next->Delete();m_next = NULL; // releases the stack above
+ m_next2->Delete();m_next2 = NULL; // also the second stack (catch)
+
+ return (m_error == 0); // interrupted if error
+}
+
+bool CBotStack::ReturnKeep(CBotStack* pfils)
+{
+ if ( pfils == this ) return true; // special
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ return (m_error == 0); // interrupted if error
+}
+
+bool CBotStack::StackOver()
+{
+ if (!m_bOver) return false;
+ m_error = TX_STACKOVER;
+ return true;
+}
+
+#else
+
+CBotStack::CBotStack(CBotStack* ppapa)
+{
+ m_next = NULL;
+ m_next2 = NULL;
+ m_prev = ppapa;
+
+ m_bBlock = (ppapa == NULL) ? true : false;
+
+ m_state = 0;
+ m_step = 1;
+
+ if (ppapa == NULL) m_timer = m_initimer; // sets the timer at the beginning
+
+ m_listVar = NULL;
+ m_bDontDelete = false;
+
+ m_var = NULL;
+ m_prog = NULL;
+ m_instr = NULL;
+ m_call = NULL;
+ m_bFunc = false;
+}
+
+// destructor
+CBotStack::~CBotStack()
+{
+ if ( m_next != EOX) delete m_next;
+ delete m_next2;
+ if (m_prev != NULL && m_prev->m_next == this )
+ m_prev->m_next = NULL; // removes chain
+
+ delete m_var;
+ if ( !m_bDontDelete ) delete m_listVar;
+}
+
+// \TODO routine has/to optimize
+CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ return m_next; // included in an existing stack
+ }
+ CBotStack* p = new CBotStack(this);
+ m_next = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_instr = instr;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ return p;
+}
+
+CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ if ( m_next == EOX )
+ {
+ m_next = NULL;
+ return EOX;
+ }
+ return m_next; // included in an existing stack
+ }
+ CBotStack* p = new CBotStack(this);
+ m_next = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_call = instr;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ p->m_bFunc = 2; // special
+ return p;
+}
+
+CBotStack* CBotStack::AddStack2(bool bBlock)
+{
+ if (m_next2 != NULL)
+ {
+ m_next2->m_prog = m_prog; // special avoids RestoreStack2
+ return m_next2; // included in an existing stack
+ }
+
+ CBotStack* p = new CBotStack(this);
+ m_next2 = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+
+ return p;
+}
+
+bool CBotStack::Return(CBotStack* pfils)
+{
+ if ( pfils == this ) return true; // special
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // do not destroy the variable
+
+ if ( m_next != EOX ) delete m_next; // releases the stack above
+ delete m_next2;m_next2 = NULL; // also the second stack (catch)
+
+ return (m_error == 0); // interrupted if error
+}
+
+bool CBotStack::StackOver()
+{
+ return false; // no overflow check in this version
+}
+
+#endif
+
+void CBotStack::Reset(void* pUser)
+{
+ m_timer = m_initimer; // resets the timer
+ m_error = 0;
+// m_start = 0;
+// m_end = 0;
+ m_labelBreak.Empty();
+ m_pUser = pUser;
+}
+
+
+
+
+CBotStack* CBotStack::RestoreStack(CBotInstr* instr)
+{
+ if (m_next != NULL)
+ {
+ m_next->m_instr = instr; // reset (if recovery after )
+ m_next->m_prog = m_prog;
+ return m_next; // included in an existing stack
+ }
+ return NULL;
+}
+
+CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr)
+{
+ CBotStack* p = RestoreStack();
+ p->m_call = instr;
+ return p;
+}
+
+
+
+// routine for execution step by step
+bool CBotStack::IfStep()
+{
+ if ( m_initimer > 0 || m_step++ > 0 ) return false;
+ return true;
+}
+
+
+bool CBotStack::BreakReturn(CBotStack* pfils, const char* name)
+{
+ if ( m_error>=0 ) return false; // normal output
+ if ( m_error==-3 ) return false; // normal output (return current)
+
+ if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name))
+ return false; // it's not for me
+
+ m_error = 0;
+ m_labelBreak.Empty();
+ return Return(pfils);
+}
+
+bool CBotStack::IfContinue(int state, const char* name)
+{
+ if ( m_error != -2 ) return false;
+
+ if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name))
+ return false; // it's not for me
+
+ m_state = state; // where again?
+ m_error = 0;
+ m_labelBreak.Empty();
+ if ( m_next != EOX ) m_next->Delete(); // purge above stack
+ return true;
+}
+
+void CBotStack::SetBreak(int val, const char* name)
+{
+ m_error = -val; // reacts as an Exception
+ m_labelBreak = name;
+ if (val == 3) // for a return
+ {
+ m_retvar = m_var;
+ m_var = NULL;
+ }
+}
+
+// gives on the stack value calculated by the last CBotReturn
+
+bool CBotStack::GivRetVar(bool bRet)
+{
+ if (m_error == -3)
+ {
+ if ( m_var ) delete m_var;
+ m_var = m_retvar;
+ m_retvar = NULL;
+ m_error = 0;
+ return true;
+ }
+ return bRet; // interrupted by something other than return
+}
+
+int CBotStack::GivError(int& start, int& end)
+{
+ start = m_start;
+ end = m_end;
+ return m_error;
+}
+
+
+int CBotStack::GivType(int mode)
+{
+ if (m_var == NULL) return -1;
+ return m_var->GivType(mode);
+}
+
+CBotTypResult CBotStack::GivTypResult(int mode)
+{
+ if (m_var == NULL) return -1;
+ return m_var->GivTypResult(mode);
+}
+
+void CBotStack::SetType(CBotTypResult& type)
+{
+ if (m_var == NULL) return;
+ m_var->SetType( type );
+}
+
+
+CBotVar* CBotStack::FindVar(CBotToken* &pToken, bool bUpdate, bool bModif)
+{
+ CBotStack* p = this;
+ CBotString name = pToken->GivString();
+
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (pp->GivName() == name)
+ {
+ if ( bUpdate )
+ pp->Maj(m_pUser, false);
+
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+CBotVar* CBotStack::FindVar(const char* name)
+{
+ CBotStack* p = this;
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (pp->GivName() == name)
+ {
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+CBotVar* CBotStack::FindVar(long ident, bool bUpdate, bool bModif)
+{
+ CBotStack* p = this;
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (pp->GivUniqNum() == ident)
+ {
+ if ( bUpdate )
+ pp->Maj(m_pUser, false);
+
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+
+CBotVar* CBotStack::FindVar(CBotToken& Token, bool bUpdate, bool bModif)
+{
+ CBotToken* pt = &Token;
+ return FindVar(pt, bUpdate, bModif);
+}
+
+
+CBotVar* CBotStack::CopyVar(CBotToken& Token, bool bUpdate)
+{
+ CBotVar* pVar = FindVar( Token, bUpdate );
+
+ if ( pVar == NULL) return NULL;
+
+ CBotVar* pCopy = CBotVar::Create(pVar);
+ pCopy->Copy(pVar);
+ return pCopy;
+}
+
+
+bool CBotStack::SetState(int n, int limite)
+{
+ m_state = n;
+
+ m_timer--; // decrement the operations \TODO decrement the operations
+ return ( m_timer > limite ); // interrupted if timer pass
+}
+
+bool CBotStack::IncState(int limite)
+{
+ m_state++;
+
+ m_timer--; // decrement the operations \TODO decompte les operations
+ return ( m_timer > limite ); // interrupted if timer pass
+}
+
+
+void CBotStack::SetError(int n, CBotToken* token)
+{
+ if ( n!= 0 && m_error != 0) return; // does not change existing error
+ m_error = n;
+ if (token != NULL)
+ {
+ m_start = token->GivStart();
+ m_end = token->GivEnd();
+ }
+}
+
+void CBotStack::ResetError(int n, int start, int end)
+{
+ m_error = n;
+ m_start = start;
+ m_end = end;
+}
+
+void CBotStack::SetPosError(CBotToken* token)
+{
+ m_start = token->GivStart();
+ m_end = token->GivEnd();
+}
+
+void CBotStack::SetTimer(int n)
+{
+ m_initimer = n;
+}
+
+bool CBotStack::Execute()
+{
+ CBotCall* instr = NULL; // the most highest instruction
+ CBotStack* pile;
+
+ CBotStack* p = this;
+
+ while (p != NULL)
+ {
+ if ( p->m_next2 != NULL ) break;
+ if ( p->m_call != NULL )
+ {
+ instr = p->m_call;
+ pile = p->m_prev ;
+ }
+ p = p->m_next;
+ }
+
+ if ( instr == NULL ) return true; // normal execution request
+
+ if (!instr->Run(pile)) return false; // \TODO exécution à partir de là
+
+#if STACKMEM
+ pile->m_next->Delete();
+#else
+ delete pile->m_next;
+#endif
+
+ pile->m_next = EOX; // special for recovery
+ return true;
+}
+
+// puts on the stack pointer to a variable
+void CBotStack::SetVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+ m_var = var;
+}
+
+// puts on the stack a copy of a variable
+void CBotStack::SetCopyVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+
+ m_var = CBotVar::Create("", var->GivTypResult(2));
+ m_var->Copy( var );
+}
+
+CBotVar* CBotStack::GivVar()
+{
+ return m_var;
+}
+
+CBotVar* CBotStack::GivPtVar()
+{
+ CBotVar* p = m_var;
+ m_var = NULL; // therefore will not be destroyed
+ return p;
+}
+
+CBotVar* CBotStack::GivCopyVar()
+{
+ if (m_var == NULL) return NULL;
+ CBotVar* v = CBotVar::Create("", m_var->GivType());
+ v->Copy( m_var );
+ return v;
+}
+
+long CBotStack::GivVal()
+{
+ if (m_var == NULL) return 0;
+ return m_var->GivValInt();
+}
+
+
+
+
+void CBotStack::AddVar(CBotVar* pVar)
+{
+ CBotStack* p = this;
+
+ // returns to the father element
+ while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
+
+ if ( p == NULL ) return;
+
+/// p->m_bDontDelete = bDontDelete;
+
+ CBotVar** pp = &p->m_listVar;
+ while ( *pp != NULL ) pp = &(*pp)->m_next;
+
+ *pp = pVar; // added after
+
+#ifdef _DEBUG
+ if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
+#endif
+}
+
+/*void CBotStack::RestoreVar(CBotVar* pVar)
+{
+ if ( !m_bDontDelete ) __asm int 3;
+ delete m_listVar;
+ m_listVar = pVar; // direct replacement
+}*/
+
+void CBotStack::SetBotCall(CBotProgram* p)
+{
+ m_prog = p;
+ m_bFunc = true;
+}
+
+CBotProgram* CBotStack::GivBotCall(bool bFirst)
+{
+ if ( ! bFirst ) return m_prog;
+ CBotStack* p = this;
+ while ( p->m_prev != NULL ) p = p->m_prev;
+ return p->m_prog;
+}
+
+void* CBotStack::GivPUser()
+{
+ return m_pUser;
+}
+
+
+bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype)
+{
+ CBotTypResult res;
+
+ // first looks by the identifier
+
+ res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype );
+ if (res.GivType() >= 0) return res.GivType();
+
+ res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token );
+ if (res.GivType() >= 0) return res.GivType();
+
+ // if not found (recompile?) seeks by name
+
+ nIdent = 0;
+ res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype );
+ if (res.GivType() >= 0) return res.GivType();
+
+ res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token );
+ if (res.GivType() >= 0) return res.GivType();
+
+ SetError(TX_NOCALL, token);
+ return true;
+}
+
+void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
+{
+ if ( m_next == NULL ) return;
+
+ if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) )
+ m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this );
+}
+
+
+bool SaveVar(FILE* pf, CBotVar* pVar)
+{
+ while ( true )
+ {
+ if ( pVar == NULL )
+ {
+ return WriteWord(pf, 0); // is a terminator
+ }
+
+ if ( !pVar->Save0State(pf)) return false; // common header
+ if ( !pVar->Save1State(pf) ) return false; // saves as the child class
+
+ pVar = pVar->GivNext();
+ }
+}
+
+void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end)
+{
+ CBotProgram* prog = m_prog; // Current program
+
+ CBotInstr* funct = NULL; // function found
+ CBotInstr* instr = NULL; // the highest intruction
+
+ CBotStack* p = this;
+
+ while (p->m_next != NULL)
+ {
+ if ( p->m_instr != NULL ) instr = p->m_instr;
+ if ( p->m_bFunc == 1 ) funct = p->m_instr;
+ if ( p->m_next->m_prog != prog ) break ;
+
+ if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
+ else p = p->m_next;
+ }
+
+ if ( p->m_instr != NULL ) instr = p->m_instr;
+ if ( p->m_bFunc == 1 ) funct = p->m_instr;
+
+ if ( funct == NULL ) return;
+
+ CBotToken* t = funct->GivToken();
+ FunctionName = t->GivString();
+
+// if ( p->m_instr != NULL ) instr = p->m_instr;
+
+ t = instr->GivToken();
+ start = t->GivStart();
+ end = t->GivEnd();
+}
+
+CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level)
+{
+ CBotProgram* prog = m_prog; // current program
+ FunctionName = NULL;
+
+ // back the stack in the current module
+ CBotStack* p = this;
+
+ while (p->m_next != NULL)
+ {
+ if ( p->m_next->m_prog != prog ) break ;
+
+ if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
+ else p = p->m_next;
+ }
+
+
+ // descends upon the elements of block
+ while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
+
+ while ( p != NULL && level++ < 0 )
+ {
+ p = p->m_prev;
+ while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
+ }
+
+ if ( p == NULL ) return NULL;
+
+ // search the name of the current function
+ CBotStack* pp = p;
+ while ( pp != NULL )
+ {
+ if ( pp->m_bFunc == 1 ) break;
+ pp = pp->m_prev;
+ }
+
+ if ( pp == NULL || pp->m_instr == NULL ) return NULL;
+
+ CBotToken* t = pp->m_instr->GivToken();
+ FunctionName = t->GivString();
+
+ return p->m_listVar;
+}
+
+bool CBotStack::SaveState(FILE* pf)
+{
+ if ( this == NULL ) // end of the tree?
+ {
+ return WriteWord(pf, 0); // is a terminator
+ }
+
+ if ( m_next2 != NULL )
+ {
+ if (!WriteWord(pf, 2)) return false; // a mark of pursuit
+ if (!m_next2->SaveState(pf)) return false;
+ }
+ else
+ {
+ if (!WriteWord(pf, 1)) return false; // a mark of pursuit
+ }
+ if (!WriteWord(pf, m_bBlock)) return false; // is a local block
+ if (!WriteWord(pf, m_state)) return false; // in what state?
+ if (!WriteWord(pf, 0)) return false; // by compatibility m_bDontDelete
+ if (!WriteWord(pf, m_step)) return false; // in what state?
+
+
+ if (!SaveVar(pf, m_var)) return false; // current result
+ if (!SaveVar(pf, m_listVar)) return false; // local variables
+
+ return m_next->SaveState(pf); // saves the following
+}
+
+
+bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
+{
+ unsigned short w;
+
+ pStack = NULL;
+ if (!ReadWord(pf, w)) return false;
+ if ( w == 0 ) return true;
+
+#if STACKMEM
+ if ( this == NULL ) pStack = FirstStack();
+ else pStack = AddStack();
+#else
+ pStack = new CBotStack(this);
+#endif
+
+ if ( w == 2 )
+ {
+ if (!pStack->RestoreState(pf, pStack->m_next2)) return false;
+ }
+
+ if (!ReadWord(pf, w)) return false; // is a local block
+ pStack->m_bBlock = w;
+
+ if (!ReadWord(pf, w)) return false; // in what state ?
+ pStack->SetState((short)w); // in a good state
+
+ if (!ReadWord(pf, w)) return false; // dont delete?
+ // uses more
+
+ if (!ReadWord(pf, w)) return false; // step by step
+ pStack->m_step = w;
+
+ if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // temp variable
+ if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// local variables
+
+ return pStack->RestoreState(pf, pStack->m_next);
+}
+
+
+bool CBotVar::Save0State(FILE* pf)
+{
+ if (!WriteWord(pf, 100+m_mPrivate))return false; // private variable?
+ if (!WriteWord(pf, m_bStatic))return false; // static variable?
+ if (!WriteWord(pf, m_type.GivType()))return false; // saves the type (always non-zero)
+ if (!WriteWord(pf, m_binit))return false; // variable defined?
+ return WriteString(pf, m_token->GivString()); // and variable name
+}
+
+bool CBotVarInt::Save0State(FILE* pf)
+{
+ if ( !m_defnum.IsEmpty() )
+ {
+ if(!WriteWord(pf, 200 )) return false; // special marker
+ if(!WriteString(pf, m_defnum)) return false; // name of the value
+ }
+
+ return CBotVar::Save0State(pf);
+}
+
+bool CBotVarInt::Save1State(FILE* pf)
+{
+ return WriteWord(pf, m_val); // the value of the variable
+}
+
+bool CBotVarBoolean::Save1State(FILE* pf)
+{
+ return WriteWord(pf, m_val); // the value of the variable
+}
+
+bool CBotVarFloat::Save1State(FILE* pf)
+{
+ return WriteFloat(pf, m_val); // the value of the variable
+}
+
+bool CBotVarString::Save1State(FILE* pf)
+{
+ return WriteString(pf, m_val); // the value of the variable
+}
+
+
+
+bool CBotVarClass::Save1State(FILE* pf)
+{
+ if ( !WriteType(pf, m_type) ) return false;
+ if ( !WriteLong(pf, m_ItemIdent) ) return false;
+
+ return SaveVar(pf, m_pVar); // content of the object
+}
+
+bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
+{
+ unsigned short w, wi, prv, st;
+ float ww;
+ CBotString name, s;
+
+ delete pVar;
+
+ pVar = NULL;
+ CBotVar* pNew = NULL;
+ CBotVar* pPrev = NULL;
+
+ while ( true ) // retrieves a list
+ {
+ if (!ReadWord(pf, w)) return false; // private or type?
+ if ( w == 0 ) return true;
+
+ CBotString defnum;
+ if ( w == 200 )
+ {
+ if (!ReadString(pf, defnum)) return false; // number with identifier
+ if (!ReadWord(pf, w)) return false; // type
+ }
+
+ prv = 100; st = 0;
+ if ( w >= 100 )
+ {
+ prv = w;
+ if (!ReadWord(pf, st)) return false; // static
+ if (!ReadWord(pf, w)) return false; // type
+ }
+
+ if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic
+
+ if (!ReadWord(pf, wi)) return false; // init ?
+
+ if (!ReadString(pf, name)) return false; // variable name
+
+ CBotToken token(name, CBotString());
+
+ switch (w)
+ {
+ case CBotTypInt:
+ case CBotTypBoolean:
+ pNew = CBotVar::Create(&token, w); // creates a variable
+ if (!ReadWord(pf, w)) return false;
+ pNew->SetValInt((short)w, defnum);
+ break;
+ case CBotTypFloat:
+ pNew = CBotVar::Create(&token, w); // creates a variable
+ if (!ReadFloat(pf, ww)) return false;
+ pNew->SetValFloat(ww);
+ break;
+ case CBotTypString:
+ pNew = CBotVar::Create(&token, w); // creates a variable
+ if (!ReadString(pf, s)) return false;
+ pNew->SetValString(s);
+ break;
+
+ // returns an intrinsic object or element of an array
+ case CBotTypIntrinsic:
+ case CBotTypArrayBody:
+ {
+ CBotTypResult r;
+ long id;
+ if (!ReadType(pf, r)) return false; // complete type
+ if (!ReadLong(pf, id) ) return false;
+
+// if (!ReadString(pf, s)) return false;
+ {
+ CBotVar* p = NULL;
+ if ( id ) p = CBotVarClass::Find(id) ;
+
+ pNew = new CBotVarClass(&token, r); // directly creates an instance
+ // attention cptuse = 0
+ if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return false;
+ pNew->SetIdent(id);
+
+ if ( p != NULL )
+ {
+ delete pNew;
+ pNew = p; // resume known element
+ }
+ }
+ }
+ break;
+
+ case CBotTypPointer:
+ case CBotTypNullPointer:
+ if (!ReadString(pf, s)) return false;
+ {
+ pNew = CBotVar::Create(&token, CBotTypResult(w, s));// creates a variable
+ CBotVarClass* p = NULL;
+ long id;
+ ReadLong(pf, id);
+// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance)
+
+ // returns a copy of the original instance
+ CBotVar* pInstance = NULL;
+ if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
+ ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over
+
+// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // rather this one
+
+ }
+ break;
+
+ case CBotTypArrayPointer:
+ {
+ CBotTypResult r;
+ if (!ReadType(pf, r)) return false;
+
+ pNew = CBotVar::Create(&token, r); // creates a variable
+
+ // returns a copy of the original instance
+ CBotVar* pInstance = NULL;
+ if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
+ ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over
+ }
+ break;
+ default:
+ ASM_TRAP();
+ }
+
+ if ( pPrev != NULL ) pPrev->m_next = pNew;
+ if ( pVar == NULL ) pVar = pNew;
+
+ pNew->m_binit = wi; // pNew->SetInit(wi);
+ pNew->SetStatic(st);
+ pNew->SetPrivate(prv-100);
+ pPrev = pNew;
+ }
+ return true;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////
+// management of the compile stack
+////////////////////////////////////////////////////////////////////////////
+
+CBotProgram* CBotCStack::m_prog = NULL; // init the static variable
+int CBotCStack::m_error = 0;
+int CBotCStack::m_end = 0;
+CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0);
+//CBotToken* CBotCStack::m_retClass= NULL;
+
+
+CBotCStack::CBotCStack(CBotCStack* ppapa)
+{
+ m_next = NULL;
+ m_prev = ppapa;
+
+ if (ppapa == NULL)
+ {
+ m_error = 0;
+ m_start = 0;
+ m_end = 0;
+ m_bBlock = true;
+ }
+ else
+ {
+ m_start = ppapa->m_start;
+ m_bBlock = false;
+ }
+
+ m_listVar = NULL;
+ m_var = NULL;
+}
+
+// destructor
+CBotCStack::~CBotCStack()
+{
+ if (m_next != NULL) delete m_next;
+ if (m_prev != NULL) m_prev->m_next = NULL; // removes chain
+
+ delete m_var;
+ delete m_listVar;
+}
+
+// used only at compile
+CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock)
+{
+ if (m_next != NULL) return m_next; // include on an existing stack
+
+ CBotCStack* p = new CBotCStack(this);
+ m_next = p; // channel element
+ p->m_bBlock = bBlock;
+
+ if (pToken != NULL) p->SetStartError(pToken->GivStart());
+
+ return p;
+}
+
+
+CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils)
+{
+ if ( pfils == this ) return inst;
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ if (m_error)
+ {
+ m_start = pfils->m_start; // retrieves the position of the error
+ m_end = pfils->m_end;
+ }
+
+ delete pfils;
+ return inst;
+}
+
+CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils)
+{
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ if (m_error)
+ {
+ m_start = pfils->m_start; // retrieves the position of the error
+ m_end = pfils->m_end;
+ }
+
+ delete pfils;
+ return inst;
+}
+
+int CBotCStack::GivError(int& start, int& end)
+{
+ start = m_start;
+ end = m_end;
+ return m_error;
+}
+
+int CBotCStack::GivError()
+{
+ return m_error;
+}
+
+// type of instruction on the stack
+CBotTypResult CBotCStack::GivTypResult(int mode)
+{
+ if (m_var == NULL)
+ return CBotTypResult(99);
+ return m_var->GivTypResult(mode);
+}
+
+// type of instruction on the stack
+int CBotCStack::GivType(int mode)
+{
+ if (m_var == NULL)
+ return 99;
+ return m_var->GivType(mode);
+}
+
+// pointer on the stack is in what class?
+CBotClass* CBotCStack::GivClass()
+{
+ if ( m_var == NULL )
+ return NULL;
+ if ( m_var->GivType(1) != CBotTypPointer ) return NULL;
+
+ return m_var->GivClass();
+}
+
+// type of instruction on the stack
+void CBotCStack::SetType(CBotTypResult& type)
+{
+ if (m_var == NULL) return;
+ m_var->SetType( type );
+}
+
+// seeks a variable on the stack
+// the token may be a result of TokenTypVar (object of a class)
+// or a pointer in the source
+
+CBotVar* CBotCStack::FindVar(CBotToken* &pToken)
+{
+ CBotCStack* p = this;
+ CBotString name = pToken->GivString();
+
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (name == pp->GivName())
+ {
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+CBotVar* CBotCStack::FindVar(CBotToken& Token)
+{
+ CBotToken* pt = &Token;
+ return FindVar(pt);
+}
+
+CBotVar* CBotCStack::CopyVar(CBotToken& Token)
+{
+ CBotVar* pVar = FindVar( Token );
+
+ if ( pVar == NULL) return NULL;
+
+ CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() );
+ pCopy->Copy(pVar);
+ return pCopy;
+}
+
+bool CBotCStack::IsOk()
+{
+ return (m_error == 0);
+}
+
+
+void CBotCStack::SetStartError( int pos )
+{
+ if ( m_error != 0) return; // does not change existing error
+ m_start = pos;
+}
+
+void CBotCStack::SetError(int n, int pos)
+{
+ if ( n!= 0 && m_error != 0) return; // does not change existing error
+ m_error = n;
+ m_end = pos;
+}
+
+void CBotCStack::SetError(int n, CBotToken* p)
+{
+ if (m_error) return; // does not change existing error
+ m_error = n;
+ m_start = p->GivStart();
+ m_end = p->GivEnd();
+}
+
+void CBotCStack::ResetError(int n, int start, int end)
+{
+ m_error = n;
+ m_start = start;
+ m_end = end;
+}
+
+bool CBotCStack::NextToken(CBotToken* &p)
+{
+ CBotToken* pp = p;
+
+ p = p->GivNext();
+ if (p!=NULL) return true;
+
+ SetError(TX_ENDOF, pp->GivEnd());
+ return false;
+}
+
+void CBotCStack::SetBotCall(CBotProgram* p)
+{
+ m_prog = p;
+}
+
+CBotProgram* CBotCStack::GivBotCall()
+{
+ return m_prog;
+}
+
+void CBotCStack::SetRetType(CBotTypResult& type)
+{
+ m_retTyp = type;
+}
+
+CBotTypResult CBotCStack::GivRetType()
+{
+ return m_retTyp;
+}
+
+void CBotCStack::SetVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+ m_var = var;
+}
+
+// puts on the stack a copy of a variable
+void CBotCStack::SetCopyVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+
+ if ( var == NULL ) return;
+ m_var = CBotVar::Create("", var->GivTypResult(2));
+ m_var->Copy( var );
+}
+
+CBotVar* CBotCStack::GivVar()
+{
+ return m_var;
+}
+
+void CBotCStack::AddVar(CBotVar* pVar)
+{
+ CBotCStack* p = this;
+
+ // returns to the father element
+ while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
+
+ if ( p == NULL ) return;
+
+ CBotVar** pp = &p->m_listVar;
+ while ( *pp != NULL ) pp = &(*pp)->m_next;
+
+ *pp = pVar; // added after
+
+#ifdef _DEBUG
+ if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
+#endif
+}
+
+// test whether a variable is already defined locally
+
+bool CBotCStack::CheckVarLocal(CBotToken* &pToken)
+{
+ CBotCStack* p = this;
+ CBotString name = pToken->GivString();
+
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (name == pp->GivName())
+ return true;
+ pp = pp->m_next;
+ }
+ if ( p->m_bBlock ) return false;
+ p = p->m_prev;
+ }
+ return false;
+}
+
+CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent)
+{
+ nIdent = 0;
+ CBotTypResult val(-1);
+
+ val = CBotCall::CompileCall(p, ppVars, this, nIdent);
+ if (val.GivType() < 0)
+ {
+ val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent);
+ if ( val.GivType() < 0 )
+ {
+ // pVar = NULL; // the error is not on a particular parameter
+ SetError( -val.GivType(), p );
+ val.SetType(-val.GivType());
+ return val;
+ }
+ }
+ return val;
+}
+
+// test if a procedure name is already defined somewhere
+
+bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
+{
+ CBotString name = pToken->GivString();
+
+ if ( CBotCall::CheckCall(name) ) return true;
+
+ CBotFunction* pp = m_prog->GivFunctions();
+ while ( pp != NULL )
+ {
+ if ( pToken->GivString() == pp->GivName() )
+ {
+ // are parameters exactly the same?
+ if ( pp->CheckParam( pParam ) )
+ return true;
+ }
+ pp = pp->Next();
+ }
+
+ pp = CBotFunction::m_listPublic;
+ while ( pp != NULL )
+ {
+ if ( pToken->GivString() == pp->GivName() )
+ {
+ // are parameters exactly the same?
+ if ( pp->CheckParam( pParam ) )
+ return true;
+ }
+ pp = pp->m_nextpublic;
+ }
+
+ return false;
+}
+
diff --git a/src/CBot/CBotString.cpp b/src/CBot/CBotString.cpp
index 9d5d257..6acd96e 100644
--- a/src/CBot/CBotString.cpp
+++ b/src/CBot/CBotString.cpp
@@ -12,7 +12,8 @@
// * 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/./////////////////////////////////////////////////////
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+/////////////////////////////////////////////////////
//strings management
diff --git a/src/CBot/CBotToken.h b/src/CBot/CBotToken.h
index 35a696a..8e9d1e3 100644
--- a/src/CBot/CBotToken.h
+++ b/src/CBot/CBotToken.h
@@ -32,6 +32,7 @@
// x
// )
+#pragma once
extern bool IsOfType(CBotToken* &p, int type1, int type2 = -1);
extern bool IsOfTypeList(CBotToken* &p, int type1, ...);
diff --git a/src/CBot/CBotTwoOpExpr.cpp b/src/CBot/CBotTwoOpExpr.cpp
index e2523b5..49cfcc8 100644
--- a/src/CBot/CBotTwoOpExpr.cpp
+++ b/src/CBot/CBotTwoOpExpr.cpp
@@ -1,566 +1,568 @@
-// * 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/.///////////////////////////////////////////////////
-// expression du genre Opérande1 + Opérande2
-// Opérande1 > Opérande2
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotTwoOpExpr::CBotTwoOpExpr()
-{
- m_leftop =
- m_rightop = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotTwoOpExpr"; // debug
-}
-
-CBotTwoOpExpr::~CBotTwoOpExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-CBotLogicExpr::CBotLogicExpr()
-{
- m_condition =
- m_op1 =
- m_op2 = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotLogicExpr"; // debug
-}
-
-CBotLogicExpr::~CBotLogicExpr()
-{
- delete m_condition;
- delete m_op1;
- delete m_op2;
-}
-
-
-// type d'opérandes acceptés par les opérations
-#define ENTIER ((1<<CBotTypByte)|(1<<CBotTypShort)|(1<<CBotTypChar)|(1<<CBotTypInt)|(1<<CBotTypLong))
-#define FLOTANT ((1<<CBotTypFloat)|(1<<CBotTypDouble))
-#define BOOLEEN (1<<CBotTypBoolean)
-#define CHAINE (1<<CBotTypString)
-#define POINTER (1<<CBotTypPointer)
-#define INSTANCE (1<<CBotTypClass)
-
-// liste des opérations (précéance)
-// type acceptable, opérande
-// le zéro termine un niveau de précéance
-
-static int ListOp[] =
-{
- BOOLEEN, ID_LOGIC, 0,
- BOOLEEN, ID_TXT_OR,
- BOOLEEN, ID_LOG_OR, 0,
- BOOLEEN, ID_TXT_AND,
- BOOLEEN, ID_LOG_AND, 0,
- BOOLEEN|ENTIER, ID_OR, 0,
- BOOLEEN|ENTIER, ID_XOR, 0,
- BOOLEEN|ENTIER, ID_AND, 0,
- BOOLEEN|ENTIER|FLOTANT
- |CHAINE
- |POINTER
- |INSTANCE,ID_EQ,
- BOOLEEN|ENTIER|FLOTANT
- |CHAINE
- |POINTER
- |INSTANCE,ID_NE, 0,
- ENTIER|FLOTANT|CHAINE, ID_HI,
- ENTIER|FLOTANT|CHAINE, ID_LO,
- ENTIER|FLOTANT|CHAINE, ID_HS,
- ENTIER|FLOTANT|CHAINE, ID_LS, 0,
- ENTIER, ID_SR,
- ENTIER, ID_SL,
- ENTIER, ID_ASR, 0,
- ENTIER|FLOTANT|CHAINE, ID_ADD,
- ENTIER|FLOTANT, ID_SUB, 0,
- ENTIER|FLOTANT, ID_MUL,
- ENTIER|FLOTANT, ID_DIV,
- ENTIER|FLOTANT, ID_MODULO, 0,
- ENTIER|FLOTANT, ID_POWER, 0,
- 0,
-};
-
-bool IsInList( int val, int* list, int& typemasque )
-{
- while (true)
- {
- if ( *list == 0 ) return false;
- typemasque = *list++;
- if ( *list++ == val ) return true;
- }
-}
-
-bool TypeOk( int type, int test )
-{
- while (true)
- {
- if ( type == 0 ) return (test & 1);
- type--; test /= 2;
- }
-}
-
-// compile une instruction de type A op B
-
-CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations)
-{
- int typemasque;
-
- if ( pOperations == NULL ) pOperations = ListOp;
- int* pOp = pOperations;
- while ( *pOp++ != 0 ); // suite de la table
-
- CBotCStack* pStk = pStack->TokenStack(); // un bout de pile svp
-
- // cherche des instructions qui peuvent convenir à gauche de l'opération
- CBotInstr* left = (*pOp == 0) ?
- CBotParExpr::Compile( p, pStk ) : // expression (...) à gauche
- CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B à gauche
-
- if (left == NULL) return pStack->Return(NULL, pStk); // si erreur, la transmet
-
- // est-ce qu'on a l'opérande prévu ensuite ?
- int TypeOp = p->GivType();
- if ( IsInList( TypeOp, pOperations, typemasque ) )
- {
- CBotTypResult type1, type2;
- type1 = pStk->GivTypResult(); // de quel type le premier opérande ?
-
- if ( TypeOp == ID_LOGIC ) // cas spécial pour condition ? op1 : op2 ;
- {
- if ( !type1.Eq(CBotTypBoolean) )
- {
- pStk->SetError( TX_BADTYPE, p);
- return pStack->Return(NULL, pStk);
- }
- CBotLogicExpr* inst = new CBotLogicExpr();
- inst->m_condition = left;
-
- p = p->GivNext(); // saute le token de l'opération
- inst->m_op1 = CBotExpression::Compile(p, pStk);
- CBotToken* pp = p;
- if ( inst->m_op1 == NULL || !IsOfType( p, ID_DOTS ) )
- {
- pStk->SetError( TX_MISDOTS, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- type1 = pStk->GivTypResult();
-
- inst->m_op2 = CBotExpression::Compile(p, pStk);
- if ( inst->m_op2 == NULL )
- {
- pStk->SetError( TX_ENDOF, p->GivStart() );
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- type2 = pStk->GivTypResult();
- if (!TypeCompatible(type1, type2))
- {
- pStk->SetError( TX_BAD2TYPE, pp );
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- pStk->SetType(type1); // le plus grand des 2 types
-
- return pStack->Return(inst, pStk);
- }
-
- CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
-
- p = p->GivNext(); // saute le token de l'opération
-
- // cherche des instructions qui peuvent convenir à droite
-
- if ( NULL != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) )
- // expression (...) à droite
- {
- // il y a un second opérande acceptable
-
- type2 = pStk->GivTypResult(); // de quel type le résultat ?
-
- // quel est le type du résultat ?
- int TypeRes = MAX( type1.GivType(3), type2.GivType(3) );
- if ( TypeOp == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- type2 = type1; // tout type convertible en chaîne
- }
- else if ( TypeOp == ID_ADD && type2.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- type1 = type2; // tout type convertible en chaîne
- }
- else if (!TypeOk( TypeRes, typemasque )) type1.SetType(99);// erreur de type
-
- switch ( TypeOp )
- {
- case ID_LOG_OR:
- case ID_LOG_AND:
- case ID_TXT_OR:
- case ID_TXT_AND:
- case ID_EQ:
- case ID_NE:
- case ID_HI:
- case ID_LO:
- case ID_HS:
- case ID_LS:
- TypeRes = CBotTypBoolean;
- }
- if ( TypeCompatible (type1, type2, TypeOp ) ) // les résultats sont-ils compatibles
- {
- // si ok, enregistre l'opérande dans l'objet
- inst->m_leftop = left;
-
- // spécial pour évaluer les opérations de même niveau de gauche à droite
- while ( IsInList( p->GivType(), pOperations, typemasque ) ) // même(s) opération(s) suit ?
- {
- TypeOp = p->GivType();
- CBotTwoOpExpr* i = new CBotTwoOpExpr(); // élément pour opération
- i->SetToken(p); // mémorise l'opération
- i->m_leftop = inst; // opérande de gauche
- type1 = TypeRes;
-
- p = p->GivNext(); // avance à la suite
- i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp );
- type2 = pStk->GivTypResult();
-
- if ( !TypeCompatible (type1, type2, TypeOp) ) // les résultats sont-ils compatibles
- {
- pStk->SetError(TX_BAD2TYPE, &i->m_token);
- delete i;
- return pStack->Return(NULL, pStk);
- }
-
- if ( TypeRes != CBotTypString )
- TypeRes = MAX(type1.GivType(), type2.GivType());
- inst = i;
- }
-
- CBotTypResult t(type1);
- t.SetType(TypeRes);
- // met une variable sur la pile pour avoir le type de résultat
- pStk->SetVar(CBotVar::Create((CBotToken*)NULL, t));
-
- // et rend l'object à qui l'a demandé
- return pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_BAD2TYPE, &inst->m_token);
- }
-
- // en cas d'erreur, libère les éléments
- delete left;
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile
- return pStack->Return(NULL, pStk);
- }
-
- // si on n'a pas affaire à une opération + ou -
- // rend à qui l'a demandé, l'opérande (de gauche) trouvé
- // à la place de l'objet "addition"
- return pStack->Return(left, pStk);
-}
-
-
-bool IsNan(CBotVar* left, CBotVar* right, int* err = NULL)
-{
- if ( left ->GivInit() > IS_DEF || right->GivInit() > IS_DEF )
- {
- if ( err != NULL ) *err = TX_OPNAN ;
- return true;
- }
- return false;
-}
-
-
-// fait l'opération sur 2 opérandes
-
-bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pStk1 == EOX ) return true;
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GivState() == 0 ) // 1er état, évalue l'opérande de gauche
- {
- if (!m_leftop->Execute(pStk1) ) return false; // interrompu ici ?
-
- // pour les OU et ET logique, n'évalue pas la seconde expression si pas nécessaire
- if ( (GivTokenType() == ID_LOG_AND || GivTokenType() == ID_TXT_AND ) && pStk1->GivVal() == false )
- {
- CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
- res->SetValInt(false);
- pStk1->SetVar(res);
- return pStack->Return(pStk1); // transmet le résultat
- }
- if ( (GivTokenType() == ID_LOG_OR||GivTokenType() == ID_TXT_OR) && pStk1->GivVal() == true )
- {
- CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
- res->SetValInt(true);
- pStk1->SetVar(res);
- return pStack->Return(pStk1); // transmet le résultat
- }
-
- // passe à l'étape suivante
- pStk1->SetState(1); // prêt pour la suite
- }
-
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- // qui se trouve sur la pile, justement.
-
- CBotStack* pStk2 = pStk1->AddStack(); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-
- // 2e état, évalue l'opérande de droite
- if ( pStk2->GivState() == 0 )
- {
- if ( !m_rightop->Execute(pStk2) ) return false; // interrompu ici ?
- pStk2->IncState();
- }
-
- CBotTypResult type1 = pStk1->GivTypResult(); // de quels types les résultats ?
- CBotTypResult type2 = pStk2->GivTypResult();
-
- CBotStack* pStk3 = pStk2->AddStack(this); // ajoute un élément à la pile
- if ( pStk3->IfStep() ) return false; // montre l'opération si step by step
-
- // crée une variable temporaire pour y mettre le résultat
- // quel est le type du résultat ?
- int TypeRes = MAX(type1.GivType(), type2.GivType());
-
- if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- }
-
- switch ( GivTokenType() )
- {
- case ID_LOG_OR:
- case ID_LOG_AND:
- case ID_TXT_OR:
- case ID_TXT_AND:
- case ID_EQ:
- case ID_NE:
- case ID_HI:
- case ID_LO:
- case ID_HS:
- case ID_LS:
- TypeRes = CBotTypBoolean;
- break;
- case ID_DIV:
- TypeRes = MAX(TypeRes, CBotTypFloat);
- }
-
- // crée une variable pour le résultat
- CBotVar* result = CBotVar::Create( (CBotToken*)NULL, TypeRes);
-
- // crée une variable pour effectuer le calcul dans le type adapté
- TypeRes = MAX(type1.GivType(), type2.GivType());
-
- if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- }
-
- CBotVar* temp;
-
- if ( TypeRes == CBotTypPointer ) TypeRes = CBotTypNullPointer;
- if ( TypeRes == CBotTypClass ) temp = CBotVar::Create( (CBotToken*)NULL, CBotTypResult(CBotTypIntrinsic, type1.GivClass() ) );
- else temp = CBotVar::Create( (CBotToken*)NULL, TypeRes );
-
- int err = 0;
- // fait l'opération selon la demande
- CBotVar* left = pStk1->GivVar();
- CBotVar* right = pStk2->GivVar();
-
- switch (GivTokenType())
- {
- case ID_ADD:
- if ( !IsNan(left, right, &err) ) result->Add(left , right); // additionne
- break;
- case ID_SUB:
- if ( !IsNan(left, right, &err) ) result->Sub(left , right); // soustrait
- break;
- case ID_MUL:
- if ( !IsNan(left, right, &err) ) result->Mul(left , right); // multiplie
- break;
- case ID_POWER:
- if ( !IsNan(left, right, &err) ) result->Power(left , right); // puissance
- break;
- case ID_DIV:
- if ( !IsNan(left, right, &err) ) err = result->Div(left , right);// divise
- break;
- case ID_MODULO:
- if ( !IsNan(left, right, &err) ) err = result->Modulo(left , right);// reste de division
- break;
- case ID_LO:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Lo(left , right)); // inférieur
- break;
- case ID_HI:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Hi(left , right)); // supérieur
- break;
- case ID_LS:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Ls(left , right)); // inférieur ou égal
- break;
- case ID_HS:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Hs(left , right)); // supérieur ou égal
- break;
- case ID_EQ:
- if ( IsNan(left, right) )
- result->SetValInt(left->GivInit() == right->GivInit()) ;
- else
- result->SetValInt(temp->Eq(left , right)); // égal
- break;
- case ID_NE:
- if ( IsNan(left, right) )
- result->SetValInt(left ->GivInit() != right->GivInit()) ;
- else
- result->SetValInt(temp->Ne(left , right)); // différent
- break;
- case ID_TXT_AND:
- case ID_LOG_AND:
- case ID_AND:
- if ( !IsNan(left, right, &err) ) result->And(left , right); // ET
- break;
- case ID_TXT_OR:
- case ID_LOG_OR:
- case ID_OR:
- if ( !IsNan(left, right, &err) ) result->Or(left , right); // OU
- break;
- case ID_XOR:
- if ( !IsNan(left, right, &err) ) result->XOr(left , right); // OU exclusif
- break;
- case ID_ASR:
- if ( !IsNan(left, right, &err) ) result->ASR(left , right);
- break;
- case ID_SR:
- if ( !IsNan(left, right, &err) ) result->SR(left , right);
- break;
- case ID_SL:
- if ( !IsNan(left, right, &err) ) result->SL(left , right);
- break;
- default:
- ASM_TRAP();
- }
- delete temp;
-
- pStk2->SetVar(result); // met le résultat sur la pile
- if ( err ) pStk2->SetError(err, &m_token); // et l'erreur éventuelle (division par zéro)
-
-// pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk2); // transmet le résultat
-}
-
-void CBotTwoOpExpr::RestoreState(CBotStack* &pStack, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pStk1 = pStack->RestoreStack(this); // ajoute un élément à la pile
- if ( pStk1 == NULL ) return;
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GivState() == 0 ) // 1er état, évalue l'opérande de gauche
- {
- m_leftop->RestoreState(pStk1, bMain); // interrompu ici !
- return;
- }
-
- CBotStack* pStk2 = pStk1->RestoreStack(); // ajoute un élément à la pile
- if ( pStk2 == NULL ) return;
-
- // 2e état, évalue l'opérande de droite
- if ( pStk2->GivState() == 0 )
- {
- m_rightop->RestoreState(pStk2, bMain); // interrompu ici !
- return;
- }
-}
-
-
-bool CBotLogicExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pStk1 == EOX ) return true;
-
- if ( pStk1->GivState() == 0 )
- {
- if ( !m_condition->Execute(pStk1) ) return false;
- if (!pStk1->SetState(1)) return false;
- }
-
- if ( pStk1->GivVal() == true )
- {
- if ( !m_op1->Execute(pStk1) ) return false;
- }
- else
- {
- if ( !m_op2->Execute(pStk1) ) return false;
- }
-
- return pStack->Return(pStk1); // transmet le résultat
-}
-
-void CBotLogicExpr::RestoreState(CBotStack* &pStack, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pStk1 = pStack->RestoreStack(this); // ajoute un élément à la pile
- if ( pStk1 == NULL ) return;
-
- if ( pStk1->GivState() == 0 )
- {
- m_condition->RestoreState(pStk1, bMain);
- return;
- }
-
- if ( pStk1->GivVal() == true )
- {
- m_op1->RestoreState(pStk1, bMain);
- }
- else
- {
- m_op2->RestoreState(pStk1, bMain);
- }
-}
-
-#if 0
-void t()
-{
- int x,y;
- 1>0 ? x = 0 : y = 0;
-}
-#endif
-
-#if 01
-void t(bool t)
-{
- int x;
- x = 1 + t ? 1 : 3 + 4 * 2 ;
- t ? 0 : "test";
-}
-#endif
+// * 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/.
+
+///////////////////////////////////////////////////
+// expression of type Opérande1 + Opérande2
+// Opérande1 > Opérande2
+
+#include "CBot.h"
+
+// various constructors
+
+CBotTwoOpExpr::CBotTwoOpExpr()
+{
+ m_leftop =
+ m_rightop = NULL; // NULL to be able to delete without other
+ name = "CBotTwoOpExpr"; // debug
+}
+
+CBotTwoOpExpr::~CBotTwoOpExpr()
+{
+ delete m_leftop;
+ delete m_rightop;
+}
+
+CBotLogicExpr::CBotLogicExpr()
+{
+ m_condition =
+ m_op1 =
+ m_op2 = NULL; // NULL to be able to delete without other
+ name = "CBotLogicExpr"; // debug
+}
+
+CBotLogicExpr::~CBotLogicExpr()
+{
+ delete m_condition;
+ delete m_op1;
+ delete m_op2;
+}
+
+
+// type of operands accepted by operations
+#define ENTIER ((1<<CBotTypByte)|(1<<CBotTypShort)|(1<<CBotTypChar)|(1<<CBotTypInt)|(1<<CBotTypLong))
+#define FLOTANT ((1<<CBotTypFloat)|(1<<CBotTypDouble))
+#define BOOLEEN (1<<CBotTypBoolean)
+#define CHAINE (1<<CBotTypString)
+#define POINTER (1<<CBotTypPointer)
+#define INSTANCE (1<<CBotTypClass)
+
+// list of operations (précéance)
+// acceptable type, operand
+// zero ends level \TODO précéance
+
+static int ListOp[] =
+{
+ BOOLEEN, ID_LOGIC, 0,
+ BOOLEEN, ID_TXT_OR,
+ BOOLEEN, ID_LOG_OR, 0,
+ BOOLEEN, ID_TXT_AND,
+ BOOLEEN, ID_LOG_AND, 0,
+ BOOLEEN|ENTIER, ID_OR, 0,
+ BOOLEEN|ENTIER, ID_XOR, 0,
+ BOOLEEN|ENTIER, ID_AND, 0,
+ BOOLEEN|ENTIER|FLOTANT
+ |CHAINE
+ |POINTER
+ |INSTANCE,ID_EQ,
+ BOOLEEN|ENTIER|FLOTANT
+ |CHAINE
+ |POINTER
+ |INSTANCE,ID_NE, 0,
+ ENTIER|FLOTANT|CHAINE, ID_HI,
+ ENTIER|FLOTANT|CHAINE, ID_LO,
+ ENTIER|FLOTANT|CHAINE, ID_HS,
+ ENTIER|FLOTANT|CHAINE, ID_LS, 0,
+ ENTIER, ID_SR,
+ ENTIER, ID_SL,
+ ENTIER, ID_ASR, 0,
+ ENTIER|FLOTANT|CHAINE, ID_ADD,
+ ENTIER|FLOTANT, ID_SUB, 0,
+ ENTIER|FLOTANT, ID_MUL,
+ ENTIER|FLOTANT, ID_DIV,
+ ENTIER|FLOTANT, ID_MODULO, 0,
+ ENTIER|FLOTANT, ID_POWER, 0,
+ 0,
+};
+
+bool IsInList( int val, int* list, int& typemasque )
+{
+ while (true)
+ {
+ if ( *list == 0 ) return false;
+ typemasque = *list++;
+ if ( *list++ == val ) return true;
+ }
+}
+
+bool TypeOk( int type, int test )
+{
+ while (true)
+ {
+ if ( type == 0 ) return (test & 1);
+ type--; test /= 2;
+ }
+}
+
+// compiles a instruction of type A op B
+
+CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations)
+{
+ int typemasque;
+
+ if ( pOperations == NULL ) pOperations = ListOp;
+ int* pOp = pOperations;
+ while ( *pOp++ != 0 ); // follows the table
+
+ CBotCStack* pStk = pStack->TokenStack(); // one end of stack please
+
+ // search the intructions that may be suitable to the left of the operation
+ CBotInstr* left = (*pOp == 0) ?
+ CBotParExpr::Compile( p, pStk ) : // expression (...) left
+ CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B left
+
+ if (left == NULL) return pStack->Return(NULL, pStk); // if error, transmit
+
+ // did we expected the operand?
+ int TypeOp = p->GivType();
+ if ( IsInList( TypeOp, pOperations, typemasque ) )
+ {
+ CBotTypResult type1, type2;
+ type1 = pStk->GivTypResult(); // what kind of the first operand?
+
+ if ( TypeOp == ID_LOGIC ) // special case provided for: ? op1: op2;
+ {
+ if ( !type1.Eq(CBotTypBoolean) )
+ {
+ pStk->SetError( TX_BADTYPE, p);
+ return pStack->Return(NULL, pStk);
+ }
+ CBotLogicExpr* inst = new CBotLogicExpr();
+ inst->m_condition = left;
+
+ p = p->GivNext(); // skip the token of the operation
+ inst->m_op1 = CBotExpression::Compile(p, pStk);
+ CBotToken* pp = p;
+ if ( inst->m_op1 == NULL || !IsOfType( p, ID_DOTS ) )
+ {
+ pStk->SetError( TX_MISDOTS, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ type1 = pStk->GivTypResult();
+
+ inst->m_op2 = CBotExpression::Compile(p, pStk);
+ if ( inst->m_op2 == NULL )
+ {
+ pStk->SetError( TX_ENDOF, p->GivStart() );
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ type2 = pStk->GivTypResult();
+ if (!TypeCompatible(type1, type2))
+ {
+ pStk->SetError( TX_BAD2TYPE, pp );
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ pStk->SetType(type1); // the greatest of 2 types
+
+ return pStack->Return(inst, pStk);
+ }
+
+ CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // element for operation
+ inst->SetToken(p); // stores the operation
+
+
+ p = p->GivNext(); // skip the token of the operation
+
+ // looking statements that may be suitable for right
+
+ if ( NULL != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) )
+ // expression (...) right
+ {
+ // there is an second operand acceptable
+
+ type2 = pStk->GivTypResult(); // what kind of results?
+
+ // what kind of result?
+ int TypeRes = MAX( type1.GivType(3), type2.GivType(3) );
+ if ( TypeOp == ID_ADD && type1.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ type2 = type1; // any type convertible chain
+ }
+ else if ( TypeOp == ID_ADD && type2.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ type1 = type2; // any type convertible chain
+ }
+ else if (!TypeOk( TypeRes, typemasque )) type1.SetType(99);// error of type
+
+ switch ( TypeOp )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_AND:
+ case ID_TXT_OR:
+ case ID_TXT_AND:
+ case ID_EQ:
+ case ID_NE:
+ case ID_HI:
+ case ID_LO:
+ case ID_HS:
+ case ID_LS:
+ TypeRes = CBotTypBoolean;
+ }
+ if ( TypeCompatible (type1, type2, TypeOp ) ) // the results are compatible
+ {
+ // ok so, saves the operand in the object
+ inst->m_leftop = left;
+
+ // special for evaluation of the operations of the same level from left to right
+ while ( IsInList( p->GivType(), pOperations, typemasque ) ) // same operation(s) follows?
+ {
+ TypeOp = p->GivType();
+ CBotTwoOpExpr* i = new CBotTwoOpExpr(); // element for operation
+ i->SetToken(p); // stores the operation
+ i->m_leftop = inst; // left operand
+ type1 = TypeRes;
+
+ p = p->GivNext(); // advance after
+ i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp );
+ type2 = pStk->GivTypResult();
+
+ if ( !TypeCompatible (type1, type2, TypeOp) ) // the results are compatible
+ {
+ pStk->SetError(TX_BAD2TYPE, &i->m_token);
+ delete i;
+ return pStack->Return(NULL, pStk);
+ }
+
+ if ( TypeRes != CBotTypString )
+ TypeRes = MAX(type1.GivType(), type2.GivType());
+ inst = i;
+ }
+
+ CBotTypResult t(type1);
+ t.SetType(TypeRes);
+ // is a variable on the stack for the type of result
+ pStk->SetVar(CBotVar::Create((CBotToken*)NULL, t));
+
+ // and returns the requested object
+ return pStack->Return(inst, pStk);
+ }
+ pStk->SetError(TX_BAD2TYPE, &inst->m_token);
+ }
+
+ // in case of error, releases the elements
+ delete left;
+ delete inst;
+ // and transmits the error to the stack
+ return pStack->Return(NULL, pStk);
+ }
+
+ // if we are not dealing with an operation + or -
+ // goes to that requested, the operand (left) found
+ // instead of the object "addition"
+ return pStack->Return(left, pStk);
+}
+
+
+bool IsNan(CBotVar* left, CBotVar* right, int* err = NULL)
+{
+ if ( left ->GivInit() > IS_DEF || right->GivInit() > IS_DEF )
+ {
+ if ( err != NULL ) *err = TX_OPNAN ;
+ return true;
+ }
+ return false;
+}
+
+
+// performes the operation on two operands
+
+bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack
+ // or return in case of recovery
+// if ( pStk1 == EOX ) return true;
+
+ // according to recovery, it may be in one of two states
+
+ if ( pStk1->GivState() == 0 ) // first state, evaluates the left operand
+ {
+ if (!m_leftop->Execute(pStk1) ) return false; // interrupted here?
+
+ // for OR and AND logic does not evaluate the second expression if not necessary
+ if ( (GivTokenType() == ID_LOG_AND || GivTokenType() == ID_TXT_AND ) && pStk1->GivVal() == false )
+ {
+ CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
+ res->SetValInt(false);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmits the result
+ }
+ if ( (GivTokenType() == ID_LOG_OR||GivTokenType() == ID_TXT_OR) && pStk1->GivVal() == true )
+ {
+ CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
+ res->SetValInt(true);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmits the result
+ }
+
+ // passes to the next step
+ pStk1->SetState(1); // ready for further
+ }
+
+
+ // requires a little more stack to avoid touching the result
+ // of which is left on the stack, precisely
+
+ CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack
+ // or return in case of recovery
+
+ // 2e état, évalue l'opérande de droite
+ if ( pStk2->GivState() == 0 )
+ {
+ if ( !m_rightop->Execute(pStk2) ) return false; // interrupted here?
+ pStk2->IncState();
+ }
+
+ CBotTypResult type1 = pStk1->GivTypResult(); // what kind of results?
+ CBotTypResult type2 = pStk2->GivTypResult();
+
+ CBotStack* pStk3 = pStk2->AddStack(this); // adds an item to the stack
+ if ( pStk3->IfStep() ) return false; // shows the operation if step by step
+
+ // creates a temporary variable to put the result
+ // what kind of result?
+ int TypeRes = MAX(type1.GivType(), type2.GivType());
+
+ if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ }
+
+ switch ( GivTokenType() )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_AND:
+ case ID_TXT_OR:
+ case ID_TXT_AND:
+ case ID_EQ:
+ case ID_NE:
+ case ID_HI:
+ case ID_LO:
+ case ID_HS:
+ case ID_LS:
+ TypeRes = CBotTypBoolean;
+ break;
+ case ID_DIV:
+ TypeRes = MAX(TypeRes, CBotTypFloat);
+ }
+
+ // creates a variable for the result
+ CBotVar* result = CBotVar::Create( (CBotToken*)NULL, TypeRes);
+
+ // creates a variable to perform the calculation in the appropriate type
+ TypeRes = MAX(type1.GivType(), type2.GivType());
+
+ if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ }
+
+ CBotVar* temp;
+
+ if ( TypeRes == CBotTypPointer ) TypeRes = CBotTypNullPointer;
+ if ( TypeRes == CBotTypClass ) temp = CBotVar::Create( (CBotToken*)NULL, CBotTypResult(CBotTypIntrinsic, type1.GivClass() ) );
+ else temp = CBotVar::Create( (CBotToken*)NULL, TypeRes );
+
+ int err = 0;
+ // is a operation according to request
+ CBotVar* left = pStk1->GivVar();
+ CBotVar* right = pStk2->GivVar();
+
+ switch (GivTokenType())
+ {
+ case ID_ADD:
+ if ( !IsNan(left, right, &err) ) result->Add(left , right); // addition
+ break;
+ case ID_SUB:
+ if ( !IsNan(left, right, &err) ) result->Sub(left , right); // substraction
+ break;
+ case ID_MUL:
+ if ( !IsNan(left, right, &err) ) result->Mul(left , right); // multiplies
+ break;
+ case ID_POWER:
+ if ( !IsNan(left, right, &err) ) result->Power(left , right); // power
+ break;
+ case ID_DIV:
+ if ( !IsNan(left, right, &err) ) err = result->Div(left , right);// division
+ break;
+ case ID_MODULO:
+ if ( !IsNan(left, right, &err) ) err = result->Modulo(left , right);// remainder of division
+ break;
+ case ID_LO:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Lo(left , right)); // lower
+ break;
+ case ID_HI:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Hi(left , right)); // top
+ break;
+ case ID_LS:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Ls(left , right)); // less than or equal
+ break;
+ case ID_HS:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Hs(left , right)); // greater than or equal
+ break;
+ case ID_EQ:
+ if ( IsNan(left, right) )
+ result->SetValInt(left->GivInit() == right->GivInit()) ;
+ else
+ result->SetValInt(temp->Eq(left , right)); // equal
+ break;
+ case ID_NE:
+ if ( IsNan(left, right) )
+ result->SetValInt(left ->GivInit() != right->GivInit()) ;
+ else
+ result->SetValInt(temp->Ne(left , right)); // different
+ break;
+ case ID_TXT_AND:
+ case ID_LOG_AND:
+ case ID_AND:
+ if ( !IsNan(left, right, &err) ) result->And(left , right); // AND
+ break;
+ case ID_TXT_OR:
+ case ID_LOG_OR:
+ case ID_OR:
+ if ( !IsNan(left, right, &err) ) result->Or(left , right); // OR
+ break;
+ case ID_XOR:
+ if ( !IsNan(left, right, &err) ) result->XOr(left , right); // exclusive OR
+ break;
+ case ID_ASR:
+ if ( !IsNan(left, right, &err) ) result->ASR(left , right);
+ break;
+ case ID_SR:
+ if ( !IsNan(left, right, &err) ) result->SR(left , right);
+ break;
+ case ID_SL:
+ if ( !IsNan(left, right, &err) ) result->SL(left , right);
+ break;
+ default:
+ ASM_TRAP();
+ }
+ delete temp;
+
+ pStk2->SetVar(result); // puts the result on the stack
+ if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero)
+
+// pStk1->Return(pStk2); // releases the stack
+ return pStack->Return(pStk2); // transmits the result
+}
+
+void CBotTwoOpExpr::RestoreState(CBotStack* &pStack, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pStk1 = pStack->RestoreStack(this); // adds an item to the stack
+ if ( pStk1 == NULL ) return;
+
+ // according to recovery, it may be in one of two states
+
+ if ( pStk1->GivState() == 0 ) // first state, evaluates the left operand
+ {
+ m_leftop->RestoreState(pStk1, bMain); // interrupted here!
+ return;
+ }
+
+ CBotStack* pStk2 = pStk1->RestoreStack(); // adds an item to the stack
+ if ( pStk2 == NULL ) return;
+
+ // second state, evaluates the right operand
+ if ( pStk2->GivState() == 0 )
+ {
+ m_rightop->RestoreState(pStk2, bMain); // interrupted here!
+ return;
+ }
+}
+
+
+bool CBotLogicExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack
+ // or return in case of recovery
+// if ( pStk1 == EOX ) return true;
+
+ if ( pStk1->GivState() == 0 )
+ {
+ if ( !m_condition->Execute(pStk1) ) return false;
+ if (!pStk1->SetState(1)) return false;
+ }
+
+ if ( pStk1->GivVal() == true )
+ {
+ if ( !m_op1->Execute(pStk1) ) return false;
+ }
+ else
+ {
+ if ( !m_op2->Execute(pStk1) ) return false;
+ }
+
+ return pStack->Return(pStk1); // transmits the result
+}
+
+void CBotLogicExpr::RestoreState(CBotStack* &pStack, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pStk1 = pStack->RestoreStack(this); // adds an item to the stack
+ if ( pStk1 == NULL ) return;
+
+ if ( pStk1->GivState() == 0 )
+ {
+ m_condition->RestoreState(pStk1, bMain);
+ return;
+ }
+
+ if ( pStk1->GivVal() == true )
+ {
+ m_op1->RestoreState(pStk1, bMain);
+ }
+ else
+ {
+ m_op2->RestoreState(pStk1, bMain);
+ }
+}
+
+#if 0
+void t()
+{
+ int x,y;
+ 1>0 ? x = 0 : y = 0;
+}
+#endif
+
+#if 01
+void t(bool t)
+{
+ int x;
+ x = 1 + t ? 1 : 3 + 4 * 2 ;
+ t ? 0 : "test";
+}
+#endif
diff --git a/src/CBot/ClassFILE.cpp b/src/CBot/ClassFILE.cpp
index b6c944c..418ddb3 100644
--- a/src/CBot/ClassFILE.cpp
+++ b/src/CBot/ClassFILE.cpp
@@ -65,10 +65,10 @@ bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exceptio
CBotString mode;
// accepts no parameters
- if ( pVar == NULL ) return TRUE;
+ if ( pVar == NULL ) return true;
// must be a string
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
CBotString filename = pVar->GivValString();
PrepareFilename(filename); //DR
@@ -79,10 +79,10 @@ bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exceptio
{
// recovers the mode
mode = pVar->GivValString();
- if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
+ if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
// no third parameter, only two or one possible
- if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return false; }
}
// save the file name
@@ -93,7 +93,7 @@ bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exceptio
{
// open the called file
FILE* pFile = fopen( filename, mode );
- if ( pFile == NULL ) { Exception = CBotErrFileOpen; return FALSE; }
+ if ( pFile == NULL ) { Exception = CBotErrFileOpen; return false; }
m_CompteurFileOpen ++;
@@ -102,7 +102,7 @@ bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exceptio
pVar->SetValInt((long)pFile);
}
- return TRUE;
+ return true;
}
// compilation
@@ -126,7 +126,7 @@ CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
}
- // le résultat est de type void (constructeur)
+ // le r�sultat est de type void (constructeur)
return CBotTypResult( 0 );
}
@@ -140,7 +140,7 @@ bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception
pVar = pThis->GivItem("handle");
// not open? no problem
- if ( pVar->GivInit() != IS_DEF) return TRUE;
+ if ( pVar->GivInit() != IS_DEF) return true;
FILE* pFile= (FILE*)pVar->GivValInt();
fclose(pFile);
@@ -148,7 +148,7 @@ bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception
pVar->SetInit(IS_NAN);
- return TRUE;
+ return true;
}
@@ -159,10 +159,10 @@ bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception
bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// there must be a parameter
- if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
+ if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
// must be a string
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
// there may be a second parameter
if ( pVar->GivNext() != NULL )
@@ -180,16 +180,16 @@ bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
}
CBotString mode = pVar->GivValString();
- if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
+ if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
// No third parameter
- if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return false; }
// retrieves the element "handle"
pVar = pThis->GivItem("handle");
// which must not be initialized
- if ( pVar->GivInit() == IS_DEF) { Exception = CBotErrFileOpen; return FALSE; }
+ if ( pVar->GivInit() == IS_DEF) { Exception = CBotErrFileOpen; return false; }
// contains filename
pVar = pThis->GivItem("filename");
@@ -201,8 +201,8 @@ bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
FILE* pFile = fopen( filename, mode );
if ( pFile == NULL ) //DR
{
- pResult->SetValInt(FALSE); //DR
- return TRUE; //DR
+ pResult->SetValInt(false); //DR
+ return true; //DR
}
m_CompteurFileOpen ++;
@@ -211,8 +211,8 @@ bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
pVar = pThis->GivItem("handle");
pVar->SetValInt((long)pFile);
- pResult->SetValInt(TRUE); //DR
- return TRUE;
+ pResult->SetValInt(true); //DR
+ return true;
}
// compilation
@@ -253,7 +253,7 @@ bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
// retrieves the element "handle"
pVar = pThis->GivItem("handle");
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= (FILE*)pVar->GivValInt();
fclose(pFile);
@@ -261,7 +261,7 @@ bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
pVar->SetInit(IS_NAN);
- return TRUE;
+ return true;
}
// compilation
@@ -280,26 +280,26 @@ CBotTypResult cfclose (CBotVar* pThis, CBotVar* &pVar)
bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// there must be a parameter
- if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
+ if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
// must be a string
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
CBotString param = pVar->GivValString();
//retrieves the element "handle"
pVar = pThis->GivItem("handle");
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= (FILE*)pVar->GivValInt();
int res = fputs(param+CBotString("\n"), pFile);
// on error throws an exception
- if ( res < 0 ) { Exception = CBotErrWrite; return FALSE; }
+ if ( res < 0 ) { Exception = CBotErrWrite; return false; }
- return TRUE;
+ return true;
}
// compilation
@@ -324,12 +324,12 @@ CBotTypResult cfwrite (CBotVar* pThis, CBotVar* &pVar)
bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// there shouldn't be any parameter
- if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
//retrieves the element "handle"
pVar = pThis->GivItem("handle");
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= (FILE*)pVar->GivValInt();
@@ -342,11 +342,11 @@ bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
for ( i = 0 ; i < 2000 ; i++ ) if (chaine[i] == '\n') chaine[i] = 0;
// on error throws an exception
- if ( ferror(pFile) ) { Exception = CBotErrRead; return FALSE; }
+ if ( ferror(pFile) ) { Exception = CBotErrRead; return false; }
pResult->SetValString( chaine );
- return TRUE;
+ return true;
}
// compilation
@@ -365,18 +365,18 @@ CBotTypResult cfread (CBotVar* pThis, CBotVar* &pVar)
bool rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// there shouldn't be any parameter
- if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
// retrieves the element "handle"
pVar = pThis->GivItem("handle");
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= (FILE*)pVar->GivValInt();
pResult->SetValInt( feof( pFile ) );
- return TRUE;
+ return true;
}
// compilation
diff --git a/src/CBot/StringFunctions.cpp b/src/CBot/StringFunctions.cpp
index 27332db..213b956 100644
--- a/src/CBot/StringFunctions.cpp
+++ b/src/CBot/StringFunctions.cpp
@@ -1,434 +1,436 @@
-// * 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/.// définition des fonctions sur les chaînes
-
-
-// donne la longueur d'une chaîne
-// exécution
-
-bool rStrLen( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // pas de second paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // met la longueur sur la pile
- pResult->SetValInt( s.GivLength() );
- return true;
-}
-
-// int xxx ( string )
-// compilation
-
-CBotTypResult cIntStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADPARAM );
-
- // pas de second paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre entier
- return CBotTypResult( CBotTypInt );
-}
-
-
-// donne la partie gauche d'une chaîne
-// exécution
-
-bool rStrLeft( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // prend la partie intéressante
- s = s.Left( n );
-
- // la met sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// string xxx ( string, int )
-// compilation
-
-CBotTypResult cStrStrInt( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-// donne la partie droite d'une chaîne
-// exécution
-
-bool rStrRight( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // prend la partie intéressante
- s = s.Right( n );
-
- // la met sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// donne la partie centrale d'une chaîne
-// exécution
-
-bool rStrMid( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // 3e paramètre optionnel
- if ( pVar->GivNext() != NULL )
- {
- pVar = pVar->GivNext();
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int l = pVar->GivValInt();
-
- // mais pas de 4e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
- // prend la partie intéressante
- s = s.Mid( n, l );
- }
- else
- {
- // prend la partie intéressante
- s = s.Mid( n );
- }
-
- // la met sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// donne la partie centrale d'une chaîne
-// compilation
-
-CBotTypResult cStrStrIntInt( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // 3e paramètre optionnel
- if ( pVar->GivNext() != NULL )
- {
-
- pVar = pVar->GivNext();
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // pas de 4e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
- }
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-
-// donne le nombre contenu dans une chaîne
-// exécution
-
-bool rStrVal( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
- float val = GivNumFloat(s);
-
- // la met la valeur sur la pile
- pResult->SetValFloat( val );
- return true;
-}
-
-// float xxx ( string )
-// compilation
-
-CBotTypResult cFloatStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 2e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre
- return CBotTypResult( CBotTypFloat );
-}
-
-
-// trouve une chaine dans une autre
-// exécution
-
-bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // récupère ce nombre
- CBotString s2 = pVar->GivValString();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // met le résultat sur la pile
- int res = s.Find(s2);
- pResult->SetValInt( res );
- if ( res < 0 ) pResult->SetInit( IS_NAN );
- return true;
-}
-
-// int xxx ( string, string )
-// compilation
-
-CBotTypResult cIntStrStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre
- return CBotTypResult( CBotTypInt );
-}
-
-// donne une chaine en majuscule
-// exécution
-
-bool rStrUpper( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
-
- s.MakeUpper();
-
- // la met la valeur sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// donne une chaine en minuscules
-// exécution
-
-bool rStrLower( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
-
- s.MakeLower();
-
- // la met la valeur sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// string xxx ( string )
-// compilation
-
-CBotTypResult cStrStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 2e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-
-void InitStringFunctions()
-{
- CBotProgram::AddFunction("strlen", rStrLen, cIntStr );
- CBotProgram::AddFunction("strleft", rStrLeft, cStrStrInt );
- CBotProgram::AddFunction("strright", rStrRight, cStrStrInt );
- CBotProgram::AddFunction("strmid", rStrMid, cStrStrIntInt );
-
- CBotProgram::AddFunction("strval", rStrVal, cFloatStr );
- CBotProgram::AddFunction("strfind", rStrFind, cIntStrStr );
-
- CBotProgram::AddFunction("strupper", rStrUpper, cStrStr );
- CBotProgram::AddFunction("strlower", rStrLower, cStrStr );
-}
+// * 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/.
+
+// definition of string functions
+
+
+// gives the length of a chain
+// execution
+
+bool rStrLen( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // puts the length of the stack
+ pResult->SetValInt( s.GivLength() );
+ return true;
+}
+
+// int xxx ( string )
+// compilation
+
+CBotTypResult cIntStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADPARAM );
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is an integer
+ return CBotTypResult( CBotTypInt );
+}
+
+
+// gives the left side of a chain
+// execution
+
+bool rStrLeft( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int n = pVar->GivValInt();
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // takes the interesting part
+ s = s.Left( n );
+
+ // puts on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// string xxx ( string, int )
+// compilation
+
+CBotTypResult cStrStrInt( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble )
+ return CBotTypResult( TX_BADNUM );
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a string
+ return CBotTypResult( CBotTypString );
+}
+
+// gives the right of a string
+// execution
+
+bool rStrRight( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int n = pVar->GivValInt();
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // takes the interesting part
+ s = s.Right( n );
+
+ // puts on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// gives the central part of a chain
+// execution
+
+bool rStrMid( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int n = pVar->GivValInt();
+
+ // third parameter optional
+ if ( pVar->GivNext() != NULL )
+ {
+ pVar = pVar->GivNext();
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int l = pVar->GivValInt();
+
+ // but no fourth parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+ // takes the interesting part
+ s = s.Mid( n, l );
+ }
+ else
+ {
+ // takes the interesting part
+ s = s.Mid( n );
+ }
+
+ // puts on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// gives the central part of a chain
+// compilation
+
+CBotTypResult cStrStrIntInt( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble )
+ return CBotTypResult( TX_BADNUM );
+
+ // third parameter optional
+ if ( pVar->GivNext() != NULL )
+ {
+
+ pVar = pVar->GivNext();
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble )
+ return CBotTypResult( TX_BADNUM );
+
+ // no fourth parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+ }
+
+ // the end result is a string
+ return CBotTypResult( CBotTypString );
+}
+
+
+// gives the number stored in a string
+// execution
+
+bool rStrVal( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // but no second parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+ float val = GivNumFloat(s);
+
+ // puts the value on the stack
+ pResult->SetValFloat( val );
+ return true;
+}
+
+// float xxx ( string )
+// compilation
+
+CBotTypResult cFloatStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a number
+ return CBotTypResult( CBotTypFloat );
+}
+
+
+// find string in other
+// exécution
+
+bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // retrieves this number
+ CBotString s2 = pVar->GivValString();
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // puts the result on the stack
+ int res = s.Find(s2);
+ pResult->SetValInt( res );
+ if ( res < 0 ) pResult->SetInit( IS_NAN );
+ return true;
+}
+
+// int xxx ( string, string )
+// compilation
+
+CBotTypResult cIntStrStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a number
+ return CBotTypResult( CBotTypInt );
+}
+
+// gives a string to uppercase
+// exécution
+
+bool rStrUpper( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // but no second parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+
+ s.MakeUpper();
+
+ // puts the value on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// gives a string to lowercase
+// exécution
+
+bool rStrLower( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // but no second parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+
+ s.MakeLower();
+
+ // puts the value on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// string xxx ( string )
+// compilation
+
+CBotTypResult cStrStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a string
+ return CBotTypResult( CBotTypString );
+}
+
+
+void InitStringFunctions()
+{
+ CBotProgram::AddFunction("strlen", rStrLen, cIntStr );
+ CBotProgram::AddFunction("strleft", rStrLeft, cStrStrInt );
+ CBotProgram::AddFunction("strright", rStrRight, cStrStrInt );
+ CBotProgram::AddFunction("strmid", rStrMid, cStrStrIntInt );
+
+ CBotProgram::AddFunction("strval", rStrVal, cFloatStr );
+ CBotProgram::AddFunction("strfind", rStrFind, cIntStrStr );
+
+ CBotProgram::AddFunction("strupper", rStrUpper, cStrStr );
+ CBotProgram::AddFunction("strlower", rStrLower, cStrStr );
+}