diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CBot/CBotAddExpr.cpp | 286 | ||||
-rw-r--r-- | src/CBot/CBotCompExpr.cpp | 264 | ||||
-rw-r--r-- | src/CBot/CBotDll.h | 2234 | ||||
-rw-r--r-- | src/CBot/CBotFunction.cpp | 3291 | ||||
-rw-r--r-- | src/CBot/CBotStack.cpp | 2942 | ||||
-rw-r--r-- | src/CBot/CBotString.cpp | 3 | ||||
-rw-r--r-- | src/CBot/CBotToken.h | 1 | ||||
-rw-r--r-- | src/CBot/CBotTwoOpExpr.cpp | 1134 | ||||
-rw-r--r-- | src/CBot/ClassFILE.cpp | 64 | ||||
-rw-r--r-- | src/CBot/StringFunctions.cpp | 870 |
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 ); +} |