From 0919796df7ab9025bb53ef2dc56d0888de8c7e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Konopacki?= Date: Wed, 8 Aug 2012 02:01:06 +0200 Subject: [PATCH] Transation of comments complete --- src/CBot/CBotAddExpr.cpp | 286 +-- src/CBot/CBotCompExpr.cpp | 264 +-- src/CBot/CBotDll.h | 2234 +++++++++++------------ src/CBot/CBotFunction.cpp | 3291 +++++++++++++++++----------------- src/CBot/CBotStack.cpp | 2942 +++++++++++++++--------------- src/CBot/CBotString.cpp | 3 +- src/CBot/CBotToken.h | 1 + src/CBot/CBotTwoOpExpr.cpp | 1134 ++++++------ src/CBot/ClassFILE.cpp | 64 +- 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 d94946e9..8e4ed85b 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 0f296d5a..8ae507ff 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 47388a6a..269ef940 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 -#include "resource.h" -#include -#include - - -#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 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 +#include "resource.h" +#include +#include + + +#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 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 363b9399..756c6cb6 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 419798f4..ddb26c68 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 -#include - - -#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 +#include + + +#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 9d5d2578..6acd96e6 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 35a696a5..8e9d1e31 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 e2523b55..49cfcc81 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<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<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 b6c944cb..418ddb36 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 27332db4..213b9565 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 ); +}