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: Transation of comments complete --- src/CBot/CBotFunction.cpp | 3291 +++++++++++++++++++++++---------------------- 1 file changed, 1647 insertions(+), 1644 deletions(-) (limited to 'src/CBot/CBotFunction.cpp') diff --git a/src/CBot/CBotFunction.cpp b/src/CBot/CBotFunction.cpp index 363b939..756c6cb 100644 --- a/src/CBot/CBotFunction.cpp +++ b/src/CBot/CBotFunction.cpp @@ -1,1644 +1,1647 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/./////////////////////////////////////////////////////////////////////// -// compilation des diverses fonctions déclarées par l'utilisateur -// - -#include "CBot.h" - -// les divers constructeurs / destructeurs -// pour libérer tout selon l'arbre établi -CBotFunction::CBotFunction() -{ - m_Param = NULL; // liste des paramètres vide - m_Block = NULL; // le bloc d'instructions - m_next = NULL; // les fonctions peuvent être chaînées - m_bPublic = false; // fonction non publique - m_bExtern = false; // fonction non externe - m_nextpublic = NULL; - m_prevpublic = NULL; - m_pProg = NULL; -// m_nThisIdent = 0; - m_nFuncIdent = 0; - m_bSynchro = false; -} - -CBotFunction* CBotFunction::m_listPublic = NULL; - -CBotFunction::~CBotFunction() -{ - delete m_Param; // liste des paramètres vide - delete m_Block; // le bloc d'instructions - delete m_next; - - // enlève de la liste publique s'il y a lieu - if ( m_bPublic ) - { - if ( m_nextpublic != NULL ) - { - m_nextpublic->m_prevpublic = m_prevpublic; - } - if ( m_prevpublic != NULL) - { - m_prevpublic->m_nextpublic = m_nextpublic; - } - else - { - // si prev = next = null peut ne pas être dans la liste ! - if ( m_listPublic == this ) m_listPublic = m_nextpublic; - } - } -} - -bool CBotFunction::IsPublic() -{ - return m_bPublic; -} - -bool CBotFunction::IsExtern() -{ - return m_bExtern; -} - -bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop) -{ - start = m_extern.GivStart(); - stop = m_closeblk.GivEnd(); - - if (modestart == GetPosExtern) - { - start = m_extern.GivStart(); - } - if (modestop == GetPosExtern) - { - stop = m_extern.GivEnd(); - } - if (modestart == GetPosNom) - { - start = m_token.GivStart(); - } - if (modestop == GetPosNom) - { - stop = m_token.GivEnd(); - } - if (modestart == GetPosParam) - { - start = m_openpar.GivStart(); - } - if (modestop == GetPosParam) - { - stop = m_closepar.GivEnd(); - } - if (modestart == GetPosBloc) - { - start = m_openblk.GivStart(); - } - if (modestop == GetPosBloc) - { - stop = m_closeblk.GivEnd(); - } - - return true; -} - - -CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type) -{ - while ( IsOfType( p, ID_OPBRK ) ) - { - if ( !IsOfType( p, ID_CLBRK ) ) - { - pile->SetError(TX_CLBRK, p->GivStart()); - return CBotTypResult( -1 ); - } - type = CBotTypResult( CBotTypArrayPointer, type ); - } - return type; -} - -CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile) -{ - CBotClass* pClass = NULL; - - switch (p->GivType()) - { - case ID_INT: - p = p->GivNext(); - return ArrayType(p, pile, CBotTypResult( CBotTypInt )); - case ID_FLOAT: - p = p->GivNext(); - return ArrayType(p, pile, CBotTypResult( CBotTypFloat )); - case ID_BOOLEAN: - case ID_BOOL: - p = p->GivNext(); - return ArrayType(p, pile, CBotTypResult( CBotTypBoolean )); - case ID_STRING: - p = p->GivNext(); - return ArrayType(p, pile, CBotTypResult( CBotTypString )); - case ID_VOID: - p = p->GivNext(); - return CBotTypResult( 0 ); - - case TokenTypVar: - pClass = CBotClass::Find(p); - if ( pClass != NULL) - { - p = p->GivNext(); - return ArrayType(p, pile, - pClass->IsIntrinsic() ? - CBotTypResult( CBotTypIntrinsic, pClass ) : - CBotTypResult( CBotTypPointer, pClass ) ); - } - } - return CBotTypResult( -1 ); -} - -// compile une nouvelle fonction -// bLocal permet de mettre la déclaration des paramètres au même niveau -// que le éléments appartenant à la classe pour les méthodes -CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal) -{ - CBotToken* pp; - CBotFunction* func = finput; - if ( func == NULL ) func = new CBotFunction(); - - CBotCStack* pStk = pStack->TokenStack(p, bLocal); - -// func->m_nFuncIdent = CBotVar::NextUniqNum(); - - while (true) - { - if ( IsOfType(p, ID_PUBLIC) ) - { - func->m_bPublic = true; - continue; - } - pp = p; - if ( IsOfType(p, ID_EXTERN) ) - { - func->m_extern = pp; // pour la position du mot "extern" - func->m_bExtern = true; -// func->m_bPublic = true; // donc aussi publique! - continue; - } - break; - } - - func->m_retToken = *p; -// CBotClass* pClass; - func->m_retTyp = TypeParam(p, pStk); // type du résultat - - if (func->m_retTyp.GivType() >= 0) - { - CBotToken* pp = p; - func->m_token = *p; - - if ( IsOfType(p, ID_NOT) ) - { - CBotToken d("~" + p->GivString()); - func->m_token = d; - } - - // un nom de fonction est-il là ? - if (IsOfType(p, TokenTypVar)) - { - if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe - { - func->m_MasterClass = pp->GivString(); - CBotClass* pClass = CBotClass::Find(pp); - if ( pClass == NULL ) goto bad; - -// pp = p; - func->m_token = *p; - if (!IsOfType(p, TokenTypVar)) goto bad; - - } - func->m_openpar = p; - func->m_Param = CBotDefParam::Compile( p, pStk ); - func->m_closepar = p->GivPrev(); - if (pStk->IsOk()) - { - pStk->SetRetType(func->m_retTyp); // pour savoir de quel type les return - - if (!func->m_MasterClass.IsEmpty()) - { - // rend "this" connu - CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass )); - pThis->SetInit(2); -// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() va pas - pThis->SetUniqNum(-2); - pStk->AddVar(pThis); - - // initialise les variables selon This - // n'enregistre que le pointeur à la première, - // le reste est chainé - CBotVar* pv = pThis->GivItemList(); -// int num = 1; - while (pv != NULL) - { - CBotVar* pcopy = CBotVar::Create(pv); -// pcopy->SetInit(2); - pcopy->Copy(pv); - pcopy->SetPrivate(pv->GivPrivate()); -// pcopy->SetUniqNum(pv->GivUniqNum()); //num++); - pStk->AddVar(pcopy); - pv = pv->GivNext(); - } - } - - // et compile le bloc d'instruction qui suit - func->m_openblk = p; - func->m_Block = CBotBlock::Compile(p, pStk, false); - func->m_closeblk = p->GivPrev(); - if ( pStk->IsOk() ) - { - if ( func->m_bPublic ) // fonction publique, la rend connue pour tous - { - CBotFunction::AddPublic(func); - } - return pStack->ReturnFunc(func, pStk); - } - } - } -bad: - pStk->SetError(TX_NOFONC, p); - } - pStk->SetError(TX_NOTYP, p); - if ( finput == NULL ) delete func; - return pStack->ReturnFunc(NULL, pStk); -} - -// pré-compile une nouvelle fonction -CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) -{ - CBotFunction* func = new CBotFunction(); - func->m_nFuncIdent = CBotVar::NextUniqNum(); - - CBotCStack* pStk = pStack->TokenStack(p, true); - - while (true) - { - if ( IsOfType(p, ID_PUBLIC) ) - { - // func->m_bPublic = true; // sera fait en passe 2 - continue; - } - if ( IsOfType(p, ID_EXTERN) ) - { - func->m_bExtern = true; - continue; - } - break; - } - - func->m_retToken = *p; - func->m_retTyp = TypeParam(p, pStack); // type du résultat - - if (func->m_retTyp.GivType() >= 0) - { - CBotToken* pp = p; - func->m_token = *p; - // un nom de fonction est-il là ? - if (IsOfType(p, TokenTypVar)) - { - if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe - { - func->m_MasterClass = pp->GivString(); - CBotClass* pClass = CBotClass::Find(pp); - if ( pClass == NULL ) - { - pStk->SetError(TX_NOCLASS, pp); - goto bad; - } - - pp = p; - func->m_token = *p; - if (!IsOfType(p, TokenTypVar)) goto bad; - - } - func->m_Param = CBotDefParam::Compile( p, pStk ); - if (pStk->IsOk()) - { - // regarde si la fonction existe ailleurs - if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) && - ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) ) - { - if (IsOfType(p, ID_OPBLK)) - { - int level = 1; - // et saute le bloc d'instructions qui suit - do - { - int type = p->GivType(); - p = p->GivNext(); - if (type == ID_OPBLK) level++; - if (type == ID_CLBLK) level--; - } - while (level > 0 && p != NULL); - - return pStack->ReturnFunc(func, pStk); - } - pStk->SetError(TX_OPENBLK, p); - } - } - pStk->SetError(TX_REDEF, pp); - } -bad: - pStk->SetError(TX_NOFONC, p); - } - pStk->SetError(TX_NOTYP, p); - delete func; - return pStack->ReturnFunc(NULL, pStk); -} - -#ifdef _DEBUG -static int xx = 0; -#endif - -bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) -{ - CBotStack* pile = pj->AddStack(this, 2); // un bout de pile local à cette fonction -// if ( pile == EOX ) return true; - - pile->SetBotCall(m_pProg); // bases pour les routines - - if ( pile->GivState() == 0 ) - { - if ( !m_Param->Execute(ppVars, pile) ) return false; // défini les paramètres - pile->IncState(); - } - - if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() ) - { - // rend "this" connu - CBotVar* pThis ; - if ( pInstance == NULL ) - { - pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass )); - pThis->SetInit(2); - } - else - { - pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass )); - pThis->SetPointer(pInstance); - pThis->SetInit(2); - } - -// pThis->SetUniqNum(m_nThisIdent); - pThis->SetUniqNum(-2); - pile->AddVar(pThis); - - pile->IncState(); - } - - if ( pile->IfStep() ) return false; - - if ( !m_Block->Execute(pile) ) - { - if ( pile->GivError() < 0 ) - pile->SetError( 0 ); - else - return false; - } - - return pj->Return(pile); -} - - -void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) -{ - CBotStack* pile = pj->RestoreStack(this); // un bout de pile local à cette fonction - if ( pile == NULL ) return; - CBotStack* pile2 = pile; - - pile->SetBotCall(m_pProg); // bases pour les routines - - if ( pile->GivBlock() < 2 ) - { - CBotStack* pile2 = pile->RestoreStack(NULL); // un bout de pile local à cette fonction - if ( pile2 == NULL ) return; - pile->SetState(pile->GivState() + pile2->GivState()); - pile2->Delete(); - } - - m_Param->RestoreState(pile2, true); // les paramètres - - if ( !m_MasterClass.IsEmpty() ) - { - CBotVar* pThis = pile->FindVar("this"); - pThis->SetInit(2); - pThis->SetUniqNum(-2); - } - - m_Block->RestoreState(pile2, true); -} - -void CBotFunction::AddNext(CBotFunction* p) -{ - CBotFunction* pp = this; - while (pp->m_next != NULL) pp = pp->m_next; - - pp->m_next = p; -} - - -CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent) -{ - nIdent = 0; - CBotTypResult type; - - CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); - return type; -} - - -// trouve une fonction selon son identificateur unique -// si l'identificateur n'est pas trouvé, cherche selon le nom et les paramètres - -CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic) -{ - TypeOrError.SetType(TX_UNDEFCALL); // pas de routine de ce nom - CBotFunction* pt; - - if ( nIdent ) - { - if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next ) - { - if ( pt->m_nFuncIdent == nIdent ) - { - TypeOrError = pt->m_retTyp; - return pt; - } - } - - // recherche dans la liste des fonctions publiques - - for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) - { - if ( pt->m_nFuncIdent == nIdent ) - { - TypeOrError = pt->m_retTyp; - return pt; - } - } - } - - if ( name == NULL ) return NULL; - - int delta = 99999; // cherche la signature la plus faible - CBotFunction* pFunc = NULL; // la meilleure fonction trouvée - - if ( this != NULL ) - { - for ( pt = this ; pt != NULL ; pt = pt->m_next ) - { - if ( pt->m_token.GivString() == name ) - { - int i = 0; - int alpha = 0; // signature des paramètres - // les paramètres sont-ils compatibles ? - CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus - CBotVar* pw = ppVars[i++]; // liste des paramètres fournis - while ( pv != NULL && pw != NULL) - { - if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult())) - { - if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; - break; - } - int d = pv->GivType() - pw->GivType(2); - alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !! - - pv = pv->GivNext(); - pw = ppVars[i++]; - } - if ( pw != NULL ) - { - if ( pFunc != NULL ) continue; - if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); - if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); - continue; // trop de paramètres - } - if ( pv != NULL ) - { - if ( pFunc != NULL ) continue; - if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); - if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); - continue; // pas assez de paramètres - } - - if (alpha == 0) // signature parfaite - { - nIdent = pt->m_nFuncIdent; - TypeOrError = pt->m_retTyp; - return pt; - } - - if ( alpha < delta ) // une meilleur signature ? - { - pFunc = pt; - delta = alpha; - } - } - } - } - - if ( bPublic ) - { - for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) - { - if ( pt->m_token.GivString() == name ) - { - int i = 0; - int alpha = 0; // signature des paramètres - // les paramètres sont-ils compatibles ? - CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus - CBotVar* pw = ppVars[i++]; // liste des paramètres fournis - while ( pv != NULL && pw != NULL) - { - if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult())) - { - if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; - break; - } - int d = pv->GivType() - pw->GivType(2); - alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !! - - pv = pv->GivNext(); - pw = ppVars[i++]; - } - if ( pw != NULL ) - { - if ( pFunc != NULL ) continue; - if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); - if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); - continue; // trop de paramètres - } - if ( pv != NULL ) - { - if ( pFunc != NULL ) continue; - if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); - if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); - continue; // pas assez de paramètres - } - - if (alpha == 0) // signature parfaite - { - nIdent = pt->m_nFuncIdent; - TypeOrError = pt->m_retTyp; - return pt; - } - - if ( alpha < delta ) // une meilleur signature ? - { - pFunc = pt; - delta = alpha; - } - } - } - } - - if ( pFunc != NULL ) - { - nIdent = pFunc->m_nFuncIdent; - TypeOrError = pFunc->m_retTyp; - return pFunc; - } - return NULL; -} - - -// fait un appel à une fonction - -int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) -{ - CBotTypResult type; - CBotFunction* pt = NULL; - - pt = FindLocalOrPublic(nIdent, name, ppVars, type); - - if ( pt != NULL ) - { - CBotStack* pStk1 = pStack->AddStack(pt, 2); // pour mettre "this" -// if ( pStk1 == EOX ) return true; - - pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module - - if ( pStk1->IfStep() ) return false; - - CBotStack* pStk3 = pStk1->AddStack(NULL, true); // paramètres - - // prépare les paramètres sur la pile - - if ( pStk1->GivState() == 0 ) - { - if ( !pt->m_MasterClass.IsEmpty() ) - { - CBotVar* pInstance = m_pProg->m_pInstance; - // rend "this" connu - CBotVar* pThis ; - if ( pInstance == NULL ) - { - pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass )); - pThis->SetInit(2); - } - else - { - pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass )); - pThis->SetPointer(pInstance); - pThis->SetInit(2); - } - - pThis->SetUniqNum(-2); - pStk1->AddVar(pThis); - - } - - // initialise les variables selon paramètres - pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu - - pStk1->IncState(); - } - - // finalement exécute la fonction trouvée - - if ( !pStk3->GivRetVar( // remet le résultat sur la pile - pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu - { - if ( !pStk3->IsOk() && pt->m_pProg != m_pProg ) - { -#ifdef _DEBUG - if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return false; -#endif - pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure - } - return false; // interrompu ! - } - - return pStack->Return( pStk3 ); - } - return -1; -} - -void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack) -{ - CBotTypResult type; - CBotFunction* pt = NULL; - CBotStack* pStk1; - CBotStack* pStk3; - - // recherche la fonction pour remettre l'identificateur ok - - pt = FindLocalOrPublic(nIdent, name, ppVars, type); - - if ( pt != NULL ) - { - pStk1 = pStack->RestoreStack(pt); - if ( pStk1 == NULL ) return; - - pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module - - if ( pStk1->GivBlock() < 2 ) - { - CBotStack* pStk2 = pStk1->RestoreStack(NULL); // plus utilisé - if ( pStk2 == NULL ) return; - pStk3 = pStk2->RestoreStack(NULL); - if ( pStk3 == NULL ) return; - } - else - { - pStk3 = pStk1->RestoreStack(NULL); - if ( pStk3 == NULL ) return; - } - - // prépare les paramètres sur la pile - - { - if ( !pt->m_MasterClass.IsEmpty() ) - { - CBotVar* pInstance = m_pProg->m_pInstance; - // rend "this" connu - CBotVar* pThis = pStk1->FindVar("this"); - pThis->SetInit(2); - pThis->SetUniqNum(-2); - } - } - - if ( pStk1->GivState() == 0 ) - { - pt->m_Param->RestoreState(pStk3, true); - return; - } - - // initialise les variables selon paramètres - pt->m_Param->RestoreState(pStk3, false); - pt->m_Block->RestoreState(pStk3, true); - } -} - - - -// fait un appel d'une méthode -// note : this est déjà sur la pile, le pointeur pThis est juste là pour simplifier - -int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass) -{ - CBotTypResult type; - CBotProgram* pProgCurrent = pStack->GivBotCall(); - - CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false); - - if ( pt != NULL ) - { -// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack); - - CBotStack* pStk = pStack->AddStack(pt, 2); -// if ( pStk == EOX ) return true; - - pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module - CBotStack* pStk3 = pStk->AddStack(NULL, true); // pour mettre les paramètres passés - - // prépare les paramètres sur la pile - - if ( pStk->GivState() == 0 ) - { - // met la variable "this" sur la pile - CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); - pthis->Copy(pThis, false); - pthis->SetUniqNum(-2); // valeur spéciale - pStk->AddVar(pthis); - - CBotClass* pClass = pThis->GivClass()->GivParent(); - if ( pClass ) - { - // met la variable "super" sur la pile - CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); - psuper->Copy(pThis, false); // en fait identique à "this" - psuper->SetUniqNum(-3); // valeur spéciale - pStk->AddVar(psuper); - } - // initialise les variables selon paramètres - pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu - pStk->IncState(); - } - - if ( pStk->GivState() == 1 ) - { - if ( pt->m_bSynchro ) - { - CBotProgram* pProgBase = pStk->GivBotCall(true); - if ( !pClass->Lock(pProgBase) ) return false; // attend de pouvoir - } - pStk->IncState(); - } - // finalement appelle la fonction trouvée - - if ( !pStk3->GivRetVar( // remet le résultat sur la pile - pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu - { - if ( !pStk3->IsOk() ) - { - if ( pt->m_bSynchro ) - { - pClass->Unlock(); // libère la fonction - } - - if ( pt->m_pProg != pProgCurrent ) - { - pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure - } - } - return false; // interrompu ! - } - - if ( pt->m_bSynchro ) - { - pClass->Unlock(); // libère la fonction - } - - return pStack->Return( pStk3 ); - } - return -1; -} - -void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass) -{ - CBotTypResult type; - CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); - - if ( pt != NULL ) - { - CBotStack* pStk = pStack->RestoreStack(pt); - if ( pStk == NULL ) return; - pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module - - CBotVar* pthis = pStk->FindVar("this"); - pthis->SetUniqNum(-2); - - CBotStack* pStk3 = pStk->RestoreStack(NULL); // pour mettre les paramètres passés - if ( pStk3 == NULL ) return; - - pt->m_Param->RestoreState(pStk3, true); // les paramètres - - if ( pStk->GivState() > 1 && // vérouillage est effectif ? - pt->m_bSynchro ) - { - CBotProgram* pProgBase = pStk->GivBotCall(true); - pClass->Lock(pProgBase); // vérouille la classe - } - - // finalement appelle la fonction trouvée - - pt->m_Block->RestoreState(pStk3, true); // interrompu ! - } -} - -// regarde si la "signature" des paramètres est identique -bool CBotFunction::CheckParam(CBotDefParam* pParam) -{ - CBotDefParam* pp = m_Param; - while ( pp != NULL && pParam != NULL ) - { - CBotTypResult type1 = pp->GivType(); - CBotTypResult type2 = pParam->GivType(); - if ( !type1.Compare(type2) ) return false; - pp = pp->GivNext(); - pParam = pParam->GivNext(); - } - return ( pp == NULL && pParam == NULL ); -} - -CBotString CBotFunction::GivName() -{ - return m_token.GivString(); -} - -CBotString CBotFunction::GivParams() -{ - if ( m_Param == NULL ) return CBotString("()"); - - CBotString params = "( "; - CBotDefParam* p = m_Param; // liste des paramètres - - while (p != NULL) - { - params += p->GivParamString(); - p = p->GivNext(); - if ( p != NULL ) params += ", "; - } - - params += " )"; - return params; -} - -CBotFunction* CBotFunction::Next() -{ - return m_next; -} - -void CBotFunction::AddPublic(CBotFunction* func) -{ - if ( m_listPublic != NULL ) - { - func->m_nextpublic = m_listPublic; - m_listPublic->m_prevpublic = func; - } - m_listPublic = func; -} - - - -///////////////////////////////////////////////////////////////////////// -// gestion des paramètres - - -CBotDefParam::CBotDefParam() -{ - m_next = NULL; - m_nIdent = 0; -} - -CBotDefParam::~CBotDefParam() -{ - delete m_next; -} - - -// compile une liste de paramètres -CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) -{ - // surtout pas de pStack->TokenStack ici - // les variables déclarées doivent rester visibles par la suite - - pStack->SetStartError(p->GivStart()); - - if (IsOfType(p, ID_OPENPAR)) - { - CBotDefParam* list = NULL; - - while (!IsOfType(p, ID_CLOSEPAR)) - { - CBotDefParam* param = new CBotDefParam(); - if (list == NULL) list = param; - else list->AddNext(param); // ajoute à la liste - - CBotClass* pClass = NULL;//= CBotClass::Find(p); - param->m_typename = p->GivString(); - CBotTypResult type = param->m_type = TypeParam(p, pStack); -// if ( type == CBotTypPointer ) type = CBotTypClass; // il faut créer un nouvel objet - - if (param->m_type.GivType() > 0) - { - CBotToken* pp = p; - param->m_token = *p; - if (pStack->IsOk() && IsOfType(p, TokenTypVar) ) - { - - // variable déjà déclarée ? - if (pStack->CheckVarLocal(pp)) - { - pStack->SetError(TX_REDEFVAR, pp); - break; - } - - if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); - CBotVar* var = CBotVar::Create(pp->GivString(), type); // crée la variable -// if ( pClass ) var->SetClass(pClass); - var->SetInit(2); // la marque initialisée - param->m_nIdent = CBotVar::NextUniqNum(); - var->SetUniqNum(param->m_nIdent); - pStack->AddVar(var); // la place sur la pile - - if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR) - continue; - } - pStack->SetError(TX_CLOSEPAR, p->GivStart()); - } - pStack->SetError(TX_NOTYP, p); - delete list; - return NULL; - } - return list; - } - pStack->SetError(TX_OPENPAR, p->GivStart()); - return NULL; -} - -void CBotDefParam::AddNext(CBotDefParam* p) -{ - CBotDefParam* pp = this; - while (pp->m_next != NULL) pp = pp->m_next; - - pp->m_next = p; -} - - -bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) -{ - int i = 0; - CBotDefParam* p = this; - - while ( p != NULL ) - { - // crée une variable locale sur la pile - CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type); - - // procède ainsi pour faire la transformation des types : - if ( ppVars != NULL && ppVars[i] != NULL ) - { - switch (p->m_type.GivType()) - { - case CBotTypInt: - newvar->SetValInt(ppVars[i]->GivValInt()); - break; - case CBotTypFloat: - newvar->SetValFloat(ppVars[i]->GivValFloat()); - break; - case CBotTypString: - newvar->SetValString(ppVars[i]->GivValString()); - break; - case CBotTypBoolean: - newvar->SetValInt(ppVars[i]->GivValInt()); - break; - case CBotTypIntrinsic: - ((CBotVarClass*)newvar)->Copy(ppVars[i], false); - break; - case CBotTypPointer: - case CBotTypArrayPointer: - { - newvar->SetPointer(ppVars[i]->GivPointer()); - } - break; - default: - ASM_TRAP(); - } - } - newvar->SetUniqNum(p->m_nIdent); - pj->AddVar(newvar); // place la variable - p = p->m_next; - i++; - } - - return true; -} - -void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) -{ - int i = 0; - CBotDefParam* p = this; - - while ( p != NULL ) - { - // crée une variable locale sur la pile - CBotVar* var = pj->FindVar(p->m_token.GivString()); - var->SetUniqNum(p->m_nIdent); - p = p->m_next; - } -} - -int CBotDefParam::GivType() -{ - return m_type.GivType(); -} - -CBotTypResult CBotDefParam::GivTypResult() -{ - return m_type; -} - -CBotDefParam* CBotDefParam::GivNext() -{ - return m_next; -} - -CBotString CBotDefParam::GivParamString() -{ - CBotString param; - - param = m_typename; - param += ' '; - - param += m_token.GivString(); - return param; -} - - - -////////////////////////////////////////////////////////////////////////// -// retour des paramètres - -CBotReturn::CBotReturn() -{ - m_Instr = NULL; - name = "CBotReturn"; // debug -} - -CBotReturn::~CBotReturn() -{ - delete m_Instr; -} - -CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotToken* pp = p; - - if (!IsOfType(p, ID_RETURN)) return NULL; // ne devrait jamais arriver - - CBotReturn* inst = new CBotReturn(); // crée l'objet - inst->SetToken( pp ); - - CBotTypResult type = pStack->GivRetType(); - - if ( type.GivType() == 0 ) // retourne void ? - { - if ( IsOfType( p, ID_SEP ) ) return inst; - pStack->SetError( TX_BADTYPE, pp ); - return NULL; - } - - inst->m_Instr = CBotExpression::Compile(p, pStack); - if ( pStack->IsOk() ) - { - CBotTypResult retType = pStack->GivTypResult(2); - if (TypeCompatible(retType, type, ID_ASS)) - { - if ( IsOfType( p, ID_SEP ) ) - return inst; - - pStack->SetError(TX_ENDOF, p->GivStart()); - } - pStack->SetError(TX_BADTYPE, p->GivStart()); - } - - delete inst; - return NULL; // pas d'objet, l'erreur est sur la pile -} - -bool CBotReturn::Execute(CBotStack* &pj) -{ - CBotStack* pile = pj->AddStack(this); -// if ( pile == EOX ) return true; - - if ( pile->GivState() == 0 ) - { - if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // évalue le résultat - // le résultat est sur la pile - pile->IncState(); - } - - if ( pile->IfStep() ) return false; - - pile->SetBreak(3, CBotString()); - return pj->Return(pile); -} - -void CBotReturn::RestoreState(CBotStack* &pj, bool bMain) -{ - if ( !bMain ) return; - CBotStack* pile = pj->RestoreStack(this); - if ( pile == NULL ) return; - - if ( pile->GivState() == 0 ) - { - if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // évalue le résultat - return; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Les appels à ces fonctions - -CBotInstrCall::CBotInstrCall() -{ - m_Parameters = NULL; - m_nFuncIdent = 0; - name = "CBotInstrCall"; -} - -CBotInstrCall::~CBotInstrCall() -{ - delete m_Parameters; -} - -CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) -{ - CBotVar* ppVars[1000]; - - int i = 0; - - CBotToken* pp = p; - p = p->GivNext(); - - pStack->SetStartError(p->GivStart()); - CBotCStack* pile = pStack; - - if ( IsOfType(p, ID_OPENPAR) ) - { - int start, end; - CBotInstrCall* inst = new CBotInstrCall(); - inst->SetToken(pp); - - // compile la liste des paramètres - if (!IsOfType(p, ID_CLOSEPAR)) while (true) - { - start = p->GivStart(); - pile = pile->TokenStack(); // garde les résultats sur la pile - - CBotInstr* param = CBotExpression::Compile(p, pile); - end = p->GivStart(); - if ( inst->m_Parameters == NULL ) inst->m_Parameters = param; - else inst->m_Parameters->AddNext(param); // construit la liste - - if ( !pile->IsOk() ) - { - delete inst; - return pStack->Return(NULL, pile); - } - - if ( param != NULL ) - { - if ( pile->GivTypResult().Eq(99) ) - { - delete pStack->TokenStack(); - pStack->SetError(TX_VOID, p->GivStart()); - delete inst; - return NULL; - } - ppVars[i] = pile->GivVar(); - ppVars[i]->GivToken()->SetPos(start, end); - i++; - - if (IsOfType(p, ID_COMMA)) continue; // saute la virgule - if (IsOfType(p, ID_CLOSEPAR)) break; - } - - pStack->SetError(TX_CLOSEPAR, p->GivStart()); - delete pStack->TokenStack(); - delete inst; - return NULL; - } - ppVars[i] = NULL; - - // la routine est-elle connue ? -// CBotClass* pClass = NULL; - inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent); - if ( inst->m_typRes.GivType() >= 20 ) - { -// if (pVar2!=NULL) pp = pVar2->RetToken(); - pStack->SetError( inst->m_typRes.GivType(), pp ); - delete pStack->TokenStack(); - delete inst; - return NULL; - } - - delete pStack->TokenStack(); - if ( inst->m_typRes.GivType() > 0 ) - { - CBotVar* pRes = CBotVar::Create("", inst->m_typRes); - pStack->SetVar(pRes); // pour connaître le type du résultat - } - else pStack->SetVar(NULL); // routine retourne void - - return inst; - } - p = pp; - delete pStack->TokenStack(); - return NULL; -} - -bool CBotInstrCall::Execute(CBotStack* &pj) -{ - CBotVar* ppVars[1000]; - CBotStack* pile = pj->AddStack(this); - if ( pile->StackOver() ) return pj->Return( pile ); - - CBotStack* pile1 = pile; - - int i = 0; - - CBotInstr* p = m_Parameters; - // évalue les paramètres - // et place les valeurs sur la pile - // pour pouvoir être interrompu n'importe quand - if ( p != NULL) while ( true ) - { - pile = pile->AddStack(); // de la place sur la pile pour les résultats - if ( pile->GivState() == 0 ) - { - if (!p->Execute(pile)) return false; // interrompu ici ? - pile->SetState(1); // marque spéciale pour reconnaîre les paramètres - } - ppVars[i++] = pile->GivVar(); - p = p->GivNext(); - if ( p == NULL) break; - } - ppVars[i] = NULL; - - CBotStack* pile2 = pile->AddStack(); - if ( pile2->IfStep() ) return false; - - if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return false; // interrompu - - return pj->Return(pile2); // libère toute la pile -} - -void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain) -{ - if ( !bMain ) return; - - CBotStack* pile = pj->RestoreStack(this); - if ( pile == NULL ) return; - - CBotStack* pile1 = pile; - - int i = 0; - CBotVar* ppVars[1000]; - CBotInstr* p = m_Parameters; - // évalue les paramètres - // et place les valeurs sur la pile - // pour pouvoir être interrompu n'importe quand - if ( p != NULL) while ( true ) - { - pile = pile->RestoreStack(); // de la place sur la pile pour les résultats - if ( pile == NULL ) return; - if ( pile->GivState() == 0 ) - { - p->RestoreState(pile, bMain); // interrompu ici ! - return; - } - ppVars[i++] = pile->GivVar(); // construit la liste des paramètres - p = p->GivNext(); - if ( p == NULL) break; - } - ppVars[i] = NULL; - - CBotStack* pile2 = pile->RestoreStack(); - if ( pile2 == NULL ) return; - - pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars); -} - -////////////////////////////////////////////////////////////////////////////// -// déclaration des classes par l'utilisateur - -// pré-compile une nouvelle class -// l'analyse est complète à l'execption du corps des routines - -CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) -{ - if ( !IsOfType(p, ID_PUBLIC) ) - { - pStack->SetError(TX_NOPUBLIC, p); - return NULL; - } - - if ( !IsOfType(p, ID_CLASS) ) return NULL; - - CBotString name = p->GivString(); - - CBotClass* pOld = CBotClass::Find(name); - if ( pOld != NULL && pOld->m_IsDef ) - { - pStack->SetError( TX_REDEFCLASS, p ); - return NULL; - } - - // un nom pour la classe est-il là ? - if (IsOfType(p, TokenTypVar)) - { - CBotClass* pPapa = NULL; - if ( IsOfType( p, ID_EXTENDS ) ) - { - CBotString name = p->GivString(); - pPapa = CBotClass::Find(name); - - if (!IsOfType(p, TokenTypVar) || pPapa == NULL ) - { - pStack->SetError( TX_NOCLASS, p ); - return NULL; - } - } - CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld; - classe->Purge(); // vide les anciennes définitions - classe->m_IsDef = false; // définition en cours - - if ( !IsOfType( p, ID_OPBLK) ) - { - pStack->SetError(TX_OPENBLK, p); - return NULL; - } - - while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) ) - { - classe->CompileDefItem(p, pStack, false); - } - - if (pStack->IsOk()) return classe; - } - pStack->SetError(TX_ENDOF, p); - return NULL; -} - -bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) -{ - bool bStatic = false; - int mProtect = PR_PUBLIC; - bool bSynchro = false; - - while (IsOfType(p, ID_SEP)) ; - - CBotTypResult type( -1 ); - - if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true; - CBotToken* pBase = p; - - if ( IsOfType(p, ID_STATIC) ) bStatic = true; - if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC; - if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE; - if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT; - if ( IsOfType(p, ID_STATIC) ) bStatic = true; - -// CBotClass* pClass = NULL; - type = TypeParam(p, pStack); // type du résultat - - if ( type.Eq(-1) ) - { - pStack->SetError(TX_NOTYP, p); - return false; - } - - while (pStack->IsOk()) - { - CBotToken* pp = p; - IsOfType(p, ID_NOT); // saute le ~ éventuel (destructeur) - - if (IsOfType(p, TokenTypVar)) - { - CBotInstr* limites = NULL; - while ( IsOfType( p, ID_OPBRK ) ) // un tableau ? - { - CBotInstr* i = NULL; - - if ( p->GivType() != ID_CLBRK ) - i = CBotExpression::Compile( p, pStack ); // expression pour la valeur - else - i = new CBotEmpty(); // spécial si pas de formule - - type = CBotTypResult(CBotTypArrayPointer, type); - - if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) ) - { - pStack->SetError(TX_CLBRK, p->GivStart()); - return false; - } - -/* CBotVar* pv = pStack->GivVar(); - if ( pv->GivType()>= CBotTypBoolean ) - { - pStack->SetError(TX_BADTYPE, p->GivStart()); - return false; - }*/ - - if (limites == NULL) limites = i; - else limites->AddNext3(i); - } - - if ( p->GivType() == ID_OPENPAR ) - { - if ( !bSecond ) - { - p = pBase; - CBotFunction* f = - CBotFunction::Compile1(p, pStack, this); - - if ( f == NULL ) return false; - - if (m_pMethod == NULL) m_pMethod = f; - else m_pMethod->AddNext(f); - } - else - { - // retrouve la méthode précompilée en passe 1 - CBotFunction* pf = m_pMethod; - CBotFunction* prev = NULL; - while ( pf != NULL ) - { - if (pf->GivName() == pp->GivString()) break; - prev = pf; - pf = pf->Next(); - } - - bool bConstructor = (pp->GivString() == GivName()); - CBotCStack* pile = pStack->TokenStack(NULL, true); - - // rend "this" connu - CBotToken TokenThis(CBotString("this"), CBotString()); - CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) ); - pThis->SetUniqNum(-2); - pile->AddVar(pThis); - - if ( m_pParent ) - { - // rend "super" connu - CBotToken TokenSuper(CBotString("super"), CBotString()); - CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) ); - pThis->SetUniqNum(-3); - pile->AddVar(pThis); - } - -// int num = 1; - CBotClass* my = this; - while (my != NULL) - { - // place une copie des varibles de la classe (this) sur la pile - CBotVar* pv = my->m_pVar; - while (pv != NULL) - { - CBotVar* pcopy = CBotVar::Create(pv); - pcopy->SetInit(!bConstructor || pv->IsStatic()); - pcopy->SetUniqNum(pv->GivUniqNum()); - pile->AddVar(pcopy); - pv = pv->GivNext(); - } - my = my->m_pParent; - } - - // compile une méthode - p = pBase; - CBotFunction* f = - CBotFunction::Compile(p, pile, NULL/*, false*/); - - if ( f != NULL ) - { - f->m_pProg = pStack->GivBotCall(); - f->m_bSynchro = bSynchro; - // remplace l'élément dans la chaîne - f->m_next = pf->m_next; - pf->m_next = NULL; - delete pf; - if (prev == NULL) m_pMethod = f; - else prev->m_next = f; - } - pStack->Return(NULL, pile); - } - - return pStack->IsOk(); - } - - // définition d'un élément - if (type.Eq(0)) - { - pStack->SetError(TX_ENDOF, p); - return false; - } - - CBotInstr* i = NULL; - if ( IsOfType(p, ID_ASS ) ) - { - if ( type.Eq(CBotTypArrayPointer) ) - { - i = CBotListArray::Compile(p, pStack, type.GivTypElem()); - } - else - { - // il y a une assignation à calculer - i = CBotTwoOpExpr::Compile(p, pStack); - } - if ( !pStack->IsOk() ) return false; - } - - - if ( !bSecond ) - { - CBotVar* pv = CBotVar::Create(pp->GivString(), type); - pv -> SetStatic( bStatic ); - pv -> SetPrivate( mProtect ); - - AddItem( pv ); - - pv->m_InitExpr = i; - pv->m_LimExpr = limites; - - - if ( pv->IsStatic() && pv->m_InitExpr != NULL ) - { - CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante - while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // évalue l'expression sans timer - pv->SetVal( pile->GivVar() ) ; - pile->Delete(); - } - } - else - delete i; - - if ( IsOfType(p, ID_COMMA) ) continue; - if ( IsOfType(p, ID_SEP) ) break; - } - pStack->SetError(TX_ENDOF, p); - } - return pStack->IsOk(); -} - - -CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack) -{ - if ( !IsOfType(p, ID_PUBLIC) ) return NULL; - if ( !IsOfType(p, ID_CLASS) ) return NULL; - - CBotString name = p->GivString(); - - // un nom pour la classe est-il là ? - if (IsOfType(p, TokenTypVar)) - { - // la classe à été créée par Compile1 - CBotClass* pOld = CBotClass::Find(name); - - if ( IsOfType( p, ID_EXTENDS ) ) - { - IsOfType(p, TokenTypVar); // forcément - } - IsOfType( p, ID_OPBLK); // forcément - - while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) ) - { - pOld->CompileDefItem(p, pStack, true); - } - - pOld->m_IsDef = true; // définition terminée - if (pStack->IsOk()) return pOld; - } - pStack->SetError(TX_ENDOF, p); - return NULL; -} +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +/////////////////////////////////////////////////////////////////////// +// compilation of various functions declared by the user +// + +#include "CBot.h" + +// various constructors / destructors +// \TODO translation:to liberate all according to esteblished tree +// pour libérer tout selon l'arbre établi +CBotFunction::CBotFunction() +{ + m_Param = NULL; // empty parameter list + m_Block = NULL; // the instruction block + m_next = NULL; // functions can be chained + m_bPublic = false; // function not public + m_bExtern = false; // function not extern + m_nextpublic = NULL; + m_prevpublic = NULL; + m_pProg = NULL; +// m_nThisIdent = 0; + m_nFuncIdent = 0; + m_bSynchro = false; +} + +CBotFunction* CBotFunction::m_listPublic = NULL; + +CBotFunction::~CBotFunction() +{ + delete m_Param; // empty parameter list + delete m_Block; // the instruction block + delete m_next; + + // remove public list if there is + if ( m_bPublic ) + { + if ( m_nextpublic != NULL ) + { + m_nextpublic->m_prevpublic = m_prevpublic; + } + if ( m_prevpublic != NULL) + { + m_prevpublic->m_nextpublic = m_nextpublic; + } + else + { + // if prev = next = null may not be in the list! + if ( m_listPublic == this ) m_listPublic = m_nextpublic; + } + } +} + +bool CBotFunction::IsPublic() +{ + return m_bPublic; +} + +bool CBotFunction::IsExtern() +{ + return m_bExtern; +} + +bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop) +{ + start = m_extern.GivStart(); + stop = m_closeblk.GivEnd(); + + if (modestart == GetPosExtern) + { + start = m_extern.GivStart(); + } + if (modestop == GetPosExtern) + { + stop = m_extern.GivEnd(); + } + if (modestart == GetPosNom) + { + start = m_token.GivStart(); + } + if (modestop == GetPosNom) + { + stop = m_token.GivEnd(); + } + if (modestart == GetPosParam) + { + start = m_openpar.GivStart(); + } + if (modestop == GetPosParam) + { + stop = m_closepar.GivEnd(); + } + if (modestart == GetPosBloc) + { + start = m_openblk.GivStart(); + } + if (modestop == GetPosBloc) + { + stop = m_closeblk.GivEnd(); + } + + return true; +} + + +CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type) +{ + while ( IsOfType( p, ID_OPBRK ) ) + { + if ( !IsOfType( p, ID_CLBRK ) ) + { + pile->SetError(TX_CLBRK, p->GivStart()); + return CBotTypResult( -1 ); + } + type = CBotTypResult( CBotTypArrayPointer, type ); + } + return type; +} + +CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile) +{ + CBotClass* pClass = NULL; + + switch (p->GivType()) + { + case ID_INT: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypInt )); + case ID_FLOAT: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypFloat )); + case ID_BOOLEAN: + case ID_BOOL: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypBoolean )); + case ID_STRING: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypString )); + case ID_VOID: + p = p->GivNext(); + return CBotTypResult( 0 ); + + case TokenTypVar: + pClass = CBotClass::Find(p); + if ( pClass != NULL) + { + p = p->GivNext(); + return ArrayType(p, pile, + pClass->IsIntrinsic() ? + CBotTypResult( CBotTypIntrinsic, pClass ) : + CBotTypResult( CBotTypPointer, pClass ) ); + } + } + return CBotTypResult( -1 ); +} + +// compiles a new function +// bLocal allows of the declaration of parameters on the same level +// as the elements belonging to the class for methods +CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal) +{ + CBotToken* pp; + CBotFunction* func = finput; + if ( func == NULL ) func = new CBotFunction(); + + CBotCStack* pStk = pStack->TokenStack(p, bLocal); + +// func->m_nFuncIdent = CBotVar::NextUniqNum(); + + while (true) + { + if ( IsOfType(p, ID_PUBLIC) ) + { + func->m_bPublic = true; + continue; + } + pp = p; + if ( IsOfType(p, ID_EXTERN) ) + { + func->m_extern = pp; // for the position of the word "extern" + func->m_bExtern = true; +// func->m_bPublic = true; // therefore also public! + continue; + } + break; + } + + func->m_retToken = *p; +// CBotClass* pClass; + func->m_retTyp = TypeParam(p, pStk); // type of the result + + if (func->m_retTyp.GivType() >= 0) + { + CBotToken* pp = p; + func->m_token = *p; + + if ( IsOfType(p, ID_NOT) ) + { + CBotToken d("~" + p->GivString()); + func->m_token = d; + } + + // un nom de fonction est-il là ? + if (IsOfType(p, TokenTypVar)) + { + if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class + { + func->m_MasterClass = pp->GivString(); + CBotClass* pClass = CBotClass::Find(pp); + if ( pClass == NULL ) goto bad; + +// pp = p; + func->m_token = *p; + if (!IsOfType(p, TokenTypVar)) goto bad; + + } + func->m_openpar = p; + func->m_Param = CBotDefParam::Compile( p, pStk ); + func->m_closepar = p->GivPrev(); + if (pStk->IsOk()) + { + pStk->SetRetType(func->m_retTyp); // for knowledge what type returns + + if (!func->m_MasterClass.IsEmpty()) + { + // return "this" known + CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass )); + pThis->SetInit(2); +// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() will not + pThis->SetUniqNum(-2); + pStk->AddVar(pThis); + + // initialize variables acording to This + // only saves the pointer to the first, + // the rest is chained + CBotVar* pv = pThis->GivItemList(); +// int num = 1; + while (pv != NULL) + { + CBotVar* pcopy = CBotVar::Create(pv); +// pcopy->SetInit(2); + pcopy->Copy(pv); + pcopy->SetPrivate(pv->GivPrivate()); +// pcopy->SetUniqNum(pv->GivUniqNum()); //num++); + pStk->AddVar(pcopy); + pv = pv->GivNext(); + } + } + + // and compiles the following instruction block + func->m_openblk = p; + func->m_Block = CBotBlock::Compile(p, pStk, false); + func->m_closeblk = p->GivPrev(); + if ( pStk->IsOk() ) + { + if ( func->m_bPublic ) // public function, return known for all + { + CBotFunction::AddPublic(func); + } + return pStack->ReturnFunc(func, pStk); + } + } + } +bad: + pStk->SetError(TX_NOFONC, p); + } + pStk->SetError(TX_NOTYP, p); + if ( finput == NULL ) delete func; + return pStack->ReturnFunc(NULL, pStk); +} + +// pre-compile a new function +CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) +{ + CBotFunction* func = new CBotFunction(); + func->m_nFuncIdent = CBotVar::NextUniqNum(); + + CBotCStack* pStk = pStack->TokenStack(p, true); + + while (true) + { + if ( IsOfType(p, ID_PUBLIC) ) + { + // func->m_bPublic = true; // will be done in two passes + continue; + } + if ( IsOfType(p, ID_EXTERN) ) + { + func->m_bExtern = true; + continue; + } + break; + } + + func->m_retToken = *p; + func->m_retTyp = TypeParam(p, pStack); // type of the result + + if (func->m_retTyp.GivType() >= 0) + { + CBotToken* pp = p; + func->m_token = *p; + // un nom de fonction est-il là ? + if (IsOfType(p, TokenTypVar)) + { + if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class + { + func->m_MasterClass = pp->GivString(); + CBotClass* pClass = CBotClass::Find(pp); + if ( pClass == NULL ) + { + pStk->SetError(TX_NOCLASS, pp); + goto bad; + } + + pp = p; + func->m_token = *p; + if (!IsOfType(p, TokenTypVar)) goto bad; + + } + func->m_Param = CBotDefParam::Compile( p, pStk ); + if (pStk->IsOk()) + { + // looks if the function exists elsewhere + if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) && + ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) ) + { + if (IsOfType(p, ID_OPBLK)) + { + int level = 1; + // and skips the following instruction block + do + { + int type = p->GivType(); + p = p->GivNext(); + if (type == ID_OPBLK) level++; + if (type == ID_CLBLK) level--; + } + while (level > 0 && p != NULL); + + return pStack->ReturnFunc(func, pStk); + } + pStk->SetError(TX_OPENBLK, p); + } + } + pStk->SetError(TX_REDEF, pp); + } +bad: + pStk->SetError(TX_NOFONC, p); + } + pStk->SetError(TX_NOTYP, p); + delete func; + return pStack->ReturnFunc(NULL, pStk); +} + +#ifdef _DEBUG +static int xx = 0; +#endif + +bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) +{ + CBotStack* pile = pj->AddStack(this, 2); // one end of stack local to this function +// if ( pile == EOX ) return true; + + pile->SetBotCall(m_pProg); // bases for routines + + if ( pile->GivState() == 0 ) + { + if ( !m_Param->Execute(ppVars, pile) ) return false; // define parameters + pile->IncState(); + } + + if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() ) + { + // makes "this" known + CBotVar* pThis ; + if ( pInstance == NULL ) + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass )); + pThis->SetInit(2); + } + else + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass )); + pThis->SetPointer(pInstance); + pThis->SetInit(2); + } + +// pThis->SetUniqNum(m_nThisIdent); + pThis->SetUniqNum(-2); + pile->AddVar(pThis); + + pile->IncState(); + } + + if ( pile->IfStep() ) return false; + + if ( !m_Block->Execute(pile) ) + { + if ( pile->GivError() < 0 ) + pile->SetError( 0 ); + else + return false; + } + + return pj->Return(pile); +} + + +void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) +{ + CBotStack* pile = pj->RestoreStack(this); // one end of stack local to this function + if ( pile == NULL ) return; + CBotStack* pile2 = pile; + + pile->SetBotCall(m_pProg); // bases for routines + + if ( pile->GivBlock() < 2 ) + { + CBotStack* pile2 = pile->RestoreStack(NULL); // one end of stack local to this function + if ( pile2 == NULL ) return; + pile->SetState(pile->GivState() + pile2->GivState()); + pile2->Delete(); + } + + m_Param->RestoreState(pile2, true); // parameters + + if ( !m_MasterClass.IsEmpty() ) + { + CBotVar* pThis = pile->FindVar("this"); + pThis->SetInit(2); + pThis->SetUniqNum(-2); + } + + m_Block->RestoreState(pile2, true); +} + +void CBotFunction::AddNext(CBotFunction* p) +{ + CBotFunction* pp = this; + while (pp->m_next != NULL) pp = pp->m_next; + + pp->m_next = p; +} + + +CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent) +{ + nIdent = 0; + CBotTypResult type; + + CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); + return type; +} + + +// is a function according to its unique identifier +// if the identifier is not found, looking by name and parameters + +CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic) +{ + TypeOrError.SetType(TX_UNDEFCALL); // no routine of the name + CBotFunction* pt; + + if ( nIdent ) + { + if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next ) + { + if ( pt->m_nFuncIdent == nIdent ) + { + TypeOrError = pt->m_retTyp; + return pt; + } + } + + // search the list of public functions + + for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) + { + if ( pt->m_nFuncIdent == nIdent ) + { + TypeOrError = pt->m_retTyp; + return pt; + } + } + } + + if ( name == NULL ) return NULL; + + int delta = 99999; // seeks the lowest signature + CBotFunction* pFunc = NULL; // the best function found + + if ( this != NULL ) + { + for ( pt = this ; pt != NULL ; pt = pt->m_next ) + { + if ( pt->m_token.GivString() == name ) + { + int i = 0; + int alpha = 0; // signature of parameters + // parameters are compatible? + CBotDefParam* pv = pt->m_Param; // expected list of parameters + CBotVar* pw = ppVars[i++]; // provided list parameter + while ( pv != NULL && pw != NULL) + { + if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult())) + { + if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; + break; + } + int d = pv->GivType() - pw->GivType(2); + alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! + + pv = pv->GivNext(); + pw = ppVars[i++]; + } + if ( pw != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); + continue; // too many parameters + } + if ( pv != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); + continue; // not enough parameters + } + + if (alpha == 0) // perfect signature + { + nIdent = pt->m_nFuncIdent; + TypeOrError = pt->m_retTyp; + return pt; + } + + if ( alpha < delta ) // a better signature? + { + pFunc = pt; + delta = alpha; + } + } + } + } + + if ( bPublic ) + { + for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) + { + if ( pt->m_token.GivString() == name ) + { + int i = 0; + int alpha = 0; // signature of parameters + // parameters sont-ils compatibles ? + CBotDefParam* pv = pt->m_Param; // list of expected parameters + CBotVar* pw = ppVars[i++]; // list of provided parameters + while ( pv != NULL && pw != NULL) + { + if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult())) + { + if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; + break; + } + int d = pv->GivType() - pw->GivType(2); + alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! + + pv = pv->GivNext(); + pw = ppVars[i++]; + } + if ( pw != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); + continue; // to many parameters + } + if ( pv != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); + continue; // not enough parameters + } + + if (alpha == 0) // perfect signature + { + nIdent = pt->m_nFuncIdent; + TypeOrError = pt->m_retTyp; + return pt; + } + + if ( alpha < delta ) // a better signature? + { + pFunc = pt; + delta = alpha; + } + } + } + } + + if ( pFunc != NULL ) + { + nIdent = pFunc->m_nFuncIdent; + TypeOrError = pFunc->m_retTyp; + return pFunc; + } + return NULL; +} + + +// fait un appel à une fonction + +int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) +{ + CBotTypResult type; + CBotFunction* pt = NULL; + + pt = FindLocalOrPublic(nIdent, name, ppVars, type); + + if ( pt != NULL ) + { + CBotStack* pStk1 = pStack->AddStack(pt, 2); // to put "this" +// if ( pStk1 == EOX ) return true; + + pStk1->SetBotCall(pt->m_pProg); // it may have changed module + + if ( pStk1->IfStep() ) return false; + + CBotStack* pStk3 = pStk1->AddStack(NULL, true); // parameters + + // preparing parameters on the stack + + if ( pStk1->GivState() == 0 ) + { + if ( !pt->m_MasterClass.IsEmpty() ) + { + CBotVar* pInstance = m_pProg->m_pInstance; + // make "this" known + CBotVar* pThis ; + if ( pInstance == NULL ) + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass )); + pThis->SetInit(2); + } + else + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass )); + pThis->SetPointer(pInstance); + pThis->SetInit(2); + } + + pThis->SetUniqNum(-2); + pStk1->AddVar(pThis); + + } + + // initializes the variables as parameters + pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted + + pStk1->IncState(); + } + + // finally execution of the found function + + if ( !pStk3->GivRetVar( // puts the result on the stack + pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted + { + if ( !pStk3->IsOk() && pt->m_pProg != m_pProg ) + { +#ifdef _DEBUG + if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return false; +#endif + pStk3->SetPosError(pToken); // indicates the error on the procedure call + } + return false; // interrupt ! + } + + return pStack->Return( pStk3 ); + } + return -1; +} + +void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack) +{ + CBotTypResult type; + CBotFunction* pt = NULL; + CBotStack* pStk1; + CBotStack* pStk3; + + // search function to return the ok identifier + + pt = FindLocalOrPublic(nIdent, name, ppVars, type); + + if ( pt != NULL ) + { + pStk1 = pStack->RestoreStack(pt); + if ( pStk1 == NULL ) return; + + pStk1->SetBotCall(pt->m_pProg); // it may have changed module + + if ( pStk1->GivBlock() < 2 ) + { + CBotStack* pStk2 = pStk1->RestoreStack(NULL); // used more + if ( pStk2 == NULL ) return; + pStk3 = pStk2->RestoreStack(NULL); + if ( pStk3 == NULL ) return; + } + else + { + pStk3 = pStk1->RestoreStack(NULL); + if ( pStk3 == NULL ) return; + } + + // preparing parameters on the stack + + { + if ( !pt->m_MasterClass.IsEmpty() ) + { + CBotVar* pInstance = m_pProg->m_pInstance; + // make "this" known + CBotVar* pThis = pStk1->FindVar("this"); + pThis->SetInit(2); + pThis->SetUniqNum(-2); + } + } + + if ( pStk1->GivState() == 0 ) + { + pt->m_Param->RestoreState(pStk3, true); + return; + } + + // initializes the variables as parameters + pt->m_Param->RestoreState(pStk3, false); + pt->m_Block->RestoreState(pStk3, true); + } +} + + + +// makes call of a method +// note: this is already on the stack, the pointer pThis is just to simplify + +int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass) +{ + CBotTypResult type; + CBotProgram* pProgCurrent = pStack->GivBotCall(); + + CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false); + + if ( pt != NULL ) + { +// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack); + + CBotStack* pStk = pStack->AddStack(pt, 2); +// if ( pStk == EOX ) return true; + + pStk->SetBotCall(pt->m_pProg); // it may have changed module + CBotStack* pStk3 = pStk->AddStack(NULL, true); // to set parameters passed + + // preparing parameters on the stack + + if ( pStk->GivState() == 0 ) + { + // sets the variable "this" on the stack + CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); + pthis->Copy(pThis, false); + pthis->SetUniqNum(-2); // special value + pStk->AddVar(pthis); + + CBotClass* pClass = pThis->GivClass()->GivParent(); + if ( pClass ) + { + // sets the variable "super" on the stack + CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); + psuper->Copy(pThis, false); // in fact identical to "this" + psuper->SetUniqNum(-3); // special value + pStk->AddVar(psuper); + } + // initializes the variables as parameters + pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted + pStk->IncState(); + } + + if ( pStk->GivState() == 1 ) + { + if ( pt->m_bSynchro ) + { + CBotProgram* pProgBase = pStk->GivBotCall(true); + if ( !pClass->Lock(pProgBase) ) return false; // expected to power \TODO attend de pouvoir + } + pStk->IncState(); + } + // finally calls the found function + + if ( !pStk3->GivRetVar( // puts the result on the stack + pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted + { + if ( !pStk3->IsOk() ) + { + if ( pt->m_bSynchro ) + { + pClass->Unlock(); // release function + } + + if ( pt->m_pProg != pProgCurrent ) + { + pStk3->SetPosError(pToken); // indicates the error on the procedure call + } + } + return false; // interrupt ! + } + + if ( pt->m_bSynchro ) + { + pClass->Unlock(); // release function + } + + return pStack->Return( pStk3 ); + } + return -1; +} + +void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass) +{ + CBotTypResult type; + CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); + + if ( pt != NULL ) + { + CBotStack* pStk = pStack->RestoreStack(pt); + if ( pStk == NULL ) return; + pStk->SetBotCall(pt->m_pProg); // it may have changed module + + CBotVar* pthis = pStk->FindVar("this"); + pthis->SetUniqNum(-2); + + CBotStack* pStk3 = pStk->RestoreStack(NULL); // to set parameters passed + if ( pStk3 == NULL ) return; + + pt->m_Param->RestoreState(pStk3, true); // parameters + + if ( pStk->GivState() > 1 && // latching is effective? + pt->m_bSynchro ) + { + CBotProgram* pProgBase = pStk->GivBotCall(true); + pClass->Lock(pProgBase); // locks the class + } + + // finally calls the found function + + pt->m_Block->RestoreState(pStk3, true); // interrupt ! + } +} + +// see if the "signature" of parameters is identical +bool CBotFunction::CheckParam(CBotDefParam* pParam) +{ + CBotDefParam* pp = m_Param; + while ( pp != NULL && pParam != NULL ) + { + CBotTypResult type1 = pp->GivType(); + CBotTypResult type2 = pParam->GivType(); + if ( !type1.Compare(type2) ) return false; + pp = pp->GivNext(); + pParam = pParam->GivNext(); + } + return ( pp == NULL && pParam == NULL ); +} + +CBotString CBotFunction::GivName() +{ + return m_token.GivString(); +} + +CBotString CBotFunction::GivParams() +{ + if ( m_Param == NULL ) return CBotString("()"); + + CBotString params = "( "; + CBotDefParam* p = m_Param; // list of parameters + + while (p != NULL) + { + params += p->GivParamString(); + p = p->GivNext(); + if ( p != NULL ) params += ", "; + } + + params += " )"; + return params; +} + +CBotFunction* CBotFunction::Next() +{ + return m_next; +} + +void CBotFunction::AddPublic(CBotFunction* func) +{ + if ( m_listPublic != NULL ) + { + func->m_nextpublic = m_listPublic; + m_listPublic->m_prevpublic = func; + } + m_listPublic = func; +} + + + +///////////////////////////////////////////////////////////////////////// +// management of parameters + + +CBotDefParam::CBotDefParam() +{ + m_next = NULL; + m_nIdent = 0; +} + +CBotDefParam::~CBotDefParam() +{ + delete m_next; +} + + +// compiles a list of parameters +CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) +{ + // mainly not pStack->TokenStack here + // declared variables must remain visible thereafter + + pStack->SetStartError(p->GivStart()); + + if (IsOfType(p, ID_OPENPAR)) + { + CBotDefParam* list = NULL; + + while (!IsOfType(p, ID_CLOSEPAR)) + { + CBotDefParam* param = new CBotDefParam(); + if (list == NULL) list = param; + else list->AddNext(param); // added to the list + + CBotClass* pClass = NULL;//= CBotClass::Find(p); + param->m_typename = p->GivString(); + CBotTypResult type = param->m_type = TypeParam(p, pStack); +// if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object + + if (param->m_type.GivType() > 0) + { + CBotToken* pp = p; + param->m_token = *p; + if (pStack->IsOk() && IsOfType(p, TokenTypVar) ) + { + + // variable already declared? + if (pStack->CheckVarLocal(pp)) + { + pStack->SetError(TX_REDEFVAR, pp); + break; + } + + if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); + CBotVar* var = CBotVar::Create(pp->GivString(), type); // creates the variable +// if ( pClass ) var->SetClass(pClass); + var->SetInit(2); // mark initialized + param->m_nIdent = CBotVar::NextUniqNum(); + var->SetUniqNum(param->m_nIdent); + pStack->AddVar(var); // place on the stack + + if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR) + continue; + } + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + } + pStack->SetError(TX_NOTYP, p); + delete list; + return NULL; + } + return list; + } + pStack->SetError(TX_OPENPAR, p->GivStart()); + return NULL; +} + +void CBotDefParam::AddNext(CBotDefParam* p) +{ + CBotDefParam* pp = this; + while (pp->m_next != NULL) pp = pp->m_next; + + pp->m_next = p; +} + + +bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) +{ + int i = 0; + CBotDefParam* p = this; + + while ( p != NULL ) + { + // creates a local variable on the stack + CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type); + + // serves to make the transformation of types: + if ( ppVars != NULL && ppVars[i] != NULL ) + { + switch (p->m_type.GivType()) + { + case CBotTypInt: + newvar->SetValInt(ppVars[i]->GivValInt()); + break; + case CBotTypFloat: + newvar->SetValFloat(ppVars[i]->GivValFloat()); + break; + case CBotTypString: + newvar->SetValString(ppVars[i]->GivValString()); + break; + case CBotTypBoolean: + newvar->SetValInt(ppVars[i]->GivValInt()); + break; + case CBotTypIntrinsic: + ((CBotVarClass*)newvar)->Copy(ppVars[i], false); + break; + case CBotTypPointer: + case CBotTypArrayPointer: + { + newvar->SetPointer(ppVars[i]->GivPointer()); + } + break; + default: + ASM_TRAP(); + } + } + newvar->SetUniqNum(p->m_nIdent); + pj->AddVar(newvar); // add a variable + p = p->m_next; + i++; + } + + return true; +} + +void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) +{ + int i = 0; + CBotDefParam* p = this; + + while ( p != NULL ) + { + // creates a local variable on the stack + CBotVar* var = pj->FindVar(p->m_token.GivString()); + var->SetUniqNum(p->m_nIdent); + p = p->m_next; + } +} + +int CBotDefParam::GivType() +{ + return m_type.GivType(); +} + +CBotTypResult CBotDefParam::GivTypResult() +{ + return m_type; +} + +CBotDefParam* CBotDefParam::GivNext() +{ + return m_next; +} + +CBotString CBotDefParam::GivParamString() +{ + CBotString param; + + param = m_typename; + param += ' '; + + param += m_token.GivString(); + return param; +} + + + +////////////////////////////////////////////////////////////////////////// +// return parameters + +CBotReturn::CBotReturn() +{ + m_Instr = NULL; + name = "CBotReturn"; // debug +} + +CBotReturn::~CBotReturn() +{ + delete m_Instr; +} + +CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + + if (!IsOfType(p, ID_RETURN)) return NULL; // should never happen + + CBotReturn* inst = new CBotReturn(); // creates the object + inst->SetToken( pp ); + + CBotTypResult type = pStack->GivRetType(); + + if ( type.GivType() == 0 ) // returned void ? + { + if ( IsOfType( p, ID_SEP ) ) return inst; + pStack->SetError( TX_BADTYPE, pp ); + return NULL; + } + + inst->m_Instr = CBotExpression::Compile(p, pStack); + if ( pStack->IsOk() ) + { + CBotTypResult retType = pStack->GivTypResult(2); + if (TypeCompatible(retType, type, ID_ASS)) + { + if ( IsOfType( p, ID_SEP ) ) + return inst; + + pStack->SetError(TX_ENDOF, p->GivStart()); + } + pStack->SetError(TX_BADTYPE, p->GivStart()); + } + + delete inst; + return NULL; // no object, the error is on the stack +} + +bool CBotReturn::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); +// if ( pile == EOX ) return true; + + if ( pile->GivState() == 0 ) + { + if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // evaluate the result + // the result is on the stack + pile->IncState(); + } + + if ( pile->IfStep() ) return false; + + pile->SetBreak(3, CBotString()); + return pj->Return(pile); +} + +void CBotReturn::RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + CBotStack* pile = pj->RestoreStack(this); + if ( pile == NULL ) return; + + if ( pile->GivState() == 0 ) + { + if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // evaluate the result + return; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Calls of these functions + +CBotInstrCall::CBotInstrCall() +{ + m_Parameters = NULL; + m_nFuncIdent = 0; + name = "CBotInstrCall"; +} + +CBotInstrCall::~CBotInstrCall() +{ + delete m_Parameters; +} + +CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotVar* ppVars[1000]; + + int i = 0; + + CBotToken* pp = p; + p = p->GivNext(); + + pStack->SetStartError(p->GivStart()); + CBotCStack* pile = pStack; + + if ( IsOfType(p, ID_OPENPAR) ) + { + int start, end; + CBotInstrCall* inst = new CBotInstrCall(); + inst->SetToken(pp); + + // compile la list of parameters + if (!IsOfType(p, ID_CLOSEPAR)) while (true) + { + start = p->GivStart(); + pile = pile->TokenStack(); // keeps the results on the stack + + CBotInstr* param = CBotExpression::Compile(p, pile); + end = p->GivStart(); + if ( inst->m_Parameters == NULL ) inst->m_Parameters = param; + else inst->m_Parameters->AddNext(param); // constructs the list + + if ( !pile->IsOk() ) + { + delete inst; + return pStack->Return(NULL, pile); + } + + if ( param != NULL ) + { + if ( pile->GivTypResult().Eq(99) ) + { + delete pStack->TokenStack(); + pStack->SetError(TX_VOID, p->GivStart()); + delete inst; + return NULL; + } + ppVars[i] = pile->GivVar(); + ppVars[i]->GivToken()->SetPos(start, end); + i++; + + if (IsOfType(p, ID_COMMA)) continue; // skips the comma + if (IsOfType(p, ID_CLOSEPAR)) break; + } + + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + delete pStack->TokenStack(); + delete inst; + return NULL; + } + ppVars[i] = NULL; + + // the routine is known? +// CBotClass* pClass = NULL; + inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent); + if ( inst->m_typRes.GivType() >= 20 ) + { +// if (pVar2!=NULL) pp = pVar2->RetToken(); + pStack->SetError( inst->m_typRes.GivType(), pp ); + delete pStack->TokenStack(); + delete inst; + return NULL; + } + + delete pStack->TokenStack(); + if ( inst->m_typRes.GivType() > 0 ) + { + CBotVar* pRes = CBotVar::Create("", inst->m_typRes); + pStack->SetVar(pRes); // for knowing the type of the result + } + else pStack->SetVar(NULL); // routine returns void + + return inst; + } + p = pp; + delete pStack->TokenStack(); + return NULL; +} + +bool CBotInstrCall::Execute(CBotStack* &pj) +{ + CBotVar* ppVars[1000]; + CBotStack* pile = pj->AddStack(this); + if ( pile->StackOver() ) return pj->Return( pile ); + + CBotStack* pile1 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluates parameters + // and places the values ​​on the stack + // for allow of interruption at any time + if ( p != NULL) while ( true ) + { + pile = pile->AddStack(); // place on the stack for the results + if ( pile->GivState() == 0 ) + { + if (!p->Execute(pile)) return false; // interrupted here? + pile->SetState(1); // mark as special for reknowed parameters \TODO marque spéciale pour reconnaîre parameters + } + ppVars[i++] = pile->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotStack* pile2 = pile->AddStack(); + if ( pile2->IfStep() ) return false; + + if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return false; // interrupt + + return pj->Return(pile2); // release the entire stack +} + +void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pile = pj->RestoreStack(this); + if ( pile == NULL ) return; + + CBotStack* pile1 = pile; + + int i = 0; + CBotVar* ppVars[1000]; + CBotInstr* p = m_Parameters; + // evaluate parameters + // and place the values on the stack + // for allow of interruption at any time + if ( p != NULL) while ( true ) + { + pile = pile->RestoreStack(); // place on the stack for the results + if ( pile == NULL ) return; + if ( pile->GivState() == 0 ) + { + p->RestoreState(pile, bMain); // interrupt here! + return; + } + ppVars[i++] = pile->GivVar(); // constructs the list of parameters + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotStack* pile2 = pile->RestoreStack(); + if ( pile2 == NULL ) return; + + pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars); +} + +////////////////////////////////////////////////////////////////////////////// +// statement of user classes + +// pre-compile a new class +// analysis is complete except the body of routines + +CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) +{ + if ( !IsOfType(p, ID_PUBLIC) ) + { + pStack->SetError(TX_NOPUBLIC, p); + return NULL; + } + + if ( !IsOfType(p, ID_CLASS) ) return NULL; + + CBotString name = p->GivString(); + + CBotClass* pOld = CBotClass::Find(name); + if ( pOld != NULL && pOld->m_IsDef ) + { + pStack->SetError( TX_REDEFCLASS, p ); + return NULL; + } + + // a name of the class is there? + if (IsOfType(p, TokenTypVar)) + { + CBotClass* pPapa = NULL; + if ( IsOfType( p, ID_EXTENDS ) ) + { + CBotString name = p->GivString(); + pPapa = CBotClass::Find(name); + + if (!IsOfType(p, TokenTypVar) || pPapa == NULL ) + { + pStack->SetError( TX_NOCLASS, p ); + return NULL; + } + } + CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld; + classe->Purge(); // emptythe old definitions + classe->m_IsDef = false; // current definition + + if ( !IsOfType( p, ID_OPBLK) ) + { + pStack->SetError(TX_OPENBLK, p); + return NULL; + } + + while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) ) + { + classe->CompileDefItem(p, pStack, false); + } + + if (pStack->IsOk()) return classe; + } + pStack->SetError(TX_ENDOF, p); + return NULL; +} + +bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) +{ + bool bStatic = false; + int mProtect = PR_PUBLIC; + bool bSynchro = false; + + while (IsOfType(p, ID_SEP)) ; + + CBotTypResult type( -1 ); + + if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true; + CBotToken* pBase = p; + + if ( IsOfType(p, ID_STATIC) ) bStatic = true; + if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC; + if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE; + if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT; + if ( IsOfType(p, ID_STATIC) ) bStatic = true; + +// CBotClass* pClass = NULL; + type = TypeParam(p, pStack); // type of the result + + if ( type.Eq(-1) ) + { + pStack->SetError(TX_NOTYP, p); + return false; + } + + while (pStack->IsOk()) + { + CBotToken* pp = p; + IsOfType(p, ID_NOT); // skips ~ eventual (destructor) + + if (IsOfType(p, TokenTypVar)) + { + CBotInstr* limites = NULL; + while ( IsOfType( p, ID_OPBRK ) ) // a table? + { + CBotInstr* i = NULL; + + if ( p->GivType() != ID_CLBRK ) + i = CBotExpression::Compile( p, pStack ); // expression for the value + else + i = new CBotEmpty(); // special if not a formula + + type = CBotTypResult(CBotTypArrayPointer, type); + + if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) ) + { + pStack->SetError(TX_CLBRK, p->GivStart()); + return false; + } + +/* CBotVar* pv = pStack->GivVar(); + if ( pv->GivType()>= CBotTypBoolean ) + { + pStack->SetError(TX_BADTYPE, p->GivStart()); + return false; + }*/ + + if (limites == NULL) limites = i; + else limites->AddNext3(i); + } + + if ( p->GivType() == ID_OPENPAR ) + { + if ( !bSecond ) + { + p = pBase; + CBotFunction* f = + CBotFunction::Compile1(p, pStack, this); + + if ( f == NULL ) return false; + + if (m_pMethod == NULL) m_pMethod = f; + else m_pMethod->AddNext(f); + } + else + { + // return a method precompiled in pass 1 + CBotFunction* pf = m_pMethod; + CBotFunction* prev = NULL; + while ( pf != NULL ) + { + if (pf->GivName() == pp->GivString()) break; + prev = pf; + pf = pf->Next(); + } + + bool bConstructor = (pp->GivString() == GivName()); + CBotCStack* pile = pStack->TokenStack(NULL, true); + + // make "this" known + CBotToken TokenThis(CBotString("this"), CBotString()); + CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) ); + pThis->SetUniqNum(-2); + pile->AddVar(pThis); + + if ( m_pParent ) + { + // makes "super" known + CBotToken TokenSuper(CBotString("super"), CBotString()); + CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) ); + pThis->SetUniqNum(-3); + pile->AddVar(pThis); + } + +// int num = 1; + CBotClass* my = this; + while (my != NULL) + { + // places a copy of variables of a class (this) on a stack + CBotVar* pv = my->m_pVar; + while (pv != NULL) + { + CBotVar* pcopy = CBotVar::Create(pv); + pcopy->SetInit(!bConstructor || pv->IsStatic()); + pcopy->SetUniqNum(pv->GivUniqNum()); + pile->AddVar(pcopy); + pv = pv->GivNext(); + } + my = my->m_pParent; + } + + // compiles a method + p = pBase; + CBotFunction* f = + CBotFunction::Compile(p, pile, NULL/*, false*/); + + if ( f != NULL ) + { + f->m_pProg = pStack->GivBotCall(); + f->m_bSynchro = bSynchro; + // replaces the element in the chain + f->m_next = pf->m_next; + pf->m_next = NULL; + delete pf; + if (prev == NULL) m_pMethod = f; + else prev->m_next = f; + } + pStack->Return(NULL, pile); + } + + return pStack->IsOk(); + } + + // definition of an element + if (type.Eq(0)) + { + pStack->SetError(TX_ENDOF, p); + return false; + } + + CBotInstr* i = NULL; + if ( IsOfType(p, ID_ASS ) ) + { + if ( type.Eq(CBotTypArrayPointer) ) + { + i = CBotListArray::Compile(p, pStack, type.GivTypElem()); + } + else + { + // it has an assignmet to calculate + i = CBotTwoOpExpr::Compile(p, pStack); + } + if ( !pStack->IsOk() ) return false; + } + + + if ( !bSecond ) + { + CBotVar* pv = CBotVar::Create(pp->GivString(), type); + pv -> SetStatic( bStatic ); + pv -> SetPrivate( mProtect ); + + AddItem( pv ); + + pv->m_InitExpr = i; + pv->m_LimExpr = limites; + + + if ( pv->IsStatic() && pv->m_InitExpr != NULL ) + { + CBotStack* pile = CBotStack::FirstStack(); // independent stack + while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer + pv->SetVal( pile->GivVar() ) ; + pile->Delete(); + } + } + else + delete i; + + if ( IsOfType(p, ID_COMMA) ) continue; + if ( IsOfType(p, ID_SEP) ) break; + } + pStack->SetError(TX_ENDOF, p); + } + return pStack->IsOk(); +} + + +CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack) +{ + if ( !IsOfType(p, ID_PUBLIC) ) return NULL; + if ( !IsOfType(p, ID_CLASS) ) return NULL; + + CBotString name = p->GivString(); + + // a name for the class is there? + if (IsOfType(p, TokenTypVar)) + { + // the class was created by Compile1 + CBotClass* pOld = CBotClass::Find(name); + + if ( IsOfType( p, ID_EXTENDS ) ) + { + IsOfType(p, TokenTypVar); // necessarily + } + IsOfType( p, ID_OPBLK); // necessarily + + while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) ) + { + pOld->CompileDefItem(p, pStack, true); + } + + pOld->m_IsDef = true; // complete definition + if (pStack->IsOk()) return pOld; + } + pStack->SetError(TX_ENDOF, p); + return NULL; +} -- cgit v1.2.3-1-g7c22