diff options
author | Piotr Dziwiński <piotrdz@gmail.com> | 2012-08-08 13:31:33 -0700 |
---|---|---|
committer | Piotr Dziwiński <piotrdz@gmail.com> | 2012-08-08 13:31:33 -0700 |
commit | beca66071c6a2d82da63fb238cdc86e68ff96bdb (patch) | |
tree | fdd53a1c67952a656de5ba3a17117fc9d6ef0e7f /src/CBot | |
parent | 5e637ca0288ddd631ec33e1d620cd4a73bcdc2be (diff) | |
parent | a760e8a749af60cd3598ebe113b7692bc6592f57 (diff) | |
download | colobot-beca66071c6a2d82da63fb238cdc86e68ff96bdb.tar.gz colobot-beca66071c6a2d82da63fb238cdc86e68ff96bdb.tar.bz2 colobot-beca66071c6a2d82da63fb238cdc86e68ff96bdb.zip |
Merge pull request #35 from konopackim/dev
Comment translation and cleanups
Diffstat (limited to 'src/CBot')
-rw-r--r-- | src/CBot/CBot.aps | bin | 44112 -> 0 bytes | |||
-rw-r--r-- | src/CBot/CBot.cpp | 7927 | ||||
-rw-r--r-- | src/CBot/CBot.h | 3465 | ||||
-rw-r--r-- | src/CBot/CBotAddExpr.cpp | 286 | ||||
-rw-r--r-- | src/CBot/CBotClass.cpp | 1762 | ||||
-rw-r--r-- | src/CBot/CBotCompExpr.cpp | 264 | ||||
-rw-r--r-- | src/CBot/CBotDll.h | 2188 | ||||
-rw-r--r-- | src/CBot/CBotFunction.cpp | 3291 | ||||
-rw-r--r-- | src/CBot/CBotIf.cpp | 320 | ||||
-rw-r--r-- | src/CBot/CBotProgram.cpp | 2230 | ||||
-rw-r--r-- | src/CBot/CBotStack.cpp | 2942 | ||||
-rw-r--r-- | src/CBot/CBotString.cpp | 3 | ||||
-rw-r--r-- | src/CBot/CBotToken.cpp | 176 | ||||
-rw-r--r-- | src/CBot/CBotToken.h | 13 | ||||
-rw-r--r-- | src/CBot/CBotTwoOpExpr.cpp | 1134 | ||||
-rw-r--r-- | src/CBot/CBotVar.cpp | 4493 | ||||
-rw-r--r-- | src/CBot/CBotWhile.cpp | 2860 | ||||
-rw-r--r-- | src/CBot/ClassFILE.cpp | 244 | ||||
-rw-r--r-- | src/CBot/StringFunctions.cpp | 870 | ||||
-rw-r--r-- | src/CBot/_Copy.bat | 2 | ||||
-rw-r--r-- | src/CBot/colobot.ini | 49 | ||||
-rw-r--r-- | src/CBot/resource.h | 5 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/CBotConsoleDlg.cpp (renamed from src/CBot/TestCBot/CBotConsoleDlg.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/CBotConsoleDlg.h (renamed from src/CBot/TestCBot/CBotConsoleDlg.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/ChildFrm.cpp (renamed from src/CBot/TestCBot/ChildFrm.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/ChildFrm.h (renamed from src/CBot/TestCBot/ChildFrm.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/MainFrm.cpp (renamed from src/CBot/TestCBot/MainFrm.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/MainFrm.h (renamed from src/CBot/TestCBot/MainFrm.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/PerformDlg.cpp (renamed from src/CBot/TestCBot/PerformDlg.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/PerformDlg.h (renamed from src/CBot/TestCBot/PerformDlg.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/Routines.cpp (renamed from src/CBot/TestCBot/Routines.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/StdAfx.cpp (renamed from src/CBot/TestCBot/StdAfx.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/StdAfx.h (renamed from src/CBot/TestCBot/StdAfx.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBot.clw (renamed from src/CBot/TestCBot/TestCBot.clw) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBot.cpp (renamed from src/CBot/TestCBot/TestCBot.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBot.dsp (renamed from src/CBot/TestCBot/TestCBot.dsp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBot.h (renamed from src/CBot/TestCBot/TestCBot.h) | 4 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBot.rc (renamed from src/CBot/TestCBot/TestCBot.rc) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBotDoc.cpp (renamed from src/CBot/TestCBot/TestCBotDoc.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBotDoc.h (renamed from src/CBot/TestCBot/TestCBotDoc.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBotView.cpp (renamed from src/CBot/TestCBot/TestCBotView.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/TestCBotView.h (renamed from src/CBot/TestCBot/TestCBotView.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/a§1.txt~ (renamed from src/CBot/TestCBot/a§1.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/res/TestCBot.ico (renamed from src/CBot/TestCBot/res/TestCBot.ico) | bin | 1078 -> 1078 bytes | |||
-rw-r--r-- | src/CBot/tests/TestCBot/res/TestCBot.rc2 (renamed from src/CBot/TestCBot/res/TestCBot.rc2) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/res/TestCBotDoc.ico (renamed from src/CBot/TestCBot/res/TestCBotDoc.ico) | bin | 1078 -> 1078 bytes | |||
-rw-r--r-- | src/CBot/tests/TestCBot/res/Toolbar.bmp (renamed from src/CBot/TestCBot/res/Toolbar.bmp) | bin | 1198 -> 1198 bytes | |||
-rw-r--r-- | src/CBot/tests/TestCBot/resource.h (renamed from src/CBot/TestCBot/resource.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/B.txt (renamed from src/CBot/TestCBot/B.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/BUG2.txt (renamed from src/CBot/TestCBot/BUG2.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/Deleted.txt (renamed from src/CBot/TestCBot/Deleted.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/MaClass.txt (renamed from src/CBot/TestCBot/MaClass.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/Mc2.txt (renamed from src/CBot/TestCBot/Mc2.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/Mon fichier.txt (renamed from src/CBot/TestCBot/Mon fichier.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/Nop.txt (renamed from src/CBot/TestCBot/Nop.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/POS.txt (renamed from src/CBot/TestCBot/POS.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/T.txt (renamed from src/CBot/TestCBot/T.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TESTALL.txt (renamed from src/CBot/TestCBot/TESTALL.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TestCB1.txt (renamed from src/CBot/TestCBot/TestCB1.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TestCBot1.txt (renamed from src/CBot/TestCBot/TestCBot1.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TestCBot3.txt (renamed from src/CBot/TestCBot/TestCBot3.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TestNull.txt (renamed from src/CBot/TestCBot/TestNull.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TestRestoreState.txt (renamed from src/CBot/TestCBot/TestRestoreState.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TestStatic.txt (renamed from src/CBot/TestCBot/TestStatic.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/TestStr.txt (renamed from src/CBot/TestCBot/TestStr.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/Z.txt (renamed from src/CBot/TestCBot/Z.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/a1.txt (renamed from src/CBot/TestCBot/až1.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/array.txt (renamed from src/CBot/TestCBot/array.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/až1.txt | 96 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/a§1.txt | 96 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/bug.txt (renamed from src/CBot/TestCBot/bug.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/bugmw.txt (renamed from src/CBot/TestCBot/bugmw.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/ccc.txt (renamed from src/CBot/TestCBot/ccc.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/enum.txt (renamed from src/CBot/TestCBot/enum.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/fibo.txt (renamed from src/CBot/TestCBot/fibo.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/file.txt (renamed from src/CBot/TestCBot/file.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/h.txt (renamed from src/CBot/TestCBot/h.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/include.txt (renamed from src/CBot/TestCBot/include.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/intrinsic.txt (renamed from src/CBot/TestCBot/intrinsic.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/methode1.txt (renamed from src/CBot/TestCBot/methode1.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/methode2.txt (renamed from src/CBot/TestCBot/methode2.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/mp1.txt (renamed from src/CBot/TestCBot/mp1.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/mp2.txt (renamed from src/CBot/TestCBot/mp2.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/mw.txt (renamed from src/CBot/TestCBot/mw.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/null.txt (renamed from src/CBot/TestCBot/null.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/opnew.txt (renamed from src/CBot/TestCBot/opnew.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/plante.txt (renamed from src/CBot/TestCBot/plante.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/pointer.txt (renamed from src/CBot/TestCBot/pointer.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/postinc.txt (renamed from src/CBot/TestCBot/postinc.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/radar.txt (renamed from src/CBot/TestCBot/radar.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/solution.txt (renamed from src/CBot/TestCBot/solution.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/test.txt (renamed from src/CBot/TestCBot/test.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/test23.txt (renamed from src/CBot/TestCBot/test23.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/testmw.txt (renamed from src/CBot/TestCBot/testmw.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/this.txt (renamed from src/CBot/TestCBot/this.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/tt.txt (renamed from src/CBot/TestCBot/tt.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/tt2.txt (renamed from src/CBot/TestCBot/tt2.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/vide.txt (renamed from src/CBot/TestCBot/vide.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/scenarios/zz.txt (renamed from src/CBot/TestCBot/zz.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/TestCBot/xTestCBot.clw (renamed from src/CBot/TestCBot/xTestCBot.clw) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/BotConsoleDlg.cpp (renamed from src/CBot/old TstCBot/BotConsoleDlg.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/BotConsoleDlg.h (renamed from src/CBot/old TstCBot/BotConsoleDlg.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/BotErrorDlg.cpp (renamed from src/CBot/old TstCBot/BotErrorDlg.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/BotErrorDlg.h (renamed from src/CBot/old TstCBot/BotErrorDlg.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/CBotTest.txt (renamed from src/CBot/old TstCBot/CBotTest.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/CMyThread.cpp (renamed from src/CBot/old TstCBot/CMyThread.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/CMyThread.h (renamed from src/CBot/old TstCBot/CMyThread.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/MainFrm.cpp (renamed from src/CBot/old TstCBot/MainFrm.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/MainFrm.h (renamed from src/CBot/old TstCBot/MainFrm.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/ReadMe.txt (renamed from src/CBot/old TstCBot/ReadMe.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/Resource.h (renamed from src/CBot/old TstCBot/Resource.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/StdAfx.cpp (renamed from src/CBot/old TstCBot/StdAfx.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/StdAfx.h (renamed from src/CBot/old TstCBot/StdAfx.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBot.clw (renamed from src/CBot/old TstCBot/TstCBot.clw) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBot.cpp (renamed from src/CBot/old TstCBot/TstCBot.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBot.dsp (renamed from src/CBot/old TstCBot/TstCBot.dsp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBot.h (renamed from src/CBot/old TstCBot/TstCBot.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBot.rc (renamed from src/CBot/old TstCBot/TstCBot.rc) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBotDoc.cpp (renamed from src/CBot/old TstCBot/TstCBotDoc.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBotDoc.h (renamed from src/CBot/old TstCBot/TstCBotDoc.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBotView.cpp (renamed from src/CBot/old TstCBot/TstCBotView.cpp) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/TstCBotView.h (renamed from src/CBot/old TstCBot/TstCBotView.h) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/res/TstCBot.ico (renamed from src/CBot/old TstCBot/res/TstCBot.ico) | bin | 1078 -> 1078 bytes | |||
-rw-r--r-- | src/CBot/tests/old TstCBot/res/TstCBot.rc2 (renamed from src/CBot/old TstCBot/res/TstCBot.rc2) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/res/TstCBotDoc.ico (renamed from src/CBot/old TstCBot/res/TstCBotDoc.ico) | bin | 1078 -> 1078 bytes | |||
-rw-r--r-- | src/CBot/tests/old TstCBot/test complet 1.txt (renamed from src/CBot/old TstCBot/test complet 1.txt) | 0 | ||||
-rw-r--r-- | src/CBot/tests/old TstCBot/x.txt (renamed from src/CBot/old TstCBot/x.txt) | 0 |
127 files changed, 17469 insertions, 17251 deletions
diff --git a/src/CBot/CBot.aps b/src/CBot/CBot.aps Binary files differdeleted file mode 100644 index cd294ec..0000000 --- a/src/CBot/CBot.aps +++ /dev/null diff --git a/src/CBot/CBot.cpp b/src/CBot/CBot.cpp index fb25049..62d9fb7 100644 --- a/src/CBot/CBot.cpp +++ b/src/CBot/CBot.cpp @@ -1,3963 +1,3964 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-
-// compilation of various instructions
-// compile all routines are static
-// and return an object according to what was found as instruction
-
-// compiler principle:
-// compile the routines return an object of the class corresponding to the operation found
-// this is always a subclass of CBotInstr.
-// (CBotInstr objects are never used directly)
-
-
-// compiles if the routine returns NULL is that the statement is false
-// or misunderstood.
-// the error is then on the stack CBotCStack :: Isok () is false
-
-
-
-#include "CBot.h"
-
-CBotInstr::CBotInstr()
-{
- name = "CBotInstr";
- m_next = NULL;
- m_next2b = NULL;
- m_next3 = NULL;
- m_next3b = NULL;
-}
-
-CBotInstr::~CBotInstr()
-{
- delete m_next;
- delete m_next2b;
- delete m_next3;
- delete m_next3b;
-}
-
-// counter of nested loops,
-// to determine the break and continue valid
-// list of labels used
-
-
-int CBotInstr::m_LoopLvl = 0;
-CBotStringArray CBotInstr::m_labelLvl = CBotStringArray();
-
-// adds a level with a label
-void CBotInstr::IncLvl(CBotString& label)
-{
- m_labelLvl.SetSize(m_LoopLvl+1);
- m_labelLvl[m_LoopLvl] = label;
- m_LoopLvl++;
-}
-
-// adds a level (switch statement)
-void CBotInstr::IncLvl()
-{
- m_labelLvl.SetSize(m_LoopLvl+1);
- m_labelLvl[m_LoopLvl] = "#SWITCH";
- m_LoopLvl++;
-}
-
-// free a level
-void CBotInstr::DecLvl()
-{
- m_LoopLvl--;
- m_labelLvl[m_LoopLvl].Empty();
-}
-
-// control validity of break and continue
-bool CBotInstr::ChkLvl(const CBotString& label, int type)
-{
- int i = m_LoopLvl;
- while (--i>=0)
- {
- if ( type == ID_CONTINUE && m_labelLvl[i] == "#SWITCH") continue;
- if (label.IsEmpty()) return true;
- if (m_labelLvl[i] == label) return true;
- }
- return false;
-}
-
-bool CBotInstr::IsOfClass(CBotString n)
-{
- return name == n;
-}
-
-
-////////////////////////////////////////////////////////////////////////////
-// database management class CBotInstr
-
-// set the token corresponding to the instruction
-
-void CBotInstr::SetToken(CBotToken* p)
-{
- m_token = *p;
-}
-
-// return the type of the token assicated with the instruction
-
-int CBotInstr::GivTokenType()
-{
- return m_token.GivType();
-}
-
-// return associated token
-
-CBotToken* CBotInstr::GivToken()
-{
- return &m_token;
-}
-
-// adds the statement following the other
-
-void CBotInstr::AddNext(CBotInstr* n)
-{
- CBotInstr* p = this;
- while (p->m_next != NULL) p = p->m_next;
- p->m_next = n;
-}
-
-void CBotInstr::AddNext3(CBotInstr* n)
-{
- CBotInstr* p = this;
- while (p->m_next3 != NULL) p = p->m_next3;
- p->m_next3 = n;
-}
-
-void CBotInstr::AddNext3b(CBotInstr* n)
-{
- CBotInstr* p = this;
- while (p->m_next3b != NULL) p = p->m_next3b;
- p->m_next3b = n;
-}
-
-// returns next statement
-
-CBotInstr* CBotInstr::GivNext()
-{
- return m_next;
-}
-
-CBotInstr* CBotInstr::GivNext3()
-{
- return m_next3;
-}
-
-CBotInstr* CBotInstr::GivNext3b()
-{
- return m_next3b;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// compile an instruction which can be
-// while, do, try, throw, if, for, switch, break, continue, return
-// int, float, boolean, string,
-// declaration of an instance of a class
-// arbitrary expression
-
-
-CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
-
- if (p == NULL) return NULL;
-
- int type = p->GivType(); // what is the next token
-
- // is it a lable?
- if (IsOfType(pp, TokenTypVar) &&
- IsOfType(pp, ID_DOTS))
- {
- type = pp->GivType();
- // these instructions accept only lable
- if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0))
- {
- pStack->SetError(TX_LABEL, pp->GivStart());
- return NULL;
- }
- }
-
- // call routine corresponding to the compilation token found
- switch (type)
- {
- case ID_WHILE:
- return CBotWhile::Compile(p, pStack);
-
- case ID_FOR:
- return CBotFor::Compile(p, pStack);
-
- case ID_DO:
- return CBotDo::Compile(p, pStack);
-
- case ID_REPEAT:
- return CBotRepeat::Compile(p, pStack);
-
- case ID_BREAK:
- case ID_CONTINUE:
- return CBotBreak::Compile(p, pStack);
-
- case ID_SWITCH:
- return CBotSwitch::Compile(p, pStack);
-
- case ID_TRY:
- return CBotTry::Compile(p, pStack);
-
- case ID_THROW:
- return CBotThrow::Compile(p, pStack);
-
- case ID_DEBUGDD:
- return CBotStartDebugDD::Compile(p, pStack);
-
- case ID_INT:
- return CBotInt::Compile(p, pStack);
-
- case ID_FLOAT:
- return CBotFloat::Compile(p, pStack);
-
- case ID_STRING:
- return CBotIString::Compile(p, pStack);
-
- case ID_BOOLEAN:
- case ID_BOOL:
- return CBotBoolean::Compile(p, pStack);
-
- case ID_IF:
- return CBotIf::Compile(p, pStack);
-
- case ID_RETURN:
- return CBotReturn::Compile(p, pStack);
-
- case ID_ELSE:
- pStack->SetStartError(p->GivStart());
- pStack->SetError(TX_ELSEWITHOUTIF, p->GivEnd());
- return NULL;
-
- case ID_CASE:
- pStack->SetStartError(p->GivStart());
- pStack->SetError(TX_OUTCASE, p->GivEnd());
- return NULL;
- }
-
- pStack->SetStartError(p->GivStart());
-
- // should not be a reserved word DefineNum
- if (p->GivType() == TokenTypDef)
- {
- pStack->SetError(TX_RESERVED, p);
- return NULL;
- }
-
- // this might be an instance of class definnition
- CBotToken* ppp = p;
- if (IsOfType(ppp, TokenTypVar))
- {
- if (CBotClass::Find(p) != NULL)
- {
- // yes, compiles the declaration of the instance
- return CBotClassInst::Compile(p, pStack);
- }
- }
-
- // this can be an arythmetic instruction
- CBotInstr* inst = CBotExpression::Compile(p, pStack);
- if (IsOfType(p, ID_SEP))
- {
- return inst;
- }
- pStack->SetError(TX_ENDOF, p->GivStart());
- delete inst;
- return NULL;
-}
-
-bool CBotInstr::Execute(CBotStack* &pj)
-{
- CBotString ClassManquante = name;
- ASM_TRAP(); // should never go through this routine
- // but use the routines of the subclasses
- return false;
-}
-
-bool CBotInstr::Execute(CBotStack* &pj, CBotVar* pVar)
-{
- if (!Execute(pj)) return false;
- pVar->SetVal(pj->GivVar());
- return true;
-}
-
-void CBotInstr::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotString ClassManquante = name;
- ASM_TRAP(); // should never go through this routine
- // but use the routines of the subclasses
-}
-
-
-bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- ASM_TRAP(); // dad do not know, see the girls
- return false;
-}
-
-bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend)
-{
- ASM_TRAP(); // dad do not know, see the girls
- return false;
-}
-
-void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain)
-{
- ASM_TRAP(); // dad do not know, see the girls
-}
-
-// this routine is defined only for the subclass CBotCase
-// this allows to make the call on all instructions CompCase
-// to see if it's a case to the desired value.
-
-bool CBotInstr::CompCase(CBotStack* &pj, int val)
-{
- return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compiles a statement block " { i ; i ; } "
-
-// this class have no constructor because there is never an instance of this
-// class (TODO what about default constructor?)
-// the object returned by Compile is usually of type CBotListInstr
-
-
-CBotInstr* CBotBlock::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal)
-{
- pStack->SetStartError(p->GivStart());
-
- if (IsOfType(p, ID_OPBLK))
- {
- CBotInstr* inst = CBotListInstr::Compile(p, pStack, bLocal);
-
- if (IsOfType(p, ID_CLBLK))
- {
- return inst;
- }
-
- pStack->SetError(TX_CLOSEBLK, p->GivStart()); // missing parenthesis
- delete inst;
- return NULL;
- }
-
- pStack->SetError(TX_OPENBLK, p->GivStart());
- return NULL;
-}
-
-CBotInstr* CBotBlock::CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal)
-{
- // is this a new block
- if (p->GivType() == ID_OPBLK) return CBotBlock::Compile(p, pStack);
-
- // otherwise, look for a single statement instead
-
- // to handle the case with local definition instruction (*)
- CBotCStack* pStk = pStack->TokenStack(p, bLocal);
-
- return pStack->Return( CBotInstr::Compile(p, pStk), // a single instruction
- pStk);
-}
-
-// (*) is the case in the following statement
-// if (1 == 1) int x = 0;
-// where the variable x is known only in the block following the if
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compiles a list of instructions separated by semicolons
-
-CBotListInstr::CBotListInstr()
-{
- m_Instr = NULL;
- name = "CBotListInstr";
-}
-
-CBotListInstr::~CBotListInstr()
-{
- delete m_Instr;
-}
-
-CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal)
-{
- CBotCStack* pStk = pStack->TokenStack(p, bLocal); // variables are local
-
- CBotListInstr* inst = new CBotListInstr();
-
- while (true)
- {
- if (p == NULL) break;
-
- if (IsOfType(p, ID_SEP)) continue; // empty statement ignored
- if (p->GivType() == ID_CLBLK) break;
-
- if (IsOfType(p, 0))
- {
- pStack->SetError(TX_CLOSEBLK, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk); // compiles next
-
- if (!pStk->IsOk())
- {
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- if (inst->m_Instr == NULL) inst->m_Instr = i;
- else inst->m_Instr->AddNext(i); // added a result
- }
- return pStack->Return(inst, pStk);
-}
-
-// executes a set of instructions
-
-bool CBotListInstr::Execute(CBotStack* &pj)
-{
-
- CBotStack* pile = pj->AddStack(this, true); //needed for SetState()
- if (pile->StackOver() ) return pj->Return( pile);
-
-
- CBotInstr* p = m_Instr; // the first expression
-
- int state = pile->GivState();
- while (state-->0) p = p->GivNext(); // returns to the interrupted operation
-
- if (p != NULL) while (true)
- {
- if (!p->Execute(pile)) return false;
- p = p->GivNext();
- if (p == NULL) break;
- if (!pile->IncState()) ;//return false; // ready for next
- }
-
- return pj->Return(pile);
-}
-
-void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (!bMain) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- CBotInstr* p = m_Instr; // the first expression
-
- int state = pile->GivState();
- while ( p != NULL && state-- > 0)
- {
- p->RestoreState(pile, false);
- p = p->GivNext(); // returns to the interrupted operation
- }
-
- if (p != NULL) p->RestoreState(pile, true);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compilation of an element to the left of an assignment
-
-CBotLeftExprVar::CBotLeftExprVar()
-{
- name = "CBotLeftExprVar";
- m_typevar = -1;
- m_nIdent = 0;
-}
-
-CBotLeftExprVar::~CBotLeftExprVar()
-{
-}
-
-CBotInstr* CBotLeftExprVar::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- // verifies that the token is a variable name
- if (p->GivType() != TokenTypVar)
- {
- pStack->SetError( TX_NOVAR, p->GivStart());
- return NULL;
- }
-
- CBotLeftExprVar* inst = new CBotLeftExprVar();
- inst->SetToken(p);
- p = p->GivNext();
-
- return inst;
-}
-
-// creates a variable and assigns the result to the stack
-bool CBotLeftExprVar::Execute(CBotStack* &pj)
-{
- CBotVar* var1;
- CBotVar* var2;
-
- var1 = CBotVar::Create(m_token.GivString(), m_typevar);
- var1->SetUniqNum(m_nIdent); // with the unique identifier
- pj->AddVar(var1); // place it on the stack
-
- var2 = pj->GivVar(); // result on the stack
- if (var2) var1->SetVal(var2); // do the assignment
-
- return true;
-}
-
-void CBotLeftExprVar::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotVar* var1;
-
- var1 = pj->FindVar(m_token.GivString());
- if (var1 == NULL) ASM_TRAP();
-
- var1->SetUniqNum(m_nIdent); // with the unique identifier
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// defining an array of any type
-// int a[12];
-// point x[];
-
-CBotInstArray::CBotInstArray()
-{
- m_var = NULL;
- m_listass = NULL;
- name = "CBotInstArray";
-}
-
-CBotInstArray::~CBotInstArray()
-{
- delete m_var;
- delete m_listass;
-}
-
-
-CBotInstr* CBotInstArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type)
-{
- CBotCStack* pStk = pStack->TokenStack(p);
-
- CBotInstArray* inst = new CBotInstArray();
-
- CBotToken* vartoken = p;
- inst->SetToken(vartoken);
-
- // determinse the expression is valid for the item on the left side
- if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
- {
- if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable?
- {
- pStk->SetError(TX_REDEFVAR, vartoken);
- goto error;
- }
-
- CBotInstr* i;
- while (IsOfType(p, ID_OPBRK))
- {
- if (p->GivType() != ID_CLBRK)
- i = CBotExpression::Compile(p, pStk); // expression for the value
- else
- i = new CBotEmpty(); // if no special formula
-
- inst->AddNext3b(i); // construct a list
- type = CBotTypResult(CBotTypArrayPointer, type);
-
- if (!pStk->IsOk() || !IsOfType(p, ID_CLBRK ))
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- }
-
- CBotVar* var = CBotVar::Create(vartoken, type); // create an instance
- inst->m_typevar = type;
-
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- pStack->AddVar(var); // place it on the stack
-
- if (IsOfType(p, ID_ASS)) // with an assignment
- {
- inst->m_listass = CBotListArray::Compile(p, pStk, type.GivTypElem());
- }
-
- if (pStk->IsOk()) return pStack->Return(inst, pStk);
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-
-// executes the definition of an array
-
-bool CBotInstArray::Execute(CBotStack* &pj)
-{
- CBotStack* pile1 = pj->AddStack(this);
-
- CBotStack* pile = pile1;
-
- if (pile1->GivState() == 0)
- {
- // seek the maximum dimension of the table
- CBotInstr* p = GivNext3b(); // the different formulas
- int nb = 0;
-
- while (p != NULL)
- {
- pile = pile->AddStack(); // little room to work
- nb++;
- if (pile->GivState() == 0)
- {
- if (!p->Execute(pile)) return false; // size calculation //interrupted?
- pile->IncState();
- }
- p = p->GivNext3b();
- }
-
- p = GivNext3b();
- pile = pile1; // returns to the stack
- int n = 0;
- int max[100];
-
- while (p != NULL)
- {
- pile = pile->AddStack();
- CBotVar* v = pile->GivVar(); // result
- max[n] = v->GivValInt(); // value
- if (max[n]>MAXARRAYSIZE)
- {
- pile->SetError(TX_OUTARRAY, &m_token);
- return pj->Return (pile);
- }
- n++;
- p = p->GivNext3b();
- }
- while (n<100) max[n++] = 0;
-
- m_typevar.SetArray(max); // store the limitations
-
- // crée simplement un pointeur null
- CBotVar* var = CBotVar::Create(m_var->GivToken(), m_typevar);
- var->SetPointer(NULL);
- var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent);
- pj->AddVar(var);
-
-#if STACKMEM
- pile1->AddStack()->Delete();
-#else
- delete pile1->AddStack(); // need more indices
-#endif
- pile1->IncState();
- }
-
- if (pile1->GivState() == 1)
- {
- if (m_listass != NULL) // there is the assignment for this table
- {
- CBotVar* pVar = pj->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent);
-
- if (!m_listass->Execute(pile1, pVar)) return false;
- }
- pile1->IncState();
- }
-
- if (pile1->IfStep()) return false;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile1 )) return false;
-
- return pj->Return(pile1);
-}
-
-void CBotInstArray::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotStack* pile1 = pj;
-
- CBotVar* var = pj->FindVar(m_var->GivToken()->GivString());
- if (var != NULL) var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent);
-
- if (bMain)
- {
- pile1 = pj->RestoreStack(this);
- CBotStack* pile = pile1;
- if (pile == NULL) return;
-
- if (pile1->GivState() == 0)
- {
- // seek the maximum dimension of the table
- CBotInstr* p = GivNext3b();
-
- while (p != NULL)
- {
- pile = pile->RestoreStack();
- if (pile == NULL) return;
- if (pile->GivState() == 0)
- {
- p->RestoreState(pile, bMain);
- return;
- }
- p = p->GivNext3b();
- }
- }
- if (pile1->GivState() == 1 && m_listass != NULL)
- {
- m_listass->RestoreState(pile1, bMain);
- }
-
- }
-
- if (m_next2b ) m_next2b->RestoreState( pile1, bMain);
-}
-
-// special case for empty indexes
-bool CBotEmpty :: Execute(CBotStack* &pj)
-{
- CBotVar* pVar = CBotVar::Create("", CBotTypInt);
- pVar->SetValInt(-1);
- pj->SetVar(pVar);
- return true;
-}
-
-void CBotEmpty :: RestoreState(CBotStack* &pj, bool bMain)
-{
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// defining a list table initialization
-// int [ ] a [ ] = (( 1, 2, 3 ) , ( 3, 2, 1 )) ;
-
-
-CBotListArray::CBotListArray()
-{
- m_expr = NULL;
- name = "CBotListArray";
-}
-
-CBotListArray::~CBotListArray()
-{
- delete m_expr;
-}
-
-
-CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type)
-{
- CBotCStack* pStk = pStack->TokenStack(p);
-
- CBotToken* pp = p;
-
- if (IsOfType( p, ID_NULL ))
- {
- CBotInstr* inst = new CBotExprNull ();
- inst->SetToken(pp);
- return pStack->Return(inst, pStk); // ok with empty element
- }
-
- CBotListArray* inst = new CBotListArray();
-
- if (IsOfType( p, ID_OPENPAR ))
- {
- // each element takes the one after the other
- if (type.Eq( CBotTypArrayPointer ))
- {
- type = type.GivTypElem();
-
- pStk->SetStartError(p->GivStart());
- if (NULL == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) ))
- {
- goto error;
- }
-
- while (IsOfType( p, ID_COMMA )) // other elements?
- {
- pStk->SetStartError(p->GivStart());
-
- CBotInstr* i = CBotListArray::Compile(p, pStk, type);
- if (NULL == i)
- {
- goto error;
- }
-
- inst->m_expr->AddNext3(i);
- }
- }
- else
- {
- pStk->SetStartError(p->GivStart());
- if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
- {
- goto error;
- }
- CBotVar* pv = pStk->GivVar(); // result of the expression
-
- if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
-
- while (IsOfType( p, ID_COMMA )) // other elements?
- {
- pStk->SetStartError(p->GivStart());
-
- CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ;
- if (NULL == i)
- {
- goto error;
- }
-
- CBotVar* pv = pStk->GivVar(); // result of the expression
-
- if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- inst->m_expr->AddNext3(i);
- }
- }
-
- if (!IsOfType(p, ID_CLOSEPAR) )
- {
- pStk->SetError(TX_CLOSEPAR, p->GivStart());
- goto error;
- }
-
- return pStack->Return(inst, pStk);
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-
-// executes the definition of an array
-
-bool CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar)
-{
- CBotStack* pile1 = pj->AddStack();
- CBotVar* pVar2;
-
- CBotInstr* p = m_expr;
-
- int n = 0;
-
- for (; p != NULL ; n++, p = p->GivNext3())
- {
- if (pile1->GivState() > n) continue;
-
- pVar2 = pVar->GivItem(n, true);
-
- if (!p->Execute(pile1, pVar2)) return false; // evaluate expression
-
- pile1->IncState();
- }
-
- return pj->Return(pile1);
-}
-
-void CBotListArray::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (bMain)
- {
- CBotStack* pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- CBotInstr* p = m_expr;
-
- int state = pile->GivState();
-
- while(state-- > 0) p = p->GivNext3() ;
-
- p->RestoreState(pile, bMain); // size calculation //interrupted!
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// definition of an integer variable
-// int a, b = 12;
-
-CBotInt::CBotInt()
-{
- m_next = NULL; // for multiple definitions
- m_var =
- m_expr = NULL;
- name = "CBotInt";
-}
-
-CBotInt::~CBotInt()
-{
- delete m_var;
- delete m_expr;
-}
-
-CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first)
-{
- if (IsOfType(p, ID_OPBRK))
- {
- if (!IsOfType(p, ID_CLBRK))
- {
- pStack->SetError(TX_CLBRK, p->GivStart());
- return NULL;
- }
-
- CBotInstr* inst = CompileArray(p, pStack, CBotTypResult(CBotTypArrayPointer, type), false);
- if (inst != NULL || !pStack->IsOk()) return inst;
- }
-
- // compiles an array declaration
- if (first) return NULL ;
-
- CBotInstr* inst = CBotInstArray::Compile(p, pStack, type);
- if (inst == NULL) return NULL;
-
- if (IsOfType(p, ID_COMMA)) // several definitions
- {
- if (NULL != ( inst->m_next2b = CBotInstArray::CompileArray(p, pStack, type, false))) // compiles next one
- {
- return inst;
- }
- delete inst;
- return NULL;
- }
-
- if (IsOfType(p, ID_SEP)) // end of instruction
- {
- return inst;
- }
-
- delete inst;
- pStack->SetError(TX_ENDOF, p->GivStart());
- return NULL;
-}
-
-CBotInstr* CBotInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
-{
- CBotToken* pp = cont ? NULL : p; // no repetition of the token "int"
-
- if (!cont && !IsOfType(p, ID_INT)) return NULL;
-
- CBotInt* inst = (CBotInt*)CompileArray(p, pStack, CBotTypInt);
- if (inst != NULL || !pStack->IsOk()) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotInt();
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- inst->SetToken(vartoken);
-
- // determines the expression is valid for the item on the left side
- if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypInt;
- if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable
- {
- pStk->SetError(TX_REDEFVAR, vartoken);
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK))
- {
- delete inst; // type is not CBotInt
- p = vartoken; // returns the variable name
-
- // compiles an array declaration
-
- CBotInstr* inst2 = CBotInstArray::Compile(p, pStk, CBotTypInt);
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
-
- if (IsOfType(p, ID_COMMA)) // several definition chained
- {
- if (NULL != ( inst2->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile the next one
- {
- return pStack->Return(inst2, pStk);
- }
- }
- inst = (CBotInt*)inst2;
- goto suite; // no assignment, variable already created
- }
-
- if (IsOfType(p, ID_ASS)) // with an assignment?
- {
- if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
- {
- goto error;
- }
- if (pStk->GivType() >= CBotTypBoolean) // compatible type ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- }
-
- {
- CBotVar* var = CBotVar::Create(vartoken, CBotTypInt);// create the variable (evaluated after the assignment)
- var->SetInit(inst->m_expr != NULL); // if initialized with assignment
- var->SetUniqNum( //set it with a unique number
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- pStack->AddVar(var); // place it on the stack
- }
-
- if (IsOfType(p, ID_COMMA)) // chained several definitions
- {
- if (NULL != ( inst->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile next one
- {
- return pStack->Return(inst, pStk);
- }
- }
-suite:
- if (noskip || IsOfType(p, ID_SEP)) // instruction is completed
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// execute the definition of the integer variable
-
-bool CBotInt::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // essential for SetState()
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return false; // initial value // interrupted?
- m_var->Execute(pile); // creates and assign the result
-
- if (!pile->SetState(1)) return false;
- }
-
- if (pile->IfStep()) return false;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return false; // other(s) definition(s)
-
- return pj->Return(pile); // forward below
-}
-
-void CBotInt::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotStack* pile = pj;
- if (bMain)
- {
- pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain); // initial value // interrupted?
- return;
- }
- }
-
- m_var->RestoreState(pile, bMain);
-
- if (m_next2b) m_next2b->RestoreState(pile, bMain); // other(s) definition(s)
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// defining a boolean variable
-// int a, b = false;
-
-CBotBoolean::CBotBoolean()
-{
- m_var =
- m_expr = NULL;
- name = "CBotBoolean";
-}
-
-CBotBoolean::~CBotBoolean()
-{
- delete m_var;
- delete m_expr;
-}
-
-CBotInstr* CBotBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
-{
- CBotToken* pp = cont ? NULL : p;
-
- if (!cont && !IsOfType(p, ID_BOOLEAN, ID_BOOL)) return NULL;
-
- CBotBoolean* inst = (CBotBoolean*)CompileArray(p, pStack, CBotTypBoolean);
- if (inst != NULL || !pStack->IsOk()) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotBoolean();
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- inst->SetToken(vartoken);
- CBotVar* var = NULL;
-
- if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypBoolean;
- if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable
- {
- pStk->SetError(TX_REDEFVAR, vartoken);
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK))
- {
- delete inst; // type is not CBotInt
- p = vartoken; // resutns to the variable name
-
- // compiles an array declaration
-
- inst = (CBotBoolean*)CBotInstArray::Compile(p, pStk, CBotTypBoolean);
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- goto suite; // no assignment, variable already created
- }
-
- if (IsOfType(p, ID_ASS))
- {
- if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
- {
- goto error;
- }
- if (!pStk->GivTypResult().Eq(CBotTypBoolean))
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- }
-
- var = CBotVar::Create(vartoken, CBotTypBoolean);// create the variable (evaluated after the assignment)
- var->SetInit(inst->m_expr != NULL);
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- pStack->AddVar(var);
-suite:
- if (IsOfType(p, ID_COMMA))
- {
- if (NULL != ( inst->m_next2b = CBotBoolean::Compile(p, pStk, true, noskip)))
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (noskip || IsOfType(p, ID_SEP))
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// executes a boolean variable definition
-
-bool CBotBoolean::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);//essential for SetState()
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return false;
- m_var->Execute(pile);
-
- if (!pile->SetState(1)) return false;
- }
-
- if (pile->IfStep()) return false;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return false;
-
- return pj->Return(pile);
-}
-
-void CBotBoolean::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotStack* pile = pj;
- if (bMain)
- {
- pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain); // initial value interrupted?
- return;
- }
- }
-
- m_var->RestoreState(pile, bMain);
-
- if (m_next2b)
- m_next2b->RestoreState(pile, bMain); // other(s) definition(s)
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// definition of a real/float variable
-// int a, b = 12.4;
-
-CBotFloat::CBotFloat()
-{
- m_var =
- m_expr = NULL;
- name = "CBotFloat";
-}
-
-CBotFloat::~CBotFloat()
-{
- delete m_var;
- delete m_expr;
-}
-
-CBotInstr* CBotFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
-{
- CBotToken* pp = cont ? NULL : p;
-
- if (!cont && !IsOfType(p, ID_FLOAT)) return NULL;
-
- CBotFloat* inst = (CBotFloat*)CompileArray(p, pStack, CBotTypFloat);
- if (inst != NULL || !pStack->IsOk()) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotFloat();
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- CBotVar* var = NULL;
- inst->SetToken(vartoken);
-
- if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypFloat;
- if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable
- {
- pStk->SetStartError(vartoken->GivStart());
- pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK))
- {
- delete inst;
- p = vartoken;
- inst = (CBotFloat*)CBotInstArray::Compile(p, pStk, CBotTypFloat);
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- goto suite; // no assignment, variable already created
- }
-
- if (IsOfType(p, ID_ASS))
- {
- if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
- {
- goto error;
- }
- if (pStk->GivType() >= CBotTypBoolean)
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- }
-
- var = CBotVar::Create(vartoken, CBotTypFloat);
- var->SetInit(inst->m_expr != NULL);
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- pStack->AddVar(var);
-suite:
- if (IsOfType(p, ID_COMMA))
- {
- if (NULL != ( inst->m_next2b = CBotFloat::Compile(p, pStk, true, noskip)))
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (noskip || IsOfType(p, ID_SEP))
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// executes the definition of a real variable
-
-bool CBotFloat::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return false;
- m_var->Execute(pile);
-
- if (!pile->SetState(1)) return false;
- }
-
- if (pile->IfStep()) return false;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return false;
-
- return pj->Return(pile);
-}
-
-void CBotFloat::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotStack* pile = pj;
- if (bMain)
- {
- pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain);
- return;
- }
- }
-
- m_var->RestoreState(pile, bMain);
-
- if (m_next2b)
- m_next2b->RestoreState(pile, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// define a string variable
-// int a, b = "salut";
-
-CBotIString::CBotIString()
-{
- m_var =
- m_expr = NULL;
- name = "CBotIString";
-}
-
-CBotIString::~CBotIString()
-{
- delete m_var;
- delete m_expr;
-}
-
-CBotInstr* CBotIString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
-{
- CBotToken* pp = cont ? NULL : p;
-
- if (!cont && !IsOfType(p, ID_STRING)) return NULL;
-
- CBotIString* inst = (CBotIString*)CompileArray(p, pStack, CBotTypString);
- if (inst != NULL || !pStack->IsOk()) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotIString();
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- inst->SetToken(vartoken);
-
- if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypString;
- if (pStk->CheckVarLocal(vartoken))
- {
- pStk->SetStartError(vartoken->GivStart());
- pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
- goto error;
- }
-
- if (IsOfType(p, ID_ASS))
- {
- if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
- {
- goto error;
- }
-/* if (!pStk->GivTypResult().Eq(CBotTypString)) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }*/
- }
-
- CBotVar* var = CBotVar::Create(vartoken, CBotTypString);
- var->SetInit(inst->m_expr != NULL);
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- pStack->AddVar(var);
-
- if (IsOfType(p, ID_COMMA))
- {
- if (NULL != ( inst->m_next2b = CBotIString::Compile(p, pStk, true, noskip)))
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (noskip || IsOfType(p, ID_SEP))
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// executes the definition of the string variable
-
-bool CBotIString::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return false;
- m_var->Execute(pile);
-
- if (!pile->SetState(1)) return false;
- }
-
- if (pile->IfStep()) return false;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return false;
-
- return pj->Return(pile);
-}
-
-void CBotIString::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotStack* pile = pj;
-
- if (bMain)
- {
- pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain);
- return;
- }
- }
-
- m_var->RestoreState(pile, bMain);
-
- if (m_next2b)
- m_next2b->RestoreState(pile, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compiles a statement such as " x = 123 " ou " z * 5 + 4 "
-// with or without assignment
-
-CBotExpression::CBotExpression()
-{
- m_leftop = NULL;
- m_rightop = NULL;
- name = "CBotExpression";
-}
-
-CBotExpression::~CBotExpression()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
-
- CBotExpression* inst = new CBotExpression();
-
- inst->m_leftop = CBotLeftExpr::Compile(p, pStack);
-
- inst->SetToken(p);
- int OpType = p->GivType();
-
- if ( pStack->IsOk() &&
- IsOfTypeList(p, ID_ASS, ID_ASSADD, ID_ASSSUB, ID_ASSMUL, ID_ASSDIV, ID_ASSMODULO,
- ID_ASSAND, ID_ASSXOR, ID_ASSOR,
- ID_ASSSL , ID_ASSSR, ID_ASSASR, 0 ))
- {
- if (inst->m_leftop == NULL)
- {
- pStack->SetError(TX_BADLEFT, p->GivEnd());
- delete inst;
- return NULL;
- }
-
- inst->m_rightop = CBotExpression::Compile(p, pStack);
- if (inst->m_rightop == NULL)
- {
- delete inst;
- return NULL;
- }
-
- CBotTypResult type1 = pStack->GivTypResult();
-
- // get the variable assigned to mark
- CBotVar* var = NULL;
- inst->m_leftop->ExecuteVar(var, pStack);
- if (var == NULL)
- {
- delete inst;
- return NULL;
- }
-
- if (OpType != ID_ASS && var->GivInit() != IS_DEF)
- {
- pStack->SetError(TX_NOTINIT, pp);
- delete inst;
- return NULL;
- }
-
- CBotTypResult type2 = var->GivTypResult();
-
- // what types are acceptable?
- switch (OpType)
- {
- case ID_ASS:
- // if (type2 == CBotTypClass) type2 = -1;
- if ((type1.Eq(CBotTypPointer) && type2.Eq(CBotTypPointer)) ||
- (type1.Eq(CBotTypClass) && type2.Eq(CBotTypClass) ) )
- {
-/* CBotClass* c1 = type1.GivClass();
- CBotClass* c2 = type2.GivClass();
- if (!c1->IsChildOf(c2)) type2.SetType(-1);
-//- if (!type1.Eq(CBotTypClass)) var->SetPointer(pStack->GivVar()->GivPointer());*/
- var->SetInit(2);
- }
- else
- var->SetInit(true);
-
- break;
- case ID_ASSADD:
- if (type2.Eq(CBotTypBoolean) ||
- type2.Eq(CBotTypPointer) ) type2 = -1; // numbers and strings
- break;
- case ID_ASSSUB:
- case ID_ASSMUL:
- case ID_ASSDIV:
- case ID_ASSMODULO:
- if (type2.GivType() >= CBotTypBoolean) type2 = -1; // numbers only
- break;
- }
-
- if (!TypeCompatible(type1, type2, OpType))
- {
- pStack->SetError(TX_BADTYPE, &inst->m_token);
- delete inst;
- return NULL;
- }
-
- return inst; // compatible type?
- }
-
- delete inst;
- int start, end, error = pStack->GivError(start, end);
-
- p = pp; // returns to the top
- pStack->SetError(0,0); // forget the error
-
- CBotInstr* i = CBotTwoOpExpr::Compile(p, pStack); // tries without assignment
- if (i != NULL && error == TX_PRIVATE && p->GivType() == ID_ASS)
- pStack->ResetError(error, start, end);
- return i;
-}
-
-// executes an expression with assignment
-
-bool CBotExpression::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- CBotToken* pToken = m_leftop->GivToken();
- CBotVar* pVar = NULL;
-
- CBotStack* pile1 = pile;
-
- bool IsInit = true;
- CBotVar* result = NULL;
-
- // must be done before any indexes (stack can be changed)
- if (!m_leftop->ExecuteVar(pVar, pile, NULL, false)) return false; // variable before accessing the value on the right
-
- if ( pile1->GivState()==0)
- {
- pile1->SetCopyVar(pVar); // keeps the copy on the stack (if interrupted)
- pile1->IncState();
- }
-
- CBotStack* pile2 = pile->AddStack();
-
- if ( pile2->GivState()==0)
- {
- if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted?
- pile2->IncState();
- }
-
- if (pile1->GivState() == 1)
- {
- if (m_token.GivType() != ID_ASS)
- {
- pVar = pile1->GivVar(); // recovers if interrupted
- IsInit = pVar->GivInit();
- if (IsInit == IS_NAN)
- {
- pile2->SetError(TX_OPNAN, m_leftop->GivToken());
- return pj->Return(pile2);
- }
- result = CBotVar::Create("", pVar->GivTypResult(2));
- }
-
- switch (m_token.GivType())
- {
- case ID_ASS:
- break;
- case ID_ASSADD:
- result->Add(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSSUB:
- result->Sub(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSMUL:
- result->Mul(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSDIV:
- if (IsInit &&
- result->Div(pile1->GivVar(), pile2->GivVar()))
- pile2->SetError(TX_DIVZERO, &m_token);
- pile2->SetVar(result);
- break;
- case ID_ASSMODULO:
- if (IsInit &&
- result->Modulo(pile1->GivVar(), pile2->GivVar()))
- pile2->SetError(TX_DIVZERO, &m_token);
- pile2->SetVar(result);
- break;
- case ID_ASSAND:
- result->And(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSXOR:
- result->XOr(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSOR:
- result->Or(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSSL:
- result->SL(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSSR:
- result->SR(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- case ID_ASSASR:
- result->ASR(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result);
- break;
- default:
- ASM_TRAP();
- }
- if (!IsInit)
- pile2->SetError(TX_NOTINIT, m_leftop->GivToken());
-
- pile1->IncState();
- }
-
- if (!m_leftop->Execute( pile2, pile1 ))
- return false;
-
- return pj->Return(pile2);
-}
-
-
-void CBotExpression::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (bMain)
- {
- CBotToken* pToken = m_leftop->GivToken();
- CBotVar* pVar = NULL;
-
- CBotStack* pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- CBotStack* pile1 = pile;
-
- if ( pile1->GivState()==0)
- {
- m_leftop->RestoreStateVar(pile, true);
- return;
- }
-
- m_leftop->RestoreStateVar(pile, false);
-
- CBotStack* pile2 = pile->RestoreStack();
- if (pile2 == NULL) return;
-
- if ( pile2->GivState()==0)
- {
- if (m_rightop) m_rightop->RestoreState(pile2, bMain);
- return;
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile a statement such as "(condition)"
-// the condition must be Boolean
-
-// this class has no constructor, because there is never an instance of this class
-// the object returned by Compile is usually type CBotExpression
-
-
-CBotInstr* CBotCondition::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- pStack->SetStartError(p->GivStart());
- if (IsOfType(p, ID_OPENPAR))
- {
- CBotInstr* inst = CBotBoolExpr::Compile(p, pStack);
- if (NULL != inst)
- {
- if (IsOfType(p, ID_CLOSEPAR))
- {
- return inst;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart()); // missing parenthesis
- }
- delete inst;
- }
-
- pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis
-
- return NULL;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile a statement such as "(condition)"
-// the condition must be Boolean
-//
-// this class has no constructor, because there is never an instance of this
-// class
-// the object returned by Compile is usually type CBotExpression
-//
-
-CBotInstr* CBotBoolExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- pStack->SetStartError(p->GivStart());
-
- CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStack);
-
- if (NULL != inst)
- {
- if (pStack->GivTypResult().Eq(CBotTypBoolean))
- {
- return inst;
- }
- pStack->SetError(TX_NOTBOOL, p->GivStart()); // is not a boolean
- }
-
- delete inst;
- return NULL;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile either:
-// instruction in parentheses (...)
-// a unary expression (negative, not)
-// variable name
-// variables pre and post-incremented or decremented
-// a given number DefineNum
-// a constant
-// procedure call
-// new statement
-//
-// this class has no constructor, because there is never an instance of this class
-// the object returned by Compile is the class corresponding to the instruction
-
-
-CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(p->GivStart());
-
- // is it an expression in parentheses?
- if (IsOfType(p, ID_OPENPAR))
- {
- CBotInstr* inst = CBotExpression::Compile(p, pStk);
-
- if (NULL != inst)
- {
- if (IsOfType(p, ID_CLOSEPAR))
- {
- return pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_CLOSEPAR, p->GivStart());
- }
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- // is this a unary operation?
- CBotInstr* inst = CBotExprUnaire::Compile(p, pStk);
- if (inst != NULL || !pStk->IsOk())
- return pStack->Return(inst, pStk);
-
- // is it a variable name?
- if (p->GivType() == TokenTypVar)
- {
- // this may be a method call without the "this." before
- inst = CBotExprVar::CompileMethode(p, pStk);
- if (inst != NULL) return pStack->Return(inst, pStk);
-
-
- // is it a procedure call?
- inst = CBotInstrCall::Compile(p, pStk);
- if (inst != NULL || !pStk->IsOk())
- return pStack->Return(inst, pStk);
-
-
- CBotToken* pvar = p;
- // no, it an "ordinaty" variable
- inst = CBotExprVar::Compile(p, pStk);
-
- CBotToken* pp = p;
- // post incremented or decremented?
- if (IsOfType(p, ID_INC, ID_DEC))
- {
- if (pStk->GivType() >= CBotTypBoolean)
- {
- pStk->SetError(TX_BADTYPE, pp);
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- // recompile the variable for read-only
- delete inst;
- p = pvar;
- inst = CBotExprVar::Compile(p, pStk, PR_READ);
- p = p->GivNext();
-
- CBotPostIncExpr* i = new CBotPostIncExpr();
- i->SetToken(pp);
- i->m_Instr = inst; // associated statement
- return pStack->Return(i, pStk);
- }
- return pStack->Return(inst, pStk);
- }
-
- // pre increpemted or pre decremented?
- CBotToken* pp = p;
- if (IsOfType(p, ID_INC, ID_DEC))
- {
- CBotPreIncExpr* i = new CBotPreIncExpr();
- i->SetToken(pp);
-
- if (p->GivType() == TokenTypVar)
- {
- if (NULL != (i->m_Instr = CBotExprVar::Compile(p, pStk, PR_READ)))
- {
- if (pStk->GivType() >= CBotTypBoolean)
- {
- pStk->SetError(TX_BADTYPE, pp);
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- return pStack->Return(i, pStk);
- }
- delete i;
- return pStack->Return(NULL, pStk);
- }
- }
-
- // is it a number or DefineNum?
- if (p->GivType() == TokenTypNum ||
- p->GivType() == TokenTypDef )
- {
- CBotInstr* inst = CBotExprNum::Compile(p, pStk);
- return pStack->Return(inst, pStk);
- }
-
- // is this a chaine?
- if (p->GivType() == TokenTypString)
- {
- CBotInstr* inst = CBotExprAlpha::Compile(p, pStk);
- return pStack->Return(inst, pStk);
- }
-
- // is a "true" or "false"
- if (p->GivType() == ID_TRUE ||
- p->GivType() == ID_FALSE )
- {
- CBotInstr* inst = CBotExprBool::Compile(p, pStk);
- return pStack->Return(inst, pStk);
- }
-
- // is an object to be created with new
- if (p->GivType() == ID_NEW)
- {
- CBotInstr* inst = CBotNew::Compile(p, pStk);
- return pStack->Return(inst, pStk);
- }
-
- // is a null pointer
- if (IsOfType(p, ID_NULL))
- {
- CBotInstr* inst = new CBotExprNull ();
- inst->SetToken(pp);
- CBotVar* var = CBotVar::Create("", CBotTypNullPointer);
- pStk->SetVar(var);
- return pStack->Return(inst, pStk);
- }
-
- // is a number nan
- if (IsOfType(p, ID_NAN))
- {
- CBotInstr* inst = new CBotExprNan ();
- inst->SetToken(pp);
- CBotVar* var = CBotVar::Create("", CBotTypInt);
- var->SetInit(IS_NAN);
- pStk->SetVar(var);
- return pStack->Return(inst, pStk);
- }
-
-
- return pStack->Return(NULL, pStk);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// Management of pre-and post increment / decrement
-// There is no routine Compiles, the object is created directly
-// Compiles in CBotParExpr ::
-
-
-CBotPostIncExpr::CBotPostIncExpr()
-{
- m_Instr = NULL;
- name = "CBotPostIncExpr";
-}
-
-CBotPostIncExpr::~CBotPostIncExpr()
-{
- delete m_Instr;
-}
-
-CBotPreIncExpr::CBotPreIncExpr()
-{
- m_Instr = NULL;
- name = "CBotPreIncExpr";
-}
-
-CBotPreIncExpr::~CBotPreIncExpr()
-{
- delete m_Instr;
-}
-
-bool CBotPostIncExpr::Execute(CBotStack* &pj)
-{
- CBotStack* pile1 = pj->AddStack(this);
- CBotStack* pile2 = pile1;
-
- CBotVar* var1 = NULL;
-
- // retrieves the variable fields and indexes according
- if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false;
-
- pile1->SetState(1);
- pile1->SetCopyVar(var1); // place le résultat (avant incrémentation);
-
- CBotStack* pile3 = pile2->AddStack(this);
- if (pile3->IfStep()) return false;
-
- if (var1->GivInit() == IS_NAN)
- {
- pile1->SetError(TX_OPNAN, &m_token);
- }
-
- if (var1->GivInit() != IS_DEF)
- {
- pile1->SetError(TX_NOTINIT, &m_token);
- }
-
- if (GivTokenType() == ID_INC) var1->Inc();
- else var1->Dec();
-
- return pj->Return(pile1); // operation done, result on pile2
-}
-
-void CBotPostIncExpr::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (!bMain) return;
-
- CBotStack* pile1 = pj->RestoreStack(this);
- if (pile1 == NULL) return;
-
- ((CBotExprVar*)m_Instr)->RestoreStateVar(pile1, bMain);
-
- if (pile1 != NULL) pile1->RestoreStack(this);
-}
-
-bool CBotPreIncExpr::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if (pile->IfStep()) return false;
-
- CBotVar* var1;
-
- if (pile->GivState() == 0)
- {
- CBotStack* pile2 = pile;
- // retrieves the variable fields and indexes according
- // pile2 is modified on return
- if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false;
-
- if (var1->GivInit() == IS_NAN)
- {
- pile->SetError(TX_OPNAN, &m_token);
- return pj->Return(pile); // operation performed
- }
-
- if (var1->GivInit() != IS_DEF)
- {
- pile->SetError(TX_NOTINIT, &m_token);
- return pj->Return(pile); // operation performed
- }
-
- if (GivTokenType() == ID_INC) var1->Inc();
- else var1->Dec(); // ((CBotVarInt*)var1)->m_val
-
- pile->IncState();
- }
-
- if (!m_Instr->Execute(pile)) return false;
- return pj->Return(pile); // operation performed
-}
-
-
-void CBotPreIncExpr::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (!bMain) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- if (pile->GivState() == 0)
- {
- return;
- }
-
- m_Instr->RestoreState(pile, bMain);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile an unary expression
-// +
-// -
-// not
-// !
-// ~
-
-CBotExprUnaire::CBotExprUnaire()
-{
- m_Expr = NULL;
- name = "CBotExprUnaire";
-}
-
-CBotExprUnaire::~CBotExprUnaire()
-{
- delete m_Expr;
-}
-
-CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- int op = p->GivType();
- CBotToken* pp = p;
- if (!IsOfTypeList( p, ID_ADD, ID_SUB, ID_LOG_NOT, ID_TXT_NOT, ID_NOT, 0 )) return NULL;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- CBotExprUnaire* inst = new CBotExprUnaire();
- inst->SetToken(pp);
-
- if (NULL != (inst->m_Expr = CBotParExpr::Compile( p, pStk )))
- {
- if (op == ID_ADD && pStk->GivType() < CBotTypBoolean) // only with the number
- return pStack->Return(inst, pStk);
- if (op == ID_SUB && pStk->GivType() < CBotTypBoolean) // only with the numer
- return pStack->Return(inst, pStk);
- if (op == ID_NOT && pStk->GivType() < CBotTypFloat) // only with an integer
- return pStack->Return(inst, pStk);
- if (op == ID_LOG_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean
- return pStack->Return(inst, pStk);
- if (op == ID_TXT_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean
- return pStack->Return(inst, pStk);
-
- pStk->SetError(TX_BADTYPE, &inst->m_token);
- }
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// executes unary expression
-
-bool CBotExprUnaire::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if (pile->GivState() == 0)
- {
- if (!m_Expr->Execute(pile)) return false; // interrupted ?
- pile->IncState();
- }
-
- CBotStack* pile2 = pile->AddStack();
- if (pile2->IfStep()) return false;
-
- CBotVar* var = pile->GivVar(); // get the result on the stack
-
- switch (GivTokenType())
- {
- case ID_ADD:
- break;
- case ID_SUB:
- var->Neg(); // change the sign
- break;
- case ID_NOT:
- case ID_LOG_NOT:
- case ID_TXT_NOT:
- var->Not();
- break;
- }
- return pj->Return(pile); // forwards below
-}
-
-void CBotExprUnaire::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (!bMain) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL) return;
-
- if (pile->GivState() == 0)
- {
- m_Expr->RestoreState(pile, bMain); // interrupted here!
- return;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// index management for arrays
-// array [ expression ]
-
-
-CBotIndexExpr::CBotIndexExpr()
-{
- m_expr = NULL;
- name = "CBotIndexExpr";
-}
-
-CBotIndexExpr::~CBotIndexExpr()
-{
- delete m_expr;
-}
-
-// finds a field from the instance at compile time
-
-bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- if (pVar->GivType(1) != CBotTypArrayPointer)
- ASM_TRAP();
-
- pVar = ((CBotVarArray*)pVar)->GivItem(0, false); // at compile time makes the element [0]
- if (pVar == NULL)
- {
- pile->SetError(TX_OUTARRAY, m_token.GivEnd());
- return false;
- }
- if (m_next3 != NULL) return m_next3->ExecuteVar(pVar, pile);
- return true;
-}
-
-// attention, changes the pointer to the stack intentionally
-// place the index calculated on the additional stack
-
-
-bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend)
-{
- CBotStack* pj = pile;
-
- if (pVar->GivType(1) != CBotTypArrayPointer)
- ASM_TRAP();
-
- pile = pile->AddStack();
-
- if (pile->GivState() == 0)
- {
- if (!m_expr->Execute(pile)) return false;
- pile->IncState();
- }
- // handles array
-
- CBotVar* p = pile->GivVar(); // result on the stack
-
- if (p == NULL || p->GivType() > CBotTypDouble)
- {
- pile->SetError(TX_BADINDEX, prevToken);
- return pj->Return(pile);
- }
-
- int n = p->GivValInt(); // position in the table
-
- pVar = ((CBotVarArray*)pVar)->GivItem(n, bExtend);
- if (pVar == NULL)
- {
- pile->SetError(TX_OUTARRAY, prevToken);
- return pj->Return(pile);
- }
-
- pVar->Maj(pile->GivPUser(), true);
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile, prevToken, bStep, bExtend) ) return false;
-
- // does not release the stack
- // to avoid recalculation of the index twice where appropriate
- return true;
-}
-
-void CBotIndexExpr::RestoreStateVar(CBotStack* &pile, bool bMain)
-{
- pile = pile->RestoreStack();
- if (pile == NULL) return;
-
- if (bMain && pile->GivState() == 0)
- {
- m_expr->RestoreState(pile, true);
- return;
- }
-
- if (m_next3)
- m_next3->RestoreStateVar(pile, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// field management in an instance (dot operator)
-// toto.x
-
-
-CBotFieldExpr::CBotFieldExpr()
-{
- name = "CBotFieldExpr";
- m_nIdent = 0;
-}
-
-CBotFieldExpr::~CBotFieldExpr()
-{
-}
-
-void CBotFieldExpr::SetUniqNum(int num)
-{
- m_nIdent = num;
-}
-
-
-// find a field from the instance at compile
-
-bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- if (pVar->GivType(1) != CBotTypPointer)
- ASM_TRAP();
-
- pVar = pVar->GivItemRef(m_nIdent);
- if (pVar == NULL)
- {
- pile->SetError(TX_NOITEM, &m_token);
- return false;
- }
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile) ) return false;
-
- return true;
-}
-
-bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend)
-{
- CBotStack* pj = pile;
- pile = pile->AddStack(this); // changes in output stack
- if (pile == EOX) return true;
-
-
- if (pVar->GivType(1) != CBotTypPointer)
- ASM_TRAP();
-
- CBotVarClass* pItem = pVar->GivPointer();
- if (pItem == NULL)
- {
- pile->SetError(TX_NULLPT, prevToken);
- return pj->Return(pile);
- }
- if (pItem->GivUserPtr() == OBJECTDELETED)
- {
- pile->SetError(TX_DELETEDPT, prevToken);
- return pj->Return(pile);
- }
-
- if (bStep && pile->IfStep()) return false;
-
- pVar = pVar->GivItemRef(m_nIdent);
- if (pVar == NULL)
- {
- pile->SetError(TX_NOITEM, &m_token);
- return pj->Return(pile);
- }
-
- if (pVar->IsStatic())
- {
- // for a static variable, takes it in the class itself
- CBotClass* pClass = pItem->GivClass();
- pVar = pClass->GivItem(m_token.GivString());
- }
-
- // request the update of the element, if applicable
- pVar->Maj(pile->GivPUser(), true);
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, bExtend) ) return false;
-
- // does not release the stack
- // to maintain the state SetState () corresponding to step
-
- return true;
-}
-
-void CBotFieldExpr::RestoreStateVar(CBotStack* &pj, bool bMain)
-{
- pj = pj->RestoreStack(this);
- if (pj == NULL) return;
-
- if (m_next3 != NULL)
- m_next3->RestoreStateVar(pj, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile a left operand for an assignment
-CBotLeftExpr::CBotLeftExpr()
-{
- name = "CBotLeftExpr";
- m_nIdent = 0;
-}
-
-CBotLeftExpr::~CBotLeftExpr()
-{
-}
-
-// compiles an expression for a left-operand (left of an assignment)
-// this can be
-// toto
-// toto[ 3 ]
-// toto.x
-// toto.pos.x
-// toto[2].pos.x
-// toto[1].pos[2].x
-// toto[1][2][3]
-
-CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(p->GivStart());
-
- // is it a variable name?
- if (p->GivType() == TokenTypVar)
- {
- CBotLeftExpr* inst = new CBotLeftExpr(); // creates the object
-
- inst->SetToken(p);
-
- CBotVar* var;
-
- if (NULL != (var = pStk->FindVar(p))) // seek if known variable
- {
- inst->m_nIdent = var->GivUniqNum();
- if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
- {
- if ( var->IsPrivate(PR_READ) &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError(TX_PRIVATE, p);
- goto err;
- }
- // this is an element of the current class
- // adds the equivalent of this. before
- CBotToken pthis("this");
- inst->SetToken(&pthis);
- inst->m_nIdent = -2; // indent for this
-
- CBotFieldExpr* i = new CBotFieldExpr(); // new element
- i->SetToken(p); // keeps the name of the token
- inst->AddNext3(i); // add after
-
- var = pStk->FindVar(pthis);
- var = var->GivItem(p->GivString());
- i->SetUniqNum(var->GivUniqNum());
- }
- p = p->GivNext(); // next token
-
- while (true)
- {
- if (var->GivType() == CBotTypArrayPointer)
- {
- if (IsOfType( p, ID_OPBRK ))
- {
- CBotIndexExpr* i = new CBotIndexExpr();
- i->m_expr = CBotExpression::Compile(p, pStk);
- inst->AddNext3(i); // add to the chain
-
- var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0]
-
- if (i->m_expr == NULL)
- {
- pStk->SetError(TX_BADINDEX, p->GivStart());
- goto err;
- }
-
- if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK ))
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto err;
- }
- continue;
- }
- }
-
- if (var->GivType(1) == CBotTypPointer) // for classes
- {
- if (IsOfType(p, ID_DOT))
- {
- CBotToken* pp = p;
-
- CBotFieldExpr* i = new CBotFieldExpr(); // new element
- i->SetToken(pp); // keeps the name of the token
- inst->AddNext3(i); // adds after
-
- if (p->GivType() == TokenTypVar) // must be a name
- {
- var = var->GivItem(p->GivString()); // get item correspondent
- if (var != NULL)
- {
- if ( var->IsPrivate(PR_READ) &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError(TX_PRIVATE, pp);
- goto err;
- }
-
- i->SetUniqNum(var->GivUniqNum());
- p = p->GivNext(); // skips the name
- continue;
- }
- pStk->SetError(TX_NOITEM, p);
- }
- pStk->SetError(TX_DOT, p->GivStart());
- goto err;
- }
- }
- break;
- }
-
-
- if (pStk->IsOk()) return (CBotLeftExpr*) pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_UNDEFVAR, p);
-err:
- delete inst;
- return (CBotLeftExpr*) pStack->Return(NULL, pStk);
- }
-
- return (CBotLeftExpr*) pStack->Return(NULL, pStk);
-}
-
-// runs, is a variable and assigns the result to the stack
-bool CBotLeftExpr::Execute(CBotStack* &pj, CBotStack* array)
-{
- CBotStack* pile = pj->AddStack();
-
- CBotVar* var1 = NULL;
- CBotVar* var2 = NULL;
- // fetch a variable (not copy)
- if (!ExecuteVar(var1, array, NULL, false)) return false;
-
- if (pile->IfStep()) return false;
-
- if (var1)
- {
- var2 = pj->GivVar(); // result on the input stack
- if (var2)
- {
- CBotTypResult t1 = var1->GivTypResult();
- CBotTypResult t2 = var2->GivTypResult();
- if (t2.Eq(CBotTypPointer))
- {
- CBotClass* c1 = t1.GivClass();
- CBotClass* c2 = t2.GivClass();
- if ( !c2->IsChildOf(c1))
- {
- CBotToken* pt = &m_token;
- pile->SetError(TX_BADTYPE, pt);
- return pj->Return(pile); // operation performed
- }
- }
- var1->SetVal(var2); // do assignment
- }
- pile->SetCopyVar(var1); // replace the stack with the copy of the variable
- // (for name)
- }
-
- return pj->Return(pile); // operation performed
-}
-
-// fetch a variable during compilation
-
-bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- pVar = pile->FindVar(m_token);
- if (pVar == NULL) return false;
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile) ) return false;
-
- return true;
-}
-
-// fetch the variable at runtume
-
-bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep)
-{
- pile = pile->AddStack(this);
-
- pVar = pile->FindVar(m_nIdent);
- if (pVar == NULL)
- {
-#ifdef _DEBUG
- ASM_TRAP();
-#endif
- pile->SetError(2, &m_token);
- return false;
- }
-
- if (bStep && m_next3 == NULL && pile->IfStep()) return false;
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, true) ) return false;
-
- return true;
-}
-
-void CBotLeftExpr::RestoreStateVar(CBotStack* &pile, bool bMain)
-{
- pile = pile->RestoreStack(this);
- if (pile == NULL) return;
-
- if (m_next3 != NULL)
- m_next3->RestoreStateVar(pile, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// converts a string into integer
-// may be of the form 0xabc123
-
-long GivNumInt(const char* p)
-{
- long num = 0;
- while (*p >= '0' && *p <= '9')
- {
- num = num * 10 + *p - '0';
- p++;
- }
- if (*p == 'x' || *p == 'X')
- {
- while (*++p != 0)
- {
- if (*p >= '0' && *p <= '9')
- {
- num = num * 16 + *p - '0';
- continue;
- }
- if (*p >= 'A' && *p <= 'F')
- {
- num = num * 16 + *p - 'A' + 10;
- continue;
- }
- if (*p >= 'a' && *p <= 'f')
- {
- num = num * 16 + *p - 'a' + 10;
- continue;
- }
- break;
- }
- }
- return num;
-}
-
-// converts a string into a float number
-extern float GivNumFloat(const char* p)
-{
- double num = 0;
- double div = 10;
- bool bNeg = false;
-
- if (*p == '-')
- {
- bNeg = true;
- p++;
- }
- while (*p >= '0' && *p <= '9')
- {
- num = num * 10. + (*p - '0');
- p++;
- }
-
- if (*p == '.')
- {
- p++;
- while (*p >= '0' && *p <= '9')
- {
- num = num + (*p - '0') / div;
- div = div * 10;
- p++;
- }
- }
-
- int exp = 0;
- if (*p == 'e' || *p == 'E')
- {
- char neg = 0;
- p++;
- if (*p == '-' || *p == '+') neg = *p++;
-
- while (*p >= '0' && *p <= '9')
- {
- exp = exp * 10 + (*p - '0');
- p++;
- }
- if (neg == '-') exp = -exp;
- }
-
- while (exp > 0)
- {
- num *= 10.0;
- exp--;
- }
-
- while (exp < 0)
- {
- num /= 10.0;
- exp++;
- }
-
- if (bNeg) num = -num;
- return (float)num;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compiles a token representing a number
-CBotExprNum::CBotExprNum()
-{
- name = "CBotExprNum";
-}
-
-CBotExprNum::~CBotExprNum()
-{
-}
-
-CBotInstr* CBotExprNum::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- CBotExprNum* inst = new CBotExprNum();
-
- inst->SetToken(p);
- CBotString s = p->GivString();
-
- inst->m_numtype = CBotTypInt;
- if (p->GivType() == TokenTypDef)
- {
- inst->m_valint = p->GivIdKey();
- }
- else
- {
- if (s.Find('.') >= 0 || ( s.Find('x') < 0 && ( s.Find('e') >= 0 || s.Find('E') >= 0 ) ))
- {
- inst->m_numtype = CBotTypFloat;
- inst->m_valfloat = GivNumFloat(s);
- }
- else
- {
- inst->m_valint = GivNumInt(s);
- }
- }
-
- if (pStk->NextToken(p))
- {
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, inst->m_numtype);
- pStk->SetVar(var);
-
- return pStack->Return(inst, pStk);
- }
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// execute, returns the corresponding number
-
-bool CBotExprNum::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if (pile->IfStep()) return false;
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, m_numtype);
-
- CBotString nombre ;
- if (m_token.GivType() == TokenTypDef)
- {
- nombre = m_token.GivString();
- }
-
- switch (m_numtype)
- {
- case CBotTypShort:
- case CBotTypInt:
- var->SetValInt(m_valint, nombre);
- break;
- case CBotTypFloat:
- var->SetValFloat(m_valfloat);
- break;
- }
- pile->SetVar(var); // place on the stack
-
- return pj->Return(pile); // it's ok
-}
-
-void CBotExprNum::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (bMain) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile a token representing a string
-
-CBotExprAlpha::CBotExprAlpha()
-{
- name = "CBotExprAlpha";
-}
-
-CBotExprAlpha::~CBotExprAlpha()
-{
-}
-
-CBotInstr* CBotExprAlpha::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- CBotExprAlpha* inst = new CBotExprAlpha();
-
- inst->SetToken(p);
- p = p->GivNext();
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString);
- pStk->SetVar(var);
-
- return pStack->Return(inst, pStk);
-}
-
-// execute, returns the corresponding string
-
-bool CBotExprAlpha::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if (pile->IfStep()) return false;
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString);
-
- CBotString chaine = m_token.GivString();
- chaine = chaine.Mid(1, chaine.GivLength()-2); // removes the quotes
-
- var->SetValString(chaine); // value of the number
-
- pile->SetVar(var); // put on the stack
-
- return pj->Return(pile);
-}
-
-void CBotExprAlpha::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (bMain) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile a token representing true or false
-
-CBotExprBool::CBotExprBool()
-{
- name = "CBotExprBool";
-}
-
-CBotExprBool::~CBotExprBool()
-{
-}
-
-CBotInstr* CBotExprBool::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
- CBotExprBool* inst = NULL;
-
- if ( p->GivType() == ID_TRUE ||
- p->GivType() == ID_FALSE )
- {
- inst = new CBotExprBool();
- inst->SetToken(p); // stores the operation false or true
- p = p->GivNext();
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
- pStk->SetVar(var);
- }
-
- return pStack->Return(inst, pStk);
-}
-
-// executes, returns true or false
-
-bool CBotExprBool::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if (pile->IfStep()) return false;
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
-
- if (GivTokenType() == ID_TRUE) var->SetValInt(1);
- else var->SetValInt(0);
-
- pile->SetVar(var); // put on the stack
- return pj->Return(pile); // forwards below
-}
-
-void CBotExprBool::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (bMain) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// management of the operand "null"
-
-CBotExprNull::CBotExprNull()
-{
- name = "CBotExprNull";
-}
-
-CBotExprNull::~CBotExprNull()
-{
-}
-
-// executes, returns an empty pointer
-
-bool CBotExprNull::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if (pile->IfStep()) return false;
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypNullPointer);
-
- var->SetInit(true); // null pointer valid
- pile->SetVar(var); // place on the stack
- return pj->Return(pile); // forwards below
-}
-
-void CBotExprNull::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (bMain) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// management of the operand "nan"
-
-CBotExprNan::CBotExprNan()
-{
- name = "CBotExprNan";
-}
-
-CBotExprNan::~CBotExprNan()
-{
-}
-
-// executes, returns null pointer
-
-bool CBotExprNan::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-
- if (pile->IfStep()) return false;
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypInt);
-
- var->SetInit(IS_NAN); // nan
- pile->SetVar(var); // put on the stack
- return pj->Return(pile); // forward below
-}
-
-void CBotExprNan::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (bMain) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile a variable name
-// check that it is known on the stack
-// and it has been initialized
-
-CBotExprVar::CBotExprVar()
-{
- name = "CBotExprVar";
- m_nIdent = 0;
-}
-
-CBotExprVar::~CBotExprVar()
-{
-}
-
-CBotInstr* CBotExprVar::Compile(CBotToken* &p, CBotCStack* pStack, int privat)
-{
- CBotToken* pDebut = p;
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(p->GivStart());
-
- // is it a variable?
- if (p->GivType() == TokenTypVar)
- {
- CBotInstr* inst = new CBotExprVar(); // create the object
-
- inst->SetToken(p);
-
- CBotVar* var;
-
- if (NULL != (var = pStk->FindVar(p))) // seek if known variable
- {
- int ident = var->GivUniqNum();
- ((CBotExprVar*)inst)->m_nIdent = ident; // identifies variable by its number
-
- if (ident > 0 && ident < 9000)
- {
- if ( var->IsPrivate(privat) &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError(TX_PRIVATE, p);
- goto err;
- }
-
- // This is an element of the current class
- // ads the equivalent of this. before
- /// \TODO need to be fixed revised and fixed after adding unit
- ///tests
- CBotToken token("this");
- inst->SetToken(&token);
- ((CBotExprVar*)inst)->m_nIdent = -2; // identificator for this
-
- CBotFieldExpr* i = new CBotFieldExpr(); // new element
- i->SetToken(p); // keeps the name of the token
- i->SetUniqNum(ident);
- inst->AddNext3(i); // added after
- }
-
- p = p->GivNext(); // next token
-
- while (true)
- {
- if (var->GivType() == CBotTypArrayPointer)
- {
- if (IsOfType( p, ID_OPBRK )) // check if there is an aindex
- {
- CBotIndexExpr* i = new CBotIndexExpr();
- i->m_expr = CBotExpression::Compile(p, pStk); // compile the formula
- inst->AddNext3(i); // add to the chain
-
- var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0]
-
- if (i->m_expr == NULL)
- {
- pStk->SetError(TX_BADINDEX, p->GivStart());
- goto err;
- }
- if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK ))
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto err;
- }
- continue;
- }
- }
- if (var->GivType(1) == CBotTypPointer) // for classes
- {
- if (IsOfType(p, ID_DOT))
- {
- CBotToken* pp = p;
-
- if (p->GivType() == TokenTypVar) // must be a name
- {
- if (p->GivNext()->GivType() == ID_OPENPAR) // a method call?
- {
- CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
- if (!pStk->IsOk()) goto err;
- inst->AddNext3(i); // added after
- return pStack->Return(inst, pStk);
- }
- else
- {
- CBotFieldExpr* i = new CBotFieldExpr(); // new element
- i->SetToken(pp); // keeps the name of the token
- inst->AddNext3(i); // add after
- var = var->GivItem(p->GivString()); // get item correspondent
- if (var != NULL)
- {
- i->SetUniqNum(var->GivUniqNum());
- if ( var->IsPrivate() &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError(TX_PRIVATE, pp);
- goto err;
- }
- }
- }
-
-
- if (var != NULL)
- {
- p = p->GivNext(); // skips the name
- continue;
- }
- pStk->SetError(TX_NOITEM, p);
- goto err;
- }
- pStk->SetError(TX_DOT, p->GivStart());
- goto err;
- }
- }
-
- break;
- }
-
- pStk->SetCopyVar(var); // place the copy of the variable on the stack (for type)
- if (pStk->IsOk()) return pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_UNDEFVAR, p);
-err:
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- return pStack->Return(NULL, pStk);
-}
-
-CBotInstr* CBotExprVar::CompileMethode(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(pp->GivStart());
-
- // is it a variable ?
- if (pp->GivType() == TokenTypVar)
- {
- CBotToken pthis("this");
- CBotVar* var = pStk->FindVar(pthis);
- if (var == 0) return pStack->Return(NULL, pStk);
-
- CBotInstr* inst = new CBotExprVar();
-
- // this is an element of the current class
- // adds the equivalent of this. before
-
- inst->SetToken(&pthis);
- ((CBotExprVar*)inst)->m_nIdent = -2; // ident for this
-
- CBotToken* pp = p;
-
- if (pp->GivType() == TokenTypVar)
- {
- if (pp->GivNext()->GivType() == ID_OPENPAR) // a method call?
- {
- CBotInstr* i = CBotInstrMethode::Compile(pp, pStk, var);
- if (pStk->IsOk())
- {
- inst->AddNext3(i); // add after
- p = pp; // previous instruction
- return pStack->Return(inst, pStk);
- }
- pStk->SetError(0,0); // the error is not adressed here
- }
- }
- delete inst;
- }
- return pStack->Return(NULL, pStk);
-}
-
-
-// execute, making the value of a variable
-
-bool CBotExprVar::Execute(CBotStack* &pj)
-{
- CBotVar* pVar = NULL;
- CBotStack* pile = pj->AddStack(this);
-
- CBotStack* pile1 = pile;
-
- if (pile1->GivState() == 0)
- {
- if (!ExecuteVar(pVar, pile, NULL, true)) return false; // Get the variable fields and indexes according
-
- if (pVar) pile1->SetCopyVar(pVar); // place a copy on the stack
- else
- {
- return pj->Return(pile1);
- }
- pile1->IncState();
- }
-
- pVar = pile1->GivVar();
-
- if (pVar == NULL)
- {
- return pj->Return(pile1);
- }
-
- if (pVar->GivInit() == IS_UNDEF)
- {
- CBotToken* pt = &m_token;
- while (pt->GivNext() != NULL) pt = pt->GivNext();
- pile1->SetError(TX_NOTINIT, pt);
- return pj->Return(pile1);
- }
- return pj->Return(pile1); // operation completed
-}
-
-void CBotExprVar::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (!bMain) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if (pile == NULL) return;
-
- CBotStack* pile1 = pile;
-
- if (pile1->GivState() == 0)
- {
- RestoreStateVar(pile, bMain); // retrieves the variable fields and indexes according
- return;
- }
-}
-
-// fetch a variable at runtime
-
-bool CBotExprVar::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep)
-{
- CBotStack* pile = pj;
- pj = pj->AddStack(this);
-
- if (bStep && m_nIdent>0 && pj->IfStep()) return false;
-
- pVar = pj->FindVar(m_nIdent, true); // tries with the variable update if necessary
- if (pVar == NULL)
- {
-#ifdef _DEBUG
- ASM_TRAP();
-#endif
- pj->SetError(1, &m_token);
- return false;
- }
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pj, &m_token, bStep, false) )
- return false; // field of an instance, table, methode
-
- return pile->ReturnKeep(pj); // does not put on stack but get the result if a method was called
-}
-
-
-// fetch variable at runtime
-
-void CBotExprVar::RestoreStateVar(CBotStack* &pj, bool bMain)
-{
- pj = pj->RestoreStack(this);
- if (pj == NULL) return;
-
- if (m_next3 != NULL)
- m_next3->RestoreStateVar(pj, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// compile a list of parameters
-
-CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars)
-{
- bool first = true;
- CBotInstr* ret = NULL; // to return to the list
-
- CBotCStack* pile = pStack;
- int i = 0;
-
- if (IsOfType(p, ID_OPENPAR))
- {
- int start, end;
- if (!IsOfType(p, ID_CLOSEPAR)) while (true)
- {
- start = p->GivStart();
- pile = pile->TokenStack(); // keeps the result on the stack
-
- if (first) pStack->SetStartError(start);
- first = false;
-
- CBotInstr* param = CBotExpression::Compile(p, pile);
- end = p->GivStart();
-
- if (!pile->IsOk())
- {
- return pStack->Return(NULL, pile);
- }
-
- if (ret == NULL) ret = param;
- else ret->AddNext(param); // construct the list
-
- if (param != NULL)
- {
- if (pile->GivTypResult().Eq(99))
- {
- delete pStack->TokenStack();
- pStack->SetError(TX_VOID, p->GivStart());
- return NULL;
- }
- ppVars[i] = pile->GivVar();
- ppVars[i]->GivToken()->SetPos(start, end);
- i++;
-
- if (IsOfType(p, ID_COMMA)) continue; // skips the comma
- if (IsOfType(p, ID_CLOSEPAR)) break;
- }
-
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- delete pStack->TokenStack();
- return NULL;
- }
- }
- ppVars[i] = NULL;
- return ret;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile a method call
-
-CBotInstrMethode::CBotInstrMethode()
-{
- m_Parameters = NULL;
- m_MethodeIdent = 0;
- name = "CBotInstrMethode";
-}
-
-CBotInstrMethode::~CBotInstrMethode()
-{
- delete m_Parameters;
-}
-
-CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var)
-{
- CBotInstrMethode* inst = new CBotInstrMethode();
- inst->SetToken(p); // corresponding token
-
- if (NULL != var)
- {
- CBotToken* pp = p;
- p = p->GivNext();
-
- if (p->GivType() == ID_OPENPAR)
- {
- inst->m_NomMethod = pp->GivString();
-
- // compiles the list of parameters
- CBotVar* ppVars[1000];
- inst->m_Parameters = CompileParams(p, pStack, ppVars);
-
- if (pStack->IsOk())
- {
- CBotClass* pClass = var->GivClass(); // pointer to the class
- inst->m_ClassName = pClass->GivName(); // name of the class
- CBotTypResult r = pClass->CompileMethode(inst->m_NomMethod, var, ppVars,
- pStack, inst->m_MethodeIdent);
- delete pStack->TokenStack(); // release parameters on the stack
- inst->m_typRes = r;
-
- if (inst->m_typRes.GivType() > 20)
- {
- pStack->SetError(inst->m_typRes.GivType(), pp);
- delete inst;
- return NULL;
- }
- // put the result on the stack to have something
- if (inst->m_typRes.GivType() > 0)
- {
- CBotVar* pResult = CBotVar::Create("", inst->m_typRes);
- if (inst->m_typRes.Eq(CBotTypClass))
- {
- pResult->SetClass(inst->m_typRes.GivClass());
- }
- pStack->SetVar(pResult);
- }
- return inst;
- }
- delete inst;
- return NULL;
- }
- }
- pStack->SetError(1234, p);
- delete inst;
- return NULL;
-}
-
-// execute the method call
-
-bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend)
-{
- CBotVar* ppVars[1000];
- CBotStack* pile1 = pj->AddStack(this, true); // a place for the copy of This
-
- if (pVar->GivPointer() == NULL)
- {
- pj->SetError(TX_NULLPT, prevToken);
- }
-
- if (pile1->IfStep()) return false;
-
- CBotStack* pile2 = pile1->AddStack(); // for the next parameters
-
- if ( pile1->GivState() == 0)
- {
- CBotVar* pThis = CBotVar::Create(pVar);
- pThis->Copy(pVar);
- // this value should be taken before the evaluation parameters
- // Test.Action (Test = Other);
- // action must act on the value before test = Other!
-
- pThis->SetName("this");
- pThis->SetUniqNum(-2);
- pile1->AddVar(pThis);
- pile1->IncState();
- }
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // evaluate the parameters
- // and places the values on the stack
- // to be interrupted at any time
-
- if (p != NULL) while ( true)
- {
- if (pile2->GivState() == 0)
- {
- if (!p->Execute(pile2)) return false; // interrupted here?
- if (!pile2->SetState(1)) return false; // special mark to recognize parameters
- }
- ppVars[i++] = pile2->GivVar(); // construct the list of pointers
- pile2 = pile2->AddStack(); // space on the stack for the result
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotClass* pClass = CBotClass::Find(m_ClassName);
- CBotVar* pThis = pile1->FindVar(-2);
- CBotVar* pResult = NULL;
- if (m_typRes.GivType() > 0) pResult = CBotVar::Create("", m_typRes);
- if (m_typRes.Eq(CBotTypClass))
- {
- pResult->SetClass(m_typRes.GivClass());
- }
- CBotVar* pRes = pResult;
-
- if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
- pThis, ppVars,
- pResult, pile2, GivToken())) return false;
- if (pRes != pResult) delete pRes;
-
- pVar = NULL; // does not return value for this
- return pj->Return(pile2); // release the entire stack
-}
-
-void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain)
-{
- if (!bMain) return;
-
- CBotVar* ppVars[1000];
- CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This
- if (pile1 == NULL) return;
-
- CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming
- if (pile2 == NULL) return;
-
- CBotVar* pThis = pile1->FindVar("this");
- pThis->SetUniqNum(-2);
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // evaluate the parameters
- // and places the values on the stack
- // to be interrupted at any time
-
- if (p != NULL) while ( true)
- {
- if (pile2->GivState() == 0)
- {
- p->RestoreState(pile2, true); // interrupted here!
- return;
- }
- ppVars[i++] = pile2->GivVar(); // construct the list of pointers
- pile2 = pile2->RestoreStack();
- if (pile2 == NULL) return;
-
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotClass* pClass = CBotClass::Find(m_ClassName);
- CBotVar* pResult = NULL;
-
- CBotVar* pRes = pResult;
-
- pClass->RestoreMethode(m_MethodeIdent, m_NomMethod,
- pThis, ppVars, pile2);
-}
-
-
-bool CBotInstrMethode::Execute(CBotStack* &pj)
-{
- CBotVar* ppVars[1000];
- CBotStack* pile1 = pj->AddStack(this, true); // place for the copy of This
-
- if (pile1->IfStep()) return false;
-
- CBotStack* pile2 = pile1->AddStack(); // and for the parameters coming
-
- if ( pile1->GivState() == 0)
- {
- CBotVar* pThis = pile1->CopyVar(m_token);
- // this value should be taken before the evaluation parameters
- // Test.Action (Test = Other);
- // Action must act on the value before test = Other!
- pThis->SetName("this");
- pile1->AddVar(pThis);
- pile1->IncState();
- }
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // evaluate the parameters
- // and places the values on the stack
- // to be interrupted at any time
- if (p != NULL) while ( true)
- {
- if (pile2->GivState() == 0)
- {
- if (!p->Execute(pile2)) return false; // interrupted here?
- if (!pile2->SetState(1)) return false; // special mark to recognize parameters
- }
- ppVars[i++] = pile2->GivVar(); // construct the list of pointers
- pile2 = pile2->AddStack(); // space on the stack for the results
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotClass* pClass = CBotClass::Find(m_ClassName);
- CBotVar* pThis = pile1->FindVar("this");
- CBotVar* pResult = NULL;
- if (m_typRes.GivType()>0) pResult = CBotVar::Create("", m_typRes);
- if (m_typRes.Eq(CBotTypClass))
- {
- pResult->SetClass(m_typRes.GivClass());
- }
- CBotVar* pRes = pResult;
-
- if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
- pThis, ppVars,
- pResult, pile2, GivToken())) return false; // interupted
-
- // set the new value of this in place of the old variable
- CBotVar* old = pile1->FindVar(m_token);
- old->Copy(pThis, false);
-
- if (pRes != pResult) delete pRes;
-
- return pj->Return(pile2); // release the entire stack
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile an instruction "new"
-
-CBotNew::CBotNew()
-{
- name = "CBotNew";
- m_Parameters = NULL;
- m_nMethodeIdent = 0;
-}
-
-CBotNew::~CBotNew()
-{
-}
-
-CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
- if (!IsOfType(p, ID_NEW)) return NULL;
-
- // verifies that the token is a class name
- if (p->GivType() != TokenTypVar) return NULL;
-
- CBotClass* pClass = CBotClass::Find(p);
- if (pClass == NULL)
- {
- pStack->SetError(TX_BADNEW, p);
- return NULL;
- }
-
- CBotNew* inst = new CBotNew();
- inst->SetToken(pp);
-
- inst->m_vartoken = p;
- p = p->GivNext();
-
- // creates the object on the "job"
- // with a pointer to the object
- CBotVar* pVar = CBotVar::Create("", pClass);
-
- // do the call of the creator
- CBotCStack* pStk = pStack->TokenStack();
- {
- // check if there are parameters
- CBotVar* ppVars[1000];
- inst->m_Parameters = CompileParams(p, pStk, ppVars);
- if (!pStk->IsOk()) goto error;
-
- // constructor exist?
- CBotTypResult r = pClass->CompileMethode(pClass->GivName(), pVar, ppVars, pStk, inst->m_nMethodeIdent);
- delete pStk->TokenStack(); // release extra stack
- int typ = r.GivType();
-
- // if there is no constructor, and no parameters either, it's ok
- if (typ == TX_UNDEFCALL && inst->m_Parameters == NULL) typ = 0;
- pVar->SetInit(true); // mark the instance as init
-
- if (typ>20)
- {
- pStk->SetError(typ, inst->m_vartoken.GivEnd());
- goto error;
- }
-
- // if the constructor does not exist, but there are parameters
- if (typ<0 && inst->m_Parameters != NULL)
- {
- pStk->SetError(TX_NOCONST, &inst->m_vartoken);
- goto error;
- }
-
- // makes pointer to the object on the stack
- pStk->SetVar(pVar);
- return pStack->Return(inst, pStk);
- }
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// executes instruction "new"
-
-bool CBotNew::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); //main stack
-
- if (pile->IfStep()) return false;
-
- CBotStack* pile1 = pj->AddStack2(); //secondary stack
-
- CBotVar* pThis = NULL;
-
- CBotToken* pt = &m_vartoken;
- CBotClass* pClass = CBotClass::Find(pt);
-
- // create the variable "this" pointer type to the stack
-
- if ( pile->GivState()==0)
- {
- // create an instance of the requested class
- // and initialize the pointer to that object
-
-
- pThis = CBotVar::Create("this", pClass);
- pThis->SetUniqNum(-2) ;
-
- pile1->SetVar(pThis); // place on stack1
- pile->IncState();
- }
-
- // fetch the this pointer if it was interrupted
- if ( pThis == NULL)
- {
- pThis = pile1->GivVar(); // find the pointer
- }
-
- // is there an assignment or parameters (constructor)
- if ( pile->GivState()==1)
- {
- // evaluates the constructor of the instance
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // evaluate the parameters
- // and places the values on the stack
- // to be interrupted at any time
-
- if (p != NULL) while ( true)
- {
- pile2 = pile2->AddStack(); // space on the stack for the result
- if (pile2->GivState() == 0)
- {
- if (!p->Execute(pile2)) return false; // interrupted here?
- pile2->SetState(1);
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // create a variable for the result
- CBotVar* pResult = NULL; // constructos still void
-
- if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(),
- pThis, ppVars,
- pResult, pile2, GivToken())) return false; // interrupt
-
- pThis->ConstructorSet(); // indicates that the constructor has been called
- }
-
- return pj->Return(pile1); // passes below
-}
-
-void CBotNew::RestoreState(CBotStack* &pj, bool bMain)
-{
- if (!bMain) return;
-
- CBotStack* pile = pj->RestoreStack(this); //primary stack
- if (pile == NULL) return;
-
- CBotStack* pile1 = pj->AddStack2(); //secondary stack
-
- CBotToken* pt = &m_vartoken;
- CBotClass* pClass = CBotClass::Find(pt);
-
- // create the variable "this" pointer type to the object
-
- if ( pile->GivState()==0)
- {
- return;
- }
-
- CBotVar* pThis = pile1->GivVar(); // find the pointer
- pThis->SetUniqNum(-2);
-
- // is ther an assignment or parameters (constructor)
- if ( pile->GivState()==1)
- {
- // evaluates the constructor of the instance
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // evaluate the parameters
- // and places the values on the stack
- // to be interrupted at any time
-
- if (p != NULL) while ( true)
- {
- pile2 = pile2->RestoreStack(); // space on the stack for the result
- if (pile2 == NULL) return;
-
- if (pile2->GivState() == 0)
- {
- p->RestoreState(pile2, bMain); // interrupt here!
- return;
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GivString(), pThis,
- ppVars, pile2) ; // interrupt here!
- }
-}
-
-/////////////////////////////////////////////////////////////
-// check if two results are consistent to make an operation
-
-bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op)
-{
- int t1 = type1.GivType();
- int t2 = type2.GivType();
-
- int max = (t1 > t2) ? t1 : t2;
-
- if (max == 99) return false; // result is void?
-
- // special case for strin concatenation
- if (op == ID_ADD && max >= CBotTypString) return true;
- if (op == ID_ASSADD && max >= CBotTypString) return true;
- if (op == ID_ASS && t1 == CBotTypString) return true;
-
- if (max >= CBotTypBoolean)
- {
- if ( (op == ID_EQ || op == ID_NE) &&
- (t1 == CBotTypPointer && t2 == CBotTypNullPointer)) return true;
- if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) &&
- (t2 == CBotTypPointer && t1 == CBotTypNullPointer)) return true;
- if ( (op == ID_EQ || op == ID_NE) &&
- (t1 == CBotTypArrayPointer && t2 == CBotTypNullPointer)) return true;
- if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) &&
- (t2 == CBotTypArrayPointer && t1 == CBotTypNullPointer)) return true;
- if (t2 != t1) return false;
- if (t1 == CBotTypArrayPointer) return type1.Compare(type2);
- if (t1 == CBotTypPointer ||
- t1 == CBotTypClass ||
- t1 == CBotTypIntrinsic )
- {
- CBotClass* c1 = type1.GivClass();
- CBotClass* c2 = type2.GivClass();
-
- return c1->IsChildOf(c2) || c2->IsChildOf(c1);
- // accept the case in reverse
- // the transaction will be denied at runtime if the pointer is not
- // compatible
- }
-
- return true;
- }
-
- type1.SetType(max);
- type2.SetType(max);
- return true;
-}
-
-// check if two variables are compatible for parameter passing
-
-bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2)
-{
- int t1 = type1.GivType();
- int t2 = type2.GivType();
-
- if (t1 == CBotTypIntrinsic) t1 = CBotTypClass;
- if (t2 == CBotTypIntrinsic) t2 = CBotTypClass;
-
- int max = (t1 > t2) ? t1 : t2;
-
- if (max == 99) return false; // result is void?
-
- if (max >= CBotTypBoolean)
- {
- if (t2 != t1) return false;
-
- if (max == CBotTypArrayPointer)
- return TypesCompatibles(type1.GivTypElem(), type2.GivTypElem());
-
- if (max == CBotTypClass || max == CBotTypPointer)
- return type1.GivClass() == type2.GivClass() ;
-
- return true ;
- }
- return true;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////
-// file management
-
-// necessary because it is not possible to do the fopen in the main program
-// fwrite and fread in a dll or using the FILE * returned.
-
-
-FILE* fOpen(const char* name, const char* mode)
-{
- return fopen(name, mode);
-}
-
-int fClose(FILE* filehandle)
-{
- return fclose(filehandle);
-}
-
-size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle)
-{
- return fwrite(buffer, elemsize, length, filehandle);
-}
-
-size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle)
-{
- return fread(buffer, elemsize, length, filehandle);
-}
-
-size_t fWrite(const void *buffer, size_t length, FILE* filehandle)
-{
- return fwrite(buffer, 1, length, filehandle);
-}
-
-size_t fRead(void *buffer, size_t length, FILE* filehandle)
-{
- return fread(buffer, 1, length, filehandle);
-}
-
-
-////////////////////////////////////////
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. +/////////////////////////////////////////////////////////////////////// + +// compilation of various instructions +// compile all routines as static +// and return an object according to what was found as instruction + +// compiler principle: +// compile the routines return an object of the class corresponding to the operation found +// this is always a subclass of CBotInstr. +// (CBotInstr objects are never used directly) + + +// compiles if the routine returns NULL is that the statement is false +// or misunderstood. +// the error is then on the stack CBotCStack :: Isok () is false + + + +#include "CBot.h" + +CBotInstr::CBotInstr() +{ + name = "CBotInstr"; + m_next = NULL; + m_next2b = NULL; + m_next3 = NULL; + m_next3b = NULL; +} + +CBotInstr::~CBotInstr() +{ + delete m_next; + delete m_next2b; + delete m_next3; + delete m_next3b; +} + +// counter of nested loops, +// to determine the break and continue valid +// list of labels used + + +int CBotInstr::m_LoopLvl = 0; +CBotStringArray CBotInstr::m_labelLvl = CBotStringArray(); + +// adds a level with a label +void CBotInstr::IncLvl(CBotString& label) +{ + m_labelLvl.SetSize(m_LoopLvl+1); + m_labelLvl[m_LoopLvl] = label; + m_LoopLvl++; +} + +// adds a level (switch statement) +void CBotInstr::IncLvl() +{ + m_labelLvl.SetSize(m_LoopLvl+1); + m_labelLvl[m_LoopLvl] = "#SWITCH"; + m_LoopLvl++; +} + +// free a level +void CBotInstr::DecLvl() +{ + m_LoopLvl--; + m_labelLvl[m_LoopLvl].Empty(); +} + +// control validity of break and continue +bool CBotInstr::ChkLvl(const CBotString& label, int type) +{ + int i = m_LoopLvl; + while (--i>=0) + { + if ( type == ID_CONTINUE && m_labelLvl[i] == "#SWITCH") continue; + if (label.IsEmpty()) return true; + if (m_labelLvl[i] == label) return true; + } + return false; +} + +bool CBotInstr::IsOfClass(CBotString n) +{ + return name == n; +} + + +//////////////////////////////////////////////////////////////////////////// +// database management class CBotInstr + +// set the token corresponding to the instruction + +void CBotInstr::SetToken(CBotToken* p) +{ + m_token = *p; +} + +// return the type of the token assicated with the instruction + +int CBotInstr::GivTokenType() +{ + return m_token.GivType(); +} + +// return associated token + +CBotToken* CBotInstr::GivToken() +{ + return &m_token; +} + +// adds the statement following the other + +void CBotInstr::AddNext(CBotInstr* n) +{ + CBotInstr* p = this; + while (p->m_next != NULL) p = p->m_next; + p->m_next = n; +} + +void CBotInstr::AddNext3(CBotInstr* n) +{ + CBotInstr* p = this; + while (p->m_next3 != NULL) p = p->m_next3; + p->m_next3 = n; +} + +void CBotInstr::AddNext3b(CBotInstr* n) +{ + CBotInstr* p = this; + while (p->m_next3b != NULL) p = p->m_next3b; + p->m_next3b = n; +} + +// returns next statement + +CBotInstr* CBotInstr::GivNext() +{ + return m_next; +} + +CBotInstr* CBotInstr::GivNext3() +{ + return m_next3; +} + +CBotInstr* CBotInstr::GivNext3b() +{ + return m_next3b; +} + +/////////////////////////////////////////////////////////////////////////// +// compile an instruction which can be +// while, do, try, throw, if, for, switch, break, continue, return +// int, float, boolean, string, +// declaration of an instance of a class +// arbitrary expression + + +CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + + if (p == NULL) return NULL; + + int type = p->GivType(); // what is the next token + + // is it a lable? + if (IsOfType(pp, TokenTypVar) && + IsOfType(pp, ID_DOTS)) + { + type = pp->GivType(); + // these instructions accept only lable + if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0)) + { + pStack->SetError(TX_LABEL, pp->GivStart()); + return NULL; + } + } + + // call routine corresponding to the compilation token found + switch (type) + { + case ID_WHILE: + return CBotWhile::Compile(p, pStack); + + case ID_FOR: + return CBotFor::Compile(p, pStack); + + case ID_DO: + return CBotDo::Compile(p, pStack); + + case ID_REPEAT: + return CBotRepeat::Compile(p, pStack); + + case ID_BREAK: + case ID_CONTINUE: + return CBotBreak::Compile(p, pStack); + + case ID_SWITCH: + return CBotSwitch::Compile(p, pStack); + + case ID_TRY: + return CBotTry::Compile(p, pStack); + + case ID_THROW: + return CBotThrow::Compile(p, pStack); + + case ID_DEBUGDD: + return CBotStartDebugDD::Compile(p, pStack); + + case ID_INT: + return CBotInt::Compile(p, pStack); + + case ID_FLOAT: + return CBotFloat::Compile(p, pStack); + + case ID_STRING: + return CBotIString::Compile(p, pStack); + + case ID_BOOLEAN: + case ID_BOOL: + return CBotBoolean::Compile(p, pStack); + + case ID_IF: + return CBotIf::Compile(p, pStack); + + case ID_RETURN: + return CBotReturn::Compile(p, pStack); + + case ID_ELSE: + pStack->SetStartError(p->GivStart()); + pStack->SetError(TX_ELSEWITHOUTIF, p->GivEnd()); + return NULL; + + case ID_CASE: + pStack->SetStartError(p->GivStart()); + pStack->SetError(TX_OUTCASE, p->GivEnd()); + return NULL; + } + + pStack->SetStartError(p->GivStart()); + + // should not be a reserved word DefineNum + if (p->GivType() == TokenTypDef) + { + pStack->SetError(TX_RESERVED, p); + return NULL; + } + + // this might be an instance of class definnition + CBotToken* ppp = p; + if (IsOfType(ppp, TokenTypVar)) + { + if (CBotClass::Find(p) != NULL) + { + // yes, compiles the declaration of the instance + return CBotClassInst::Compile(p, pStack); + } + } + + // this can be an arythmetic instruction + CBotInstr* inst = CBotExpression::Compile(p, pStack); + if (IsOfType(p, ID_SEP)) + { + return inst; + } + pStack->SetError(TX_ENDOF, p->GivStart()); + delete inst; + return NULL; +} + +bool CBotInstr::Execute(CBotStack* &pj) +{ + CBotString ClassManquante = name; + ASM_TRAP(); // should never go through this routine + // but use the routines of the subclasses + return false; +} + +bool CBotInstr::Execute(CBotStack* &pj, CBotVar* pVar) +{ + if (!Execute(pj)) return false; + pVar->SetVal(pj->GivVar()); + return true; +} + +void CBotInstr::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotString ClassManquante = name; + ASM_TRAP(); // should never go through this routine + // but use the routines of the subclasses +} + + +bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + ASM_TRAP(); // dad do not know, see the girls + return false; +} + +bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) +{ + ASM_TRAP(); // dad do not know, see the girls + return false; +} + +void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + ASM_TRAP(); // dad do not know, see the girls +} + +// this routine is defined only for the subclass CBotCase +// this allows to make the call on all instructions CompCase +// to see if it's a case to the desired value. + +bool CBotInstr::CompCase(CBotStack* &pj, int val) +{ + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a statement block " { i ; i ; } " + +// this class have no constructor because there is never an instance of this +// class (TODO what about default constructor?) +// the object returned by Compile is usually of type CBotListInstr + + +CBotInstr* CBotBlock::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal) +{ + pStack->SetStartError(p->GivStart()); + + if (IsOfType(p, ID_OPBLK)) + { + CBotInstr* inst = CBotListInstr::Compile(p, pStack, bLocal); + + if (IsOfType(p, ID_CLBLK)) + { + return inst; + } + + pStack->SetError(TX_CLOSEBLK, p->GivStart()); // missing parenthesis + delete inst; + return NULL; + } + + pStack->SetError(TX_OPENBLK, p->GivStart()); + return NULL; +} + +CBotInstr* CBotBlock::CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal) +{ + // is this a new block + if (p->GivType() == ID_OPBLK) return CBotBlock::Compile(p, pStack); + + // otherwise, look for a single statement instead + + // to handle the case with local definition instruction (*) + CBotCStack* pStk = pStack->TokenStack(p, bLocal); + + return pStack->Return( CBotInstr::Compile(p, pStk), // a single instruction + pStk); +} + +// (*) is the case in the following statement +// if (1 == 1) int x = 0; +// where the variable x is known only in the block following the if + + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a list of instructions separated by semicolons + +CBotListInstr::CBotListInstr() +{ + m_Instr = NULL; + name = "CBotListInstr"; +} + +CBotListInstr::~CBotListInstr() +{ + delete m_Instr; +} + +CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal) +{ + CBotCStack* pStk = pStack->TokenStack(p, bLocal); // variables are local + + CBotListInstr* inst = new CBotListInstr(); + + while (true) + { + if (p == NULL) break; + + if (IsOfType(p, ID_SEP)) continue; // empty statement ignored + if (p->GivType() == ID_CLBLK) break; + + if (IsOfType(p, 0)) + { + pStack->SetError(TX_CLOSEBLK, p->GivStart()); + delete inst; + return pStack->Return(NULL, pStk); + } + + CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk); // compiles next + + if (!pStk->IsOk()) + { + delete inst; + return pStack->Return(NULL, pStk); + } + + if (inst->m_Instr == NULL) inst->m_Instr = i; + else inst->m_Instr->AddNext(i); // added a result + } + return pStack->Return(inst, pStk); +} + +// executes a set of instructions + +bool CBotListInstr::Execute(CBotStack* &pj) +{ + + CBotStack* pile = pj->AddStack(this, true); //needed for SetState() + if (pile->StackOver() ) return pj->Return( pile); + + + CBotInstr* p = m_Instr; // the first expression + + int state = pile->GivState(); + while (state-->0) p = p->GivNext(); // returns to the interrupted operation + + if (p != NULL) while (true) + { + if (!p->Execute(pile)) return false; + p = p->GivNext(); + if (p == NULL) break; + if (!pile->IncState()) ;//return false; // ready for next + } + + return pj->Return(pile); +} + +void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotInstr* p = m_Instr; // the first expression + + int state = pile->GivState(); + while ( p != NULL && state-- > 0) + { + p->RestoreState(pile, false); + p = p->GivNext(); // returns to the interrupted operation + } + + if (p != NULL) p->RestoreState(pile, true); +} + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// compilation of an element to the left of an assignment + +CBotLeftExprVar::CBotLeftExprVar() +{ + name = "CBotLeftExprVar"; + m_typevar = -1; + m_nIdent = 0; +} + +CBotLeftExprVar::~CBotLeftExprVar() +{ +} + +CBotInstr* CBotLeftExprVar::Compile(CBotToken* &p, CBotCStack* pStack) +{ + // verifies that the token is a variable name + if (p->GivType() != TokenTypVar) + { + pStack->SetError( TX_NOVAR, p->GivStart()); + return NULL; + } + + CBotLeftExprVar* inst = new CBotLeftExprVar(); + inst->SetToken(p); + p = p->GivNext(); + + return inst; +} + +// creates a variable and assigns the result to the stack +bool CBotLeftExprVar::Execute(CBotStack* &pj) +{ + CBotVar* var1; + CBotVar* var2; + + var1 = CBotVar::Create(m_token.GivString(), m_typevar); + var1->SetUniqNum(m_nIdent); // with the unique identifier + pj->AddVar(var1); // place it on the stack + + var2 = pj->GivVar(); // result on the stack + if (var2) var1->SetVal(var2); // do the assignment + + return true; +} + +void CBotLeftExprVar::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotVar* var1; + + var1 = pj->FindVar(m_token.GivString()); + if (var1 == NULL) ASM_TRAP(); + + var1->SetUniqNum(m_nIdent); // with the unique identifier +} + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// defining an array of any type +// int a[12]; +// point x[]; + +CBotInstArray::CBotInstArray() +{ + m_var = NULL; + m_listass = NULL; + name = "CBotInstArray"; +} + +CBotInstArray::~CBotInstArray() +{ + delete m_var; + delete m_listass; +} + + +CBotInstr* CBotInstArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) +{ + CBotCStack* pStk = pStack->TokenStack(p); + + CBotInstArray* inst = new CBotInstArray(); + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + + // determinse the expression is valid for the item on the left side + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable? + { + pStk->SetError(TX_REDEFVAR, vartoken); + goto error; + } + + CBotInstr* i; + while (IsOfType(p, ID_OPBRK)) + { + if (p->GivType() != ID_CLBRK) + i = CBotExpression::Compile(p, pStk); // expression for the value + else + i = new CBotEmpty(); // if no special formula + + inst->AddNext3b(i); // construct a list + type = CBotTypResult(CBotTypArrayPointer, type); + + if (!pStk->IsOk() || !IsOfType(p, ID_CLBRK )) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + } + + CBotVar* var = CBotVar::Create(vartoken, type); // create an instance + inst->m_typevar = type; + + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); // place it on the stack + + if (IsOfType(p, ID_ASS)) // with an assignment + { + inst->m_listass = CBotListArray::Compile(p, pStk, type.GivTypElem()); + } + + if (pStk->IsOk()) return pStack->Return(inst, pStk); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + + +// executes the definition of an array + +bool CBotInstArray::Execute(CBotStack* &pj) +{ + CBotStack* pile1 = pj->AddStack(this); + + CBotStack* pile = pile1; + + if (pile1->GivState() == 0) + { + // seek the maximum dimension of the table + CBotInstr* p = GivNext3b(); // the different formulas + int nb = 0; + + while (p != NULL) + { + pile = pile->AddStack(); // little room to work + nb++; + if (pile->GivState() == 0) + { + if (!p->Execute(pile)) return false; // size calculation //interrupted? + pile->IncState(); + } + p = p->GivNext3b(); + } + + p = GivNext3b(); + pile = pile1; // returns to the stack + int n = 0; + int max[100]; + + while (p != NULL) + { + pile = pile->AddStack(); + CBotVar* v = pile->GivVar(); // result + max[n] = v->GivValInt(); // value + if (max[n]>MAXARRAYSIZE) + { + pile->SetError(TX_OUTARRAY, &m_token); + return pj->Return (pile); + } + n++; + p = p->GivNext3b(); + } + while (n<100) max[n++] = 0; + + m_typevar.SetArray(max); // store the limitations + + // create simply a NULL pointer + CBotVar* var = CBotVar::Create(m_var->GivToken(), m_typevar); + var->SetPointer(NULL); + var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); + pj->AddVar(var); + +#if STACKMEM + pile1->AddStack()->Delete(); +#else + delete pile1->AddStack(); // need more indices +#endif + pile1->IncState(); + } + + if (pile1->GivState() == 1) + { + if (m_listass != NULL) // there is the assignment for this table + { + CBotVar* pVar = pj->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent); + + if (!m_listass->Execute(pile1, pVar)) return false; + } + pile1->IncState(); + } + + if (pile1->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile1 )) return false; + + return pj->Return(pile1); +} + +void CBotInstArray::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile1 = pj; + + CBotVar* var = pj->FindVar(m_var->GivToken()->GivString()); + if (var != NULL) var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); + + if (bMain) + { + pile1 = pj->RestoreStack(this); + CBotStack* pile = pile1; + if (pile == NULL) return; + + if (pile1->GivState() == 0) + { + // seek the maximum dimension of the table + CBotInstr* p = GivNext3b(); + + while (p != NULL) + { + pile = pile->RestoreStack(); + if (pile == NULL) return; + if (pile->GivState() == 0) + { + p->RestoreState(pile, bMain); + return; + } + p = p->GivNext3b(); + } + } + if (pile1->GivState() == 1 && m_listass != NULL) + { + m_listass->RestoreState(pile1, bMain); + } + + } + + if (m_next2b ) m_next2b->RestoreState( pile1, bMain); +} + +// special case for empty indexes +bool CBotEmpty :: Execute(CBotStack* &pj) +{ + CBotVar* pVar = CBotVar::Create("", CBotTypInt); + pVar->SetValInt(-1); + pj->SetVar(pVar); + return true; +} + +void CBotEmpty :: RestoreState(CBotStack* &pj, bool bMain) +{ +} + +////////////////////////////////////////////////////////////////////////////////////// +// defining a list table initialization +// int [ ] a [ ] = (( 1, 2, 3 ) , ( 3, 2, 1 )) ; + + +CBotListArray::CBotListArray() +{ + m_expr = NULL; + name = "CBotListArray"; +} + +CBotListArray::~CBotListArray() +{ + delete m_expr; +} + + +CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) +{ + CBotCStack* pStk = pStack->TokenStack(p); + + CBotToken* pp = p; + + if (IsOfType( p, ID_NULL )) + { + CBotInstr* inst = new CBotExprNull (); + inst->SetToken(pp); + return pStack->Return(inst, pStk); // ok with empty element + } + + CBotListArray* inst = new CBotListArray(); + + if (IsOfType( p, ID_OPENPAR )) + { + // each element takes the one after the other + if (type.Eq( CBotTypArrayPointer )) + { + type = type.GivTypElem(); + + pStk->SetStartError(p->GivStart()); + if (NULL == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) )) + { + goto error; + } + + while (IsOfType( p, ID_COMMA )) // other elements? + { + pStk->SetStartError(p->GivStart()); + + CBotInstr* i = CBotListArray::Compile(p, pStk, type); + if (NULL == i) + { + goto error; + } + + inst->m_expr->AddNext3(i); + } + } + else + { + pStk->SetStartError(p->GivStart()); + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + CBotVar* pv = pStk->GivVar(); // result of the expression + + if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + + while (IsOfType( p, ID_COMMA )) // other elements? + { + pStk->SetStartError(p->GivStart()); + + CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ; + if (NULL == i) + { + goto error; + } + + CBotVar* pv = pStk->GivVar(); // result of the expression + + if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + inst->m_expr->AddNext3(i); + } + } + + if (!IsOfType(p, ID_CLOSEPAR) ) + { + pStk->SetError(TX_CLOSEPAR, p->GivStart()); + goto error; + } + + return pStack->Return(inst, pStk); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + + +// executes the definition of an array + +bool CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar) +{ + CBotStack* pile1 = pj->AddStack(); + CBotVar* pVar2; + + CBotInstr* p = m_expr; + + int n = 0; + + for (; p != NULL ; n++, p = p->GivNext3()) + { + if (pile1->GivState() > n) continue; + + pVar2 = pVar->GivItem(n, true); + + if (!p->Execute(pile1, pVar2)) return false; // evaluate expression + + pile1->IncState(); + } + + return pj->Return(pile1); +} + +void CBotListArray::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) + { + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotInstr* p = m_expr; + + int state = pile->GivState(); + + while(state-- > 0) p = p->GivNext3() ; + + p->RestoreState(pile, bMain); // size calculation //interrupted! + } +} + +////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// definition of an integer variable +// int a, b = 12; + +CBotInt::CBotInt() +{ + m_next = NULL; // for multiple definitions + m_var = + m_expr = NULL; + name = "CBotInt"; +} + +CBotInt::~CBotInt() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first) +{ + if (IsOfType(p, ID_OPBRK)) + { + if (!IsOfType(p, ID_CLBRK)) + { + pStack->SetError(TX_CLBRK, p->GivStart()); + return NULL; + } + + CBotInstr* inst = CompileArray(p, pStack, CBotTypResult(CBotTypArrayPointer, type), false); + if (inst != NULL || !pStack->IsOk()) return inst; + } + + // compiles an array declaration + if (first) return NULL ; + + CBotInstr* inst = CBotInstArray::Compile(p, pStack, type); + if (inst == NULL) return NULL; + + if (IsOfType(p, ID_COMMA)) // several definitions + { + if (NULL != ( inst->m_next2b = CBotInstArray::CompileArray(p, pStack, type, false))) // compiles next one + { + return inst; + } + delete inst; + return NULL; + } + + if (IsOfType(p, ID_SEP)) // end of instruction + { + return inst; + } + + delete inst; + pStack->SetError(TX_ENDOF, p->GivStart()); + return NULL; +} + +CBotInstr* CBotInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; // no repetition of the token "int" + + if (!cont && !IsOfType(p, ID_INT)) return NULL; + + CBotInt* inst = (CBotInt*)CompileArray(p, pStack, CBotTypInt); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotInt(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + + // determines the expression is valid for the item on the left side + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypInt; + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable + { + pStk->SetError(TX_REDEFVAR, vartoken); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) + { + delete inst; // type is not CBotInt + p = vartoken; // returns the variable name + + // compiles an array declaration + + CBotInstr* inst2 = CBotInstArray::Compile(p, pStk, CBotTypInt); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + + if (IsOfType(p, ID_COMMA)) // several definition chained + { + if (NULL != ( inst2->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile the next one + { + return pStack->Return(inst2, pStk); + } + } + inst = (CBotInt*)inst2; + goto suite; // no assignment, variable already created + } + + if (IsOfType(p, ID_ASS)) // with an assignment? + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + if (pStk->GivType() >= CBotTypBoolean) // compatible type ? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + } + + { + CBotVar* var = CBotVar::Create(vartoken, CBotTypInt);// create the variable (evaluated after the assignment) + var->SetInit(inst->m_expr != NULL); // if initialized with assignment + var->SetUniqNum( //set it with a unique number + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); // place it on the stack + } + + if (IsOfType(p, ID_COMMA)) // chained several definitions + { + if (NULL != ( inst->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile next one + { + return pStack->Return(inst, pStk); + } + } +suite: + if (noskip || IsOfType(p, ID_SEP)) // instruction is completed + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// execute the definition of the integer variable + +bool CBotInt::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); // essential for SetState() + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; // initial value // interrupted? + m_var->Execute(pile); // creates and assign the result + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; // other(s) definition(s) + + return pj->Return(pile); // forward below +} + +void CBotInt::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); // initial value // interrupted? + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) m_next2b->RestoreState(pile, bMain); // other(s) definition(s) +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// defining a boolean variable +// int a, b = false; + +CBotBoolean::CBotBoolean() +{ + m_var = + m_expr = NULL; + name = "CBotBoolean"; +} + +CBotBoolean::~CBotBoolean() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; + + if (!cont && !IsOfType(p, ID_BOOLEAN, ID_BOOL)) return NULL; + + CBotBoolean* inst = (CBotBoolean*)CompileArray(p, pStack, CBotTypBoolean); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotBoolean(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + CBotVar* var = NULL; + + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypBoolean; + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable + { + pStk->SetError(TX_REDEFVAR, vartoken); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) + { + delete inst; // type is not CBotInt + p = vartoken; // resutns to the variable name + + // compiles an array declaration + + inst = (CBotBoolean*)CBotInstArray::Compile(p, pStk, CBotTypBoolean); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + goto suite; // no assignment, variable already created + } + + if (IsOfType(p, ID_ASS)) + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + if (!pStk->GivTypResult().Eq(CBotTypBoolean)) + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + } + + var = CBotVar::Create(vartoken, CBotTypBoolean);// create the variable (evaluated after the assignment) + var->SetInit(inst->m_expr != NULL); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); +suite: + if (IsOfType(p, ID_COMMA)) + { + if (NULL != ( inst->m_next2b = CBotBoolean::Compile(p, pStk, true, noskip))) + { + return pStack->Return(inst, pStk); + } + } + + if (noskip || IsOfType(p, ID_SEP)) + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes a boolean variable definition + +bool CBotBoolean::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this);//essential for SetState() + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; + m_var->Execute(pile); + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; + + return pj->Return(pile); +} + +void CBotBoolean::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); // initial value interrupted? + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) + m_next2b->RestoreState(pile, bMain); // other(s) definition(s) +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// definition of a real/float variable +// int a, b = 12.4; + +CBotFloat::CBotFloat() +{ + m_var = + m_expr = NULL; + name = "CBotFloat"; +} + +CBotFloat::~CBotFloat() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; + + if (!cont && !IsOfType(p, ID_FLOAT)) return NULL; + + CBotFloat* inst = (CBotFloat*)CompileArray(p, pStack, CBotTypFloat); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotFloat(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + CBotVar* var = NULL; + inst->SetToken(vartoken); + + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypFloat; + if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable + { + pStk->SetStartError(vartoken->GivStart()); + pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) + { + delete inst; + p = vartoken; + inst = (CBotFloat*)CBotInstArray::Compile(p, pStk, CBotTypFloat); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + goto suite; // no assignment, variable already created + } + + if (IsOfType(p, ID_ASS)) + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } + if (pStk->GivType() >= CBotTypBoolean) + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } + } + + var = CBotVar::Create(vartoken, CBotTypFloat); + var->SetInit(inst->m_expr != NULL); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); +suite: + if (IsOfType(p, ID_COMMA)) + { + if (NULL != ( inst->m_next2b = CBotFloat::Compile(p, pStk, true, noskip))) + { + return pStack->Return(inst, pStk); + } + } + + if (noskip || IsOfType(p, ID_SEP)) + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes the definition of a real variable + +bool CBotFloat::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; + m_var->Execute(pile); + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; + + return pj->Return(pile); +} + +void CBotFloat::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) + m_next2b->RestoreState(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// define a string variable +// int a, b = "salut"; + +CBotIString::CBotIString() +{ + m_var = + m_expr = NULL; + name = "CBotIString"; +} + +CBotIString::~CBotIString() +{ + delete m_var; + delete m_expr; +} + +CBotInstr* CBotIString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip) +{ + CBotToken* pp = cont ? NULL : p; + + if (!cont && !IsOfType(p, ID_STRING)) return NULL; + + CBotIString* inst = (CBotIString*)CompileArray(p, pStack, CBotTypString); + if (inst != NULL || !pStack->IsOk()) return inst; + + CBotCStack* pStk = pStack->TokenStack(pp); + + inst = new CBotIString(); + + inst->m_expr = NULL; + + CBotToken* vartoken = p; + inst->SetToken(vartoken); + + if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypString; + if (pStk->CheckVarLocal(vartoken)) + { + pStk->SetStartError(vartoken->GivStart()); + pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); + goto error; + } + + if (IsOfType(p, ID_ASS)) + { + if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) + { + goto error; + } +/* if (!pStk->GivTypResult().Eq(CBotTypString)) // type compatible ? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + }*/ + } + + CBotVar* var = CBotVar::Create(vartoken, CBotTypString); + var->SetInit(inst->m_expr != NULL); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + pStack->AddVar(var); + + if (IsOfType(p, ID_COMMA)) + { + if (NULL != ( inst->m_next2b = CBotIString::Compile(p, pStk, true, noskip))) + { + return pStack->Return(inst, pStk); + } + } + + if (noskip || IsOfType(p, ID_SEP)) + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes the definition of the string variable + +bool CBotIString::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if ( pile->GivState()==0) + { + if (m_expr && !m_expr->Execute(pile)) return false; + m_var->Execute(pile); + + if (!pile->SetState(1)) return false; + } + + if (pile->IfStep()) return false; + + if ( m_next2b && + !m_next2b->Execute(pile)) return false; + + return pj->Return(pile); +} + +void CBotIString::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + + if (bMain) + { + pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if ( pile->GivState()==0) + { + if (m_expr) m_expr->RestoreState(pile, bMain); + return; + } + } + + m_var->RestoreState(pile, bMain); + + if (m_next2b) + m_next2b->RestoreState(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a statement such as " x = 123 " ou " z * 5 + 4 " +// with or without assignment + +CBotExpression::CBotExpression() +{ + m_leftop = NULL; + m_rightop = NULL; + name = "CBotExpression"; +} + +CBotExpression::~CBotExpression() +{ + delete m_leftop; + delete m_rightop; +} + +CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + + CBotExpression* inst = new CBotExpression(); + + inst->m_leftop = CBotLeftExpr::Compile(p, pStack); + + inst->SetToken(p); + int OpType = p->GivType(); + + if ( pStack->IsOk() && + IsOfTypeList(p, ID_ASS, ID_ASSADD, ID_ASSSUB, ID_ASSMUL, ID_ASSDIV, ID_ASSMODULO, + ID_ASSAND, ID_ASSXOR, ID_ASSOR, + ID_ASSSL , ID_ASSSR, ID_ASSASR, 0 )) + { + if (inst->m_leftop == NULL) + { + pStack->SetError(TX_BADLEFT, p->GivEnd()); + delete inst; + return NULL; + } + + inst->m_rightop = CBotExpression::Compile(p, pStack); + if (inst->m_rightop == NULL) + { + delete inst; + return NULL; + } + + CBotTypResult type1 = pStack->GivTypResult(); + + // get the variable assigned to mark + CBotVar* var = NULL; + inst->m_leftop->ExecuteVar(var, pStack); + if (var == NULL) + { + delete inst; + return NULL; + } + + if (OpType != ID_ASS && var->GivInit() != IS_DEF) + { + pStack->SetError(TX_NOTINIT, pp); + delete inst; + return NULL; + } + + CBotTypResult type2 = var->GivTypResult(); + + // what types are acceptable? + switch (OpType) + { + case ID_ASS: + // if (type2 == CBotTypClass) type2 = -1; + if ((type1.Eq(CBotTypPointer) && type2.Eq(CBotTypPointer)) || + (type1.Eq(CBotTypClass) && type2.Eq(CBotTypClass) ) ) + { +/* CBotClass* c1 = type1.GivClass(); + CBotClass* c2 = type2.GivClass(); + if (!c1->IsChildOf(c2)) type2.SetType(-1); +//- if (!type1.Eq(CBotTypClass)) var->SetPointer(pStack->GivVar()->GivPointer());*/ + var->SetInit(2); + } + else + var->SetInit(true); + + break; + case ID_ASSADD: + if (type2.Eq(CBotTypBoolean) || + type2.Eq(CBotTypPointer) ) type2 = -1; // numbers and strings + break; + case ID_ASSSUB: + case ID_ASSMUL: + case ID_ASSDIV: + case ID_ASSMODULO: + if (type2.GivType() >= CBotTypBoolean) type2 = -1; // numbers only + break; + } + + if (!TypeCompatible(type1, type2, OpType)) + { + pStack->SetError(TX_BADTYPE, &inst->m_token); + delete inst; + return NULL; + } + + return inst; // compatible type? + } + + delete inst; + int start, end, error = pStack->GivError(start, end); + + p = pp; // returns to the top + pStack->SetError(0,0); // forget the error + + CBotInstr* i = CBotTwoOpExpr::Compile(p, pStack); // tries without assignment + if (i != NULL && error == TX_PRIVATE && p->GivType() == ID_ASS) + pStack->ResetError(error, start, end); + return i; +} + +// executes an expression with assignment + +bool CBotExpression::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + CBotToken* pToken = m_leftop->GivToken(); + CBotVar* pVar = NULL; + + CBotStack* pile1 = pile; + + bool IsInit = true; + CBotVar* result = NULL; + + // must be done before any indexes (stack can be changed) + if (!m_leftop->ExecuteVar(pVar, pile, NULL, false)) return false; // variable before accessing the value on the right + + if ( pile1->GivState()==0) + { + pile1->SetCopyVar(pVar); // keeps the copy on the stack (if interrupted) + pile1->IncState(); + } + + CBotStack* pile2 = pile->AddStack(); + + if ( pile2->GivState()==0) + { + if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted? + pile2->IncState(); + } + + if (pile1->GivState() == 1) + { + if (m_token.GivType() != ID_ASS) + { + pVar = pile1->GivVar(); // recovers if interrupted + IsInit = pVar->GivInit(); + if (IsInit == IS_NAN) + { + pile2->SetError(TX_OPNAN, m_leftop->GivToken()); + return pj->Return(pile2); + } + result = CBotVar::Create("", pVar->GivTypResult(2)); + } + + switch (m_token.GivType()) + { + case ID_ASS: + break; + case ID_ASSADD: + result->Add(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSSUB: + result->Sub(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSMUL: + result->Mul(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSDIV: + if (IsInit && + result->Div(pile1->GivVar(), pile2->GivVar())) + pile2->SetError(TX_DIVZERO, &m_token); + pile2->SetVar(result); + break; + case ID_ASSMODULO: + if (IsInit && + result->Modulo(pile1->GivVar(), pile2->GivVar())) + pile2->SetError(TX_DIVZERO, &m_token); + pile2->SetVar(result); + break; + case ID_ASSAND: + result->And(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSXOR: + result->XOr(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSOR: + result->Or(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSSL: + result->SL(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSSR: + result->SR(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + case ID_ASSASR: + result->ASR(pile1->GivVar(), pile2->GivVar()); + pile2->SetVar(result); + break; + default: + ASM_TRAP(); + } + if (!IsInit) + pile2->SetError(TX_NOTINIT, m_leftop->GivToken()); + + pile1->IncState(); + } + + if (!m_leftop->Execute( pile2, pile1 )) + return false; + + return pj->Return(pile2); +} + + +void CBotExpression::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) + { + CBotToken* pToken = m_leftop->GivToken(); + CBotVar* pVar = NULL; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotStack* pile1 = pile; + + if ( pile1->GivState()==0) + { + m_leftop->RestoreStateVar(pile, true); + return; + } + + m_leftop->RestoreStateVar(pile, false); + + CBotStack* pile2 = pile->RestoreStack(); + if (pile2 == NULL) return; + + if ( pile2->GivState()==0) + { + if (m_rightop) m_rightop->RestoreState(pile2, bMain); + return; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a statement such as "(condition)" +// the condition must be Boolean + +// this class has no constructor, because there is never an instance of this class +// the object returned by Compile is usually type CBotExpression + + +CBotInstr* CBotCondition::Compile(CBotToken* &p, CBotCStack* pStack) +{ + pStack->SetStartError(p->GivStart()); + if (IsOfType(p, ID_OPENPAR)) + { + CBotInstr* inst = CBotBoolExpr::Compile(p, pStack); + if (NULL != inst) + { + if (IsOfType(p, ID_CLOSEPAR)) + { + return inst; + } + pStack->SetError(TX_CLOSEPAR, p->GivStart()); // missing parenthesis + } + delete inst; + } + + pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis + + return NULL; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a statement such as "(condition)" +// the condition must be Boolean +// +// this class has no constructor, because there is never an instance of this +// class +// the object returned by Compile is usually type CBotExpression +// + +CBotInstr* CBotBoolExpr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + pStack->SetStartError(p->GivStart()); + + CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStack); + + if (NULL != inst) + { + if (pStack->GivTypResult().Eq(CBotTypBoolean)) + { + return inst; + } + pStack->SetError(TX_NOTBOOL, p->GivStart()); // is not a boolean + } + + delete inst; + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile either: +// instruction in parentheses (...) +// a unary expression (negative, not) +// variable name +// variables pre and post-incremented or decremented +// a given number DefineNum +// a constant +// procedure call +// new statement +// +// this class has no constructor, because there is never an instance of this class +// the object returned by Compile is the class corresponding to the instruction + + +CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(p->GivStart()); + + // is it an expression in parentheses? + if (IsOfType(p, ID_OPENPAR)) + { + CBotInstr* inst = CBotExpression::Compile(p, pStk); + + if (NULL != inst) + { + if (IsOfType(p, ID_CLOSEPAR)) + { + return pStack->Return(inst, pStk); + } + pStk->SetError(TX_CLOSEPAR, p->GivStart()); + } + delete inst; + return pStack->Return(NULL, pStk); + } + + // is this a unary operation? + CBotInstr* inst = CBotExprUnaire::Compile(p, pStk); + if (inst != NULL || !pStk->IsOk()) + return pStack->Return(inst, pStk); + + // is it a variable name? + if (p->GivType() == TokenTypVar) + { + // this may be a method call without the "this." before + inst = CBotExprVar::CompileMethode(p, pStk); + if (inst != NULL) return pStack->Return(inst, pStk); + + + // is it a procedure call? + inst = CBotInstrCall::Compile(p, pStk); + if (inst != NULL || !pStk->IsOk()) + return pStack->Return(inst, pStk); + + + CBotToken* pvar = p; + // no, it an "ordinaty" variable + inst = CBotExprVar::Compile(p, pStk); + + CBotToken* pp = p; + // post incremented or decremented? + if (IsOfType(p, ID_INC, ID_DEC)) + { + if (pStk->GivType() >= CBotTypBoolean) + { + pStk->SetError(TX_BADTYPE, pp); + delete inst; + return pStack->Return(NULL, pStk); + } + + // recompile the variable for read-only + delete inst; + p = pvar; + inst = CBotExprVar::Compile(p, pStk, PR_READ); + p = p->GivNext(); + + CBotPostIncExpr* i = new CBotPostIncExpr(); + i->SetToken(pp); + i->m_Instr = inst; // associated statement + return pStack->Return(i, pStk); + } + return pStack->Return(inst, pStk); + } + + // pre increpemted or pre decremented? + CBotToken* pp = p; + if (IsOfType(p, ID_INC, ID_DEC)) + { + CBotPreIncExpr* i = new CBotPreIncExpr(); + i->SetToken(pp); + + if (p->GivType() == TokenTypVar) + { + if (NULL != (i->m_Instr = CBotExprVar::Compile(p, pStk, PR_READ))) + { + if (pStk->GivType() >= CBotTypBoolean) + { + pStk->SetError(TX_BADTYPE, pp); + delete inst; + return pStack->Return(NULL, pStk); + } + return pStack->Return(i, pStk); + } + delete i; + return pStack->Return(NULL, pStk); + } + } + + // is it a number or DefineNum? + if (p->GivType() == TokenTypNum || + p->GivType() == TokenTypDef ) + { + CBotInstr* inst = CBotExprNum::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is this a chaine? + if (p->GivType() == TokenTypString) + { + CBotInstr* inst = CBotExprAlpha::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is a "true" or "false" + if (p->GivType() == ID_TRUE || + p->GivType() == ID_FALSE ) + { + CBotInstr* inst = CBotExprBool::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is an object to be created with new + if (p->GivType() == ID_NEW) + { + CBotInstr* inst = CBotNew::Compile(p, pStk); + return pStack->Return(inst, pStk); + } + + // is a null pointer + if (IsOfType(p, ID_NULL)) + { + CBotInstr* inst = new CBotExprNull (); + inst->SetToken(pp); + CBotVar* var = CBotVar::Create("", CBotTypNullPointer); + pStk->SetVar(var); + return pStack->Return(inst, pStk); + } + + // is a number nan + if (IsOfType(p, ID_NAN)) + { + CBotInstr* inst = new CBotExprNan (); + inst->SetToken(pp); + CBotVar* var = CBotVar::Create("", CBotTypInt); + var->SetInit(IS_NAN); + pStk->SetVar(var); + return pStack->Return(inst, pStk); + } + + + return pStack->Return(NULL, pStk); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// Management of pre-and post increment / decrement +// There is no routine Compiles, the object is created directly +// Compiles in CBotParExpr :: + + +CBotPostIncExpr::CBotPostIncExpr() +{ + m_Instr = NULL; + name = "CBotPostIncExpr"; +} + +CBotPostIncExpr::~CBotPostIncExpr() +{ + delete m_Instr; +} + +CBotPreIncExpr::CBotPreIncExpr() +{ + m_Instr = NULL; + name = "CBotPreIncExpr"; +} + +CBotPreIncExpr::~CBotPreIncExpr() +{ + delete m_Instr; +} + +bool CBotPostIncExpr::Execute(CBotStack* &pj) +{ + CBotStack* pile1 = pj->AddStack(this); + CBotStack* pile2 = pile1; + + CBotVar* var1 = NULL; + + // retrieves the variable fields and indexes according + if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false; + + pile1->SetState(1); + pile1->SetCopyVar(var1); // places the result (before incrementation); + + CBotStack* pile3 = pile2->AddStack(this); + if (pile3->IfStep()) return false; + + if (var1->GivInit() == IS_NAN) + { + pile1->SetError(TX_OPNAN, &m_token); + } + + if (var1->GivInit() != IS_DEF) + { + pile1->SetError(TX_NOTINIT, &m_token); + } + + if (GivTokenType() == ID_INC) var1->Inc(); + else var1->Dec(); + + return pj->Return(pile1); // operation done, result on pile2 +} + +void CBotPostIncExpr::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile1 = pj->RestoreStack(this); + if (pile1 == NULL) return; + + ((CBotExprVar*)m_Instr)->RestoreStateVar(pile1, bMain); + + if (pile1 != NULL) pile1->RestoreStack(this); +} + +bool CBotPreIncExpr::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var1; + + if (pile->GivState() == 0) + { + CBotStack* pile2 = pile; + // retrieves the variable fields and indexes according + // pile2 is modified on return + if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false; + + if (var1->GivInit() == IS_NAN) + { + pile->SetError(TX_OPNAN, &m_token); + return pj->Return(pile); // operation performed + } + + if (var1->GivInit() != IS_DEF) + { + pile->SetError(TX_NOTINIT, &m_token); + return pj->Return(pile); // operation performed + } + + if (GivTokenType() == ID_INC) var1->Inc(); + else var1->Dec(); // ((CBotVarInt*)var1)->m_val + + pile->IncState(); + } + + if (!m_Instr->Execute(pile)) return false; + return pj->Return(pile); // operation performed +} + + +void CBotPreIncExpr::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + if (pile->GivState() == 0) + { + return; + } + + m_Instr->RestoreState(pile, bMain); +} + + +////////////////////////////////////////////////////////////////////////////////////// +// compile an unary expression +// + +// - +// not +// ! +// ~ + +CBotExprUnaire::CBotExprUnaire() +{ + m_Expr = NULL; + name = "CBotExprUnaire"; +} + +CBotExprUnaire::~CBotExprUnaire() +{ + delete m_Expr; +} + +CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack) +{ + int op = p->GivType(); + CBotToken* pp = p; + if (!IsOfTypeList( p, ID_ADD, ID_SUB, ID_LOG_NOT, ID_TXT_NOT, ID_NOT, 0 )) return NULL; + + CBotCStack* pStk = pStack->TokenStack(pp); + + CBotExprUnaire* inst = new CBotExprUnaire(); + inst->SetToken(pp); + + if (NULL != (inst->m_Expr = CBotParExpr::Compile( p, pStk ))) + { + if (op == ID_ADD && pStk->GivType() < CBotTypBoolean) // only with the number + return pStack->Return(inst, pStk); + if (op == ID_SUB && pStk->GivType() < CBotTypBoolean) // only with the numer + return pStack->Return(inst, pStk); + if (op == ID_NOT && pStk->GivType() < CBotTypFloat) // only with an integer + return pStack->Return(inst, pStk); + if (op == ID_LOG_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean + return pStack->Return(inst, pStk); + if (op == ID_TXT_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean + return pStack->Return(inst, pStk); + + pStk->SetError(TX_BADTYPE, &inst->m_token); + } + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes unary expression + +bool CBotExprUnaire::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->GivState() == 0) + { + if (!m_Expr->Execute(pile)) return false; // interrupted ? + pile->IncState(); + } + + CBotStack* pile2 = pile->AddStack(); + if (pile2->IfStep()) return false; + + CBotVar* var = pile->GivVar(); // get the result on the stack + + switch (GivTokenType()) + { + case ID_ADD: + break; + case ID_SUB: + var->Neg(); // change the sign + break; + case ID_NOT: + case ID_LOG_NOT: + case ID_TXT_NOT: + var->Not(); + break; + } + return pj->Return(pile); // forwards below +} + +void CBotExprUnaire::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if ( pile == NULL) return; + + if (pile->GivState() == 0) + { + m_Expr->RestoreState(pile, bMain); // interrupted here! + return; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// index management for arrays +// array [ expression ] + + +CBotIndexExpr::CBotIndexExpr() +{ + m_expr = NULL; + name = "CBotIndexExpr"; +} + +CBotIndexExpr::~CBotIndexExpr() +{ + delete m_expr; +} + +// finds a field from the instance at compile time + +bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + if (pVar->GivType(1) != CBotTypArrayPointer) + ASM_TRAP(); + + pVar = ((CBotVarArray*)pVar)->GivItem(0, false); // at compile time makes the element [0] + if (pVar == NULL) + { + pile->SetError(TX_OUTARRAY, m_token.GivEnd()); + return false; + } + if (m_next3 != NULL) return m_next3->ExecuteVar(pVar, pile); + return true; +} + +// attention, changes the pointer to the stack intentionally +// place the index calculated on the additional stack + + +bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) +{ + CBotStack* pj = pile; + + if (pVar->GivType(1) != CBotTypArrayPointer) + ASM_TRAP(); + + pile = pile->AddStack(); + + if (pile->GivState() == 0) + { + if (!m_expr->Execute(pile)) return false; + pile->IncState(); + } + // handles array + + CBotVar* p = pile->GivVar(); // result on the stack + + if (p == NULL || p->GivType() > CBotTypDouble) + { + pile->SetError(TX_BADINDEX, prevToken); + return pj->Return(pile); + } + + int n = p->GivValInt(); // position in the table + + pVar = ((CBotVarArray*)pVar)->GivItem(n, bExtend); + if (pVar == NULL) + { + pile->SetError(TX_OUTARRAY, prevToken); + return pj->Return(pile); + } + + pVar->Maj(pile->GivPUser(), true); + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile, prevToken, bStep, bExtend) ) return false; + + // does not release the stack + // to avoid recalculation of the index twice where appropriate + return true; +} + +void CBotIndexExpr::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + pile = pile->RestoreStack(); + if (pile == NULL) return; + + if (bMain && pile->GivState() == 0) + { + m_expr->RestoreState(pile, true); + return; + } + + if (m_next3) + m_next3->RestoreStateVar(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// field management in an instance (dot operator) +// toto.x + + +CBotFieldExpr::CBotFieldExpr() +{ + name = "CBotFieldExpr"; + m_nIdent = 0; +} + +CBotFieldExpr::~CBotFieldExpr() +{ +} + +void CBotFieldExpr::SetUniqNum(int num) +{ + m_nIdent = num; +} + + +// find a field from the instance at compile + +bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + if (pVar->GivType(1) != CBotTypPointer) + ASM_TRAP(); + + pVar = pVar->GivItemRef(m_nIdent); + if (pVar == NULL) + { + pile->SetError(TX_NOITEM, &m_token); + return false; + } + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile) ) return false; + + return true; +} + +bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend) +{ + CBotStack* pj = pile; + pile = pile->AddStack(this); // changes in output stack + if (pile == EOX) return true; + + + if (pVar->GivType(1) != CBotTypPointer) + ASM_TRAP(); + + CBotVarClass* pItem = pVar->GivPointer(); + if (pItem == NULL) + { + pile->SetError(TX_NULLPT, prevToken); + return pj->Return(pile); + } + if (pItem->GivUserPtr() == OBJECTDELETED) + { + pile->SetError(TX_DELETEDPT, prevToken); + return pj->Return(pile); + } + + if (bStep && pile->IfStep()) return false; + + pVar = pVar->GivItemRef(m_nIdent); + if (pVar == NULL) + { + pile->SetError(TX_NOITEM, &m_token); + return pj->Return(pile); + } + + if (pVar->IsStatic()) + { + // for a static variable, takes it in the class itself + CBotClass* pClass = pItem->GivClass(); + pVar = pClass->GivItem(m_token.GivString()); + } + + // request the update of the element, if applicable + pVar->Maj(pile->GivPUser(), true); + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, bExtend) ) return false; + + // does not release the stack + // to maintain the state SetState () corresponding to step + + return true; +} + +void CBotFieldExpr::RestoreStateVar(CBotStack* &pj, bool bMain) +{ + pj = pj->RestoreStack(this); + if (pj == NULL) return; + + if (m_next3 != NULL) + m_next3->RestoreStateVar(pj, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// compile a left operand for an assignment +CBotLeftExpr::CBotLeftExpr() +{ + name = "CBotLeftExpr"; + m_nIdent = 0; +} + +CBotLeftExpr::~CBotLeftExpr() +{ +} + +// compiles an expression for a left-operand (left of an assignment) +// this can be +// toto +// toto[ 3 ] +// toto.x +// toto.pos.x +// toto[2].pos.x +// toto[1].pos[2].x +// toto[1][2][3] + +CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(p->GivStart()); + + // is it a variable name? + if (p->GivType() == TokenTypVar) + { + CBotLeftExpr* inst = new CBotLeftExpr(); // creates the object + + inst->SetToken(p); + + CBotVar* var; + + if (NULL != (var = pStk->FindVar(p))) // seek if known variable + { + inst->m_nIdent = var->GivUniqNum(); + if (inst->m_nIdent > 0 && inst->m_nIdent < 9000) + { + if ( var->IsPrivate(PR_READ) && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, p); + goto err; + } + // this is an element of the current class + // adds the equivalent of this. before + CBotToken pthis("this"); + inst->SetToken(&pthis); + inst->m_nIdent = -2; // indent for this + + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(p); // keeps the name of the token + inst->AddNext3(i); // add after + + var = pStk->FindVar(pthis); + var = var->GivItem(p->GivString()); + i->SetUniqNum(var->GivUniqNum()); + } + p = p->GivNext(); // next token + + while (true) + { + if (var->GivType() == CBotTypArrayPointer) + { + if (IsOfType( p, ID_OPBRK )) + { + CBotIndexExpr* i = new CBotIndexExpr(); + i->m_expr = CBotExpression::Compile(p, pStk); + inst->AddNext3(i); // add to the chain + + var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0] + + if (i->m_expr == NULL) + { + pStk->SetError(TX_BADINDEX, p->GivStart()); + goto err; + } + + if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto err; + } + continue; + } + } + + if (var->GivType(1) == CBotTypPointer) // for classes + { + if (IsOfType(p, ID_DOT)) + { + CBotToken* pp = p; + + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(pp); // keeps the name of the token + inst->AddNext3(i); // adds after + + if (p->GivType() == TokenTypVar) // must be a name + { + var = var->GivItem(p->GivString()); // get item correspondent + if (var != NULL) + { + if ( var->IsPrivate(PR_READ) && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, pp); + goto err; + } + + i->SetUniqNum(var->GivUniqNum()); + p = p->GivNext(); // skips the name + continue; + } + pStk->SetError(TX_NOITEM, p); + } + pStk->SetError(TX_DOT, p->GivStart()); + goto err; + } + } + break; + } + + + if (pStk->IsOk()) return (CBotLeftExpr*) pStack->Return(inst, pStk); + } + pStk->SetError(TX_UNDEFVAR, p); +err: + delete inst; + return (CBotLeftExpr*) pStack->Return(NULL, pStk); + } + + return (CBotLeftExpr*) pStack->Return(NULL, pStk); +} + +// runs, is a variable and assigns the result to the stack +bool CBotLeftExpr::Execute(CBotStack* &pj, CBotStack* array) +{ + CBotStack* pile = pj->AddStack(); + + CBotVar* var1 = NULL; + CBotVar* var2 = NULL; + // fetch a variable (not copy) + if (!ExecuteVar(var1, array, NULL, false)) return false; + + if (pile->IfStep()) return false; + + if (var1) + { + var2 = pj->GivVar(); // result on the input stack + if (var2) + { + CBotTypResult t1 = var1->GivTypResult(); + CBotTypResult t2 = var2->GivTypResult(); + if (t2.Eq(CBotTypPointer)) + { + CBotClass* c1 = t1.GivClass(); + CBotClass* c2 = t2.GivClass(); + if ( !c2->IsChildOf(c1)) + { + CBotToken* pt = &m_token; + pile->SetError(TX_BADTYPE, pt); + return pj->Return(pile); // operation performed + } + } + var1->SetVal(var2); // do assignment + } + pile->SetCopyVar(var1); // replace the stack with the copy of the variable + // (for name) + } + + return pj->Return(pile); // operation performed +} + +// fetch a variable during compilation + +bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile) +{ + pVar = pile->FindVar(m_token); + if (pVar == NULL) return false; + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile) ) return false; + + return true; +} + +// fetch the variable at runtume + +bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep) +{ + pile = pile->AddStack(this); + + pVar = pile->FindVar(m_nIdent); + if (pVar == NULL) + { +#ifdef _DEBUG + ASM_TRAP(); +#endif + pile->SetError(2, &m_token); + return false; + } + + if (bStep && m_next3 == NULL && pile->IfStep()) return false; + + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, true) ) return false; + + return true; +} + +void CBotLeftExpr::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + pile = pile->RestoreStack(this); + if (pile == NULL) return; + + if (m_next3 != NULL) + m_next3->RestoreStateVar(pile, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// converts a string into integer +// may be of the form 0xabc123 + +long GivNumInt(const char* p) +{ + long num = 0; + while (*p >= '0' && *p <= '9') + { + num = num * 10 + *p - '0'; + p++; + } + if (*p == 'x' || *p == 'X') + { + while (*++p != 0) + { + if (*p >= '0' && *p <= '9') + { + num = num * 16 + *p - '0'; + continue; + } + if (*p >= 'A' && *p <= 'F') + { + num = num * 16 + *p - 'A' + 10; + continue; + } + if (*p >= 'a' && *p <= 'f') + { + num = num * 16 + *p - 'a' + 10; + continue; + } + break; + } + } + return num; +} + +// converts a string into a float number +extern float GivNumFloat(const char* p) +{ + double num = 0; + double div = 10; + bool bNeg = false; + + if (*p == '-') + { + bNeg = true; + p++; + } + while (*p >= '0' && *p <= '9') + { + num = num * 10. + (*p - '0'); + p++; + } + + if (*p == '.') + { + p++; + while (*p >= '0' && *p <= '9') + { + num = num + (*p - '0') / div; + div = div * 10; + p++; + } + } + + int exp = 0; + if (*p == 'e' || *p == 'E') + { + char neg = 0; + p++; + if (*p == '-' || *p == '+') neg = *p++; + + while (*p >= '0' && *p <= '9') + { + exp = exp * 10 + (*p - '0'); + p++; + } + if (neg == '-') exp = -exp; + } + + while (exp > 0) + { + num *= 10.0; + exp--; + } + + while (exp < 0) + { + num /= 10.0; + exp++; + } + + if (bNeg) num = -num; + return (float)num; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a token representing a number +CBotExprNum::CBotExprNum() +{ + name = "CBotExprNum"; +} + +CBotExprNum::~CBotExprNum() +{ +} + +CBotInstr* CBotExprNum::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + CBotExprNum* inst = new CBotExprNum(); + + inst->SetToken(p); + CBotString s = p->GivString(); + + inst->m_numtype = CBotTypInt; + if (p->GivType() == TokenTypDef) + { + inst->m_valint = p->GivIdKey(); + } + else + { + if (s.Find('.') >= 0 || ( s.Find('x') < 0 && ( s.Find('e') >= 0 || s.Find('E') >= 0 ) )) + { + inst->m_numtype = CBotTypFloat; + inst->m_valfloat = GivNumFloat(s); + } + else + { + inst->m_valint = GivNumInt(s); + } + } + + if (pStk->NextToken(p)) + { + CBotVar* var = CBotVar::Create((CBotToken*)NULL, inst->m_numtype); + pStk->SetVar(var); + + return pStack->Return(inst, pStk); + } + delete inst; + return pStack->Return(NULL, pStk); +} + +// execute, returns the corresponding number + +bool CBotExprNum::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, m_numtype); + + CBotString nombre ; + if (m_token.GivType() == TokenTypDef) + { + nombre = m_token.GivString(); + } + + switch (m_numtype) + { + case CBotTypShort: + case CBotTypInt: + var->SetValInt(m_valint, nombre); + break; + case CBotTypFloat: + var->SetValFloat(m_valfloat); + break; + } + pile->SetVar(var); // place on the stack + + return pj->Return(pile); // it's ok +} + +void CBotExprNum::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a token representing a string + +CBotExprAlpha::CBotExprAlpha() +{ + name = "CBotExprAlpha"; +} + +CBotExprAlpha::~CBotExprAlpha() +{ +} + +CBotInstr* CBotExprAlpha::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + + CBotExprAlpha* inst = new CBotExprAlpha(); + + inst->SetToken(p); + p = p->GivNext(); + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString); + pStk->SetVar(var); + + return pStack->Return(inst, pStk); +} + +// execute, returns the corresponding string + +bool CBotExprAlpha::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString); + + CBotString chaine = m_token.GivString(); + chaine = chaine.Mid(1, chaine.GivLength()-2); // removes the quotes + + var->SetValString(chaine); // value of the number + + pile->SetVar(var); // put on the stack + + return pj->Return(pile); +} + +void CBotExprAlpha::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a token representing true or false + +CBotExprBool::CBotExprBool() +{ + name = "CBotExprBool"; +} + +CBotExprBool::~CBotExprBool() +{ +} + +CBotInstr* CBotExprBool::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->TokenStack(); + CBotExprBool* inst = NULL; + + if ( p->GivType() == ID_TRUE || + p->GivType() == ID_FALSE ) + { + inst = new CBotExprBool(); + inst->SetToken(p); // stores the operation false or true + p = p->GivNext(); + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean); + pStk->SetVar(var); + } + + return pStack->Return(inst, pStk); +} + +// executes, returns true or false + +bool CBotExprBool::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean); + + if (GivTokenType() == ID_TRUE) var->SetValInt(1); + else var->SetValInt(0); + + pile->SetVar(var); // put on the stack + return pj->Return(pile); // forwards below +} + +void CBotExprBool::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// management of the operand "null" + +CBotExprNull::CBotExprNull() +{ + name = "CBotExprNull"; +} + +CBotExprNull::~CBotExprNull() +{ +} + +// executes, returns an empty pointer + +bool CBotExprNull::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypNullPointer); + + var->SetInit(true); // null pointer valid + pile->SetVar(var); // place on the stack + return pj->Return(pile); // forwards below +} + +void CBotExprNull::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// management of the operand "nan" + +CBotExprNan::CBotExprNan() +{ + name = "CBotExprNan"; +} + +CBotExprNan::~CBotExprNan() +{ +} + +// executes, returns null pointer + +bool CBotExprNan::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); + + if (pile->IfStep()) return false; + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypInt); + + var->SetInit(IS_NAN); // nan + pile->SetVar(var); // put on the stack + return pj->Return(pile); // forward below +} + +void CBotExprNan::RestoreState(CBotStack* &pj, bool bMain) +{ + if (bMain) pj->RestoreStack(this); +} + +////////////////////////////////////////////////////////////////////////////////////// +// compile a variable name +// check that it is known on the stack +// and it has been initialized + +CBotExprVar::CBotExprVar() +{ + name = "CBotExprVar"; + m_nIdent = 0; +} + +CBotExprVar::~CBotExprVar() +{ +} + +CBotInstr* CBotExprVar::Compile(CBotToken* &p, CBotCStack* pStack, int privat) +{ + CBotToken* pDebut = p; + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(p->GivStart()); + + // is it a variable? + if (p->GivType() == TokenTypVar) + { + CBotInstr* inst = new CBotExprVar(); // create the object + + inst->SetToken(p); + + CBotVar* var; + + if (NULL != (var = pStk->FindVar(p))) // seek if known variable + { + int ident = var->GivUniqNum(); + ((CBotExprVar*)inst)->m_nIdent = ident; // identifies variable by its number + + if (ident > 0 && ident < 9000) + { + if ( var->IsPrivate(privat) && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, p); + goto err; + } + + // This is an element of the current class + // ads the equivalent of this. before + /// \TODO need to be fixed revised and fixed after adding unit + ///tests + CBotToken token("this"); + inst->SetToken(&token); + ((CBotExprVar*)inst)->m_nIdent = -2; // identificator for this + + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(p); // keeps the name of the token + i->SetUniqNum(ident); + inst->AddNext3(i); // added after + } + + p = p->GivNext(); // next token + + while (true) + { + if (var->GivType() == CBotTypArrayPointer) + { + if (IsOfType( p, ID_OPBRK )) // check if there is an aindex + { + CBotIndexExpr* i = new CBotIndexExpr(); + i->m_expr = CBotExpression::Compile(p, pStk); // compile the formula + inst->AddNext3(i); // add to the chain + + var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0] + + if (i->m_expr == NULL) + { + pStk->SetError(TX_BADINDEX, p->GivStart()); + goto err; + } + if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto err; + } + continue; + } + } + if (var->GivType(1) == CBotTypPointer) // for classes + { + if (IsOfType(p, ID_DOT)) + { + CBotToken* pp = p; + + if (p->GivType() == TokenTypVar) // must be a name + { + if (p->GivNext()->GivType() == ID_OPENPAR) // a method call? + { + CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var); + if (!pStk->IsOk()) goto err; + inst->AddNext3(i); // added after + return pStack->Return(inst, pStk); + } + else + { + CBotFieldExpr* i = new CBotFieldExpr(); // new element + i->SetToken(pp); // keeps the name of the token + inst->AddNext3(i); // add after + var = var->GivItem(p->GivString()); // get item correspondent + if (var != NULL) + { + i->SetUniqNum(var->GivUniqNum()); + if ( var->IsPrivate() && + !pStk->GivBotCall()->m_bCompileClass) + { + pStk->SetError(TX_PRIVATE, pp); + goto err; + } + } + } + + + if (var != NULL) + { + p = p->GivNext(); // skips the name + continue; + } + pStk->SetError(TX_NOITEM, p); + goto err; + } + pStk->SetError(TX_DOT, p->GivStart()); + goto err; + } + } + + break; + } + + pStk->SetCopyVar(var); // place the copy of the variable on the stack (for type) + if (pStk->IsOk()) return pStack->Return(inst, pStk); + } + pStk->SetError(TX_UNDEFVAR, p); +err: + delete inst; + return pStack->Return(NULL, pStk); + } + + return pStack->Return(NULL, pStk); +} + +CBotInstr* CBotExprVar::CompileMethode(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + CBotCStack* pStk = pStack->TokenStack(); + + pStk->SetStartError(pp->GivStart()); + + // is it a variable ? + if (pp->GivType() == TokenTypVar) + { + CBotToken pthis("this"); + CBotVar* var = pStk->FindVar(pthis); + if (var == 0) return pStack->Return(NULL, pStk); + + CBotInstr* inst = new CBotExprVar(); + + // this is an element of the current class + // adds the equivalent of this. before + + inst->SetToken(&pthis); + ((CBotExprVar*)inst)->m_nIdent = -2; // ident for this + + CBotToken* pp = p; + + if (pp->GivType() == TokenTypVar) + { + if (pp->GivNext()->GivType() == ID_OPENPAR) // a method call? + { + CBotInstr* i = CBotInstrMethode::Compile(pp, pStk, var); + if (pStk->IsOk()) + { + inst->AddNext3(i); // add after + p = pp; // previous instruction + return pStack->Return(inst, pStk); + } + pStk->SetError(0,0); // the error is not adressed here + } + } + delete inst; + } + return pStack->Return(NULL, pStk); +} + + +// execute, making the value of a variable + +bool CBotExprVar::Execute(CBotStack* &pj) +{ + CBotVar* pVar = NULL; + CBotStack* pile = pj->AddStack(this); + + CBotStack* pile1 = pile; + + if (pile1->GivState() == 0) + { + if (!ExecuteVar(pVar, pile, NULL, true)) return false; // Get the variable fields and indexes according + + if (pVar) pile1->SetCopyVar(pVar); // place a copy on the stack + else + { + return pj->Return(pile1); + } + pile1->IncState(); + } + + pVar = pile1->GivVar(); + + if (pVar == NULL) + { + return pj->Return(pile1); + } + + if (pVar->GivInit() == IS_UNDEF) + { + CBotToken* pt = &m_token; + while (pt->GivNext() != NULL) pt = pt->GivNext(); + pile1->SetError(TX_NOTINIT, pt); + return pj->Return(pile1); + } + return pj->Return(pile1); // operation completed +} + +void CBotExprVar::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); + if (pile == NULL) return; + + CBotStack* pile1 = pile; + + if (pile1->GivState() == 0) + { + RestoreStateVar(pile, bMain); // retrieves the variable fields and indexes according + return; + } +} + +// fetch a variable at runtime + +bool CBotExprVar::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep) +{ + CBotStack* pile = pj; + pj = pj->AddStack(this); + + if (bStep && m_nIdent>0 && pj->IfStep()) return false; + + pVar = pj->FindVar(m_nIdent, true); // tries with the variable update if necessary + if (pVar == NULL) + { +#ifdef _DEBUG + ASM_TRAP(); +#endif + pj->SetError(1, &m_token); + return false; + } + if ( m_next3 != NULL && + !m_next3->ExecuteVar(pVar, pj, &m_token, bStep, false) ) + return false; // field of an instance, table, methode + + return pile->ReturnKeep(pj); // does not put on stack but get the result if a method was called +} + + +// fetch variable at runtime + +void CBotExprVar::RestoreStateVar(CBotStack* &pj, bool bMain) +{ + pj = pj->RestoreStack(this); + if (pj == NULL) return; + + if (m_next3 != NULL) + m_next3->RestoreStateVar(pj, bMain); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// compile a list of parameters + +CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars) +{ + bool first = true; + CBotInstr* ret = NULL; // to return to the list + + CBotCStack* pile = pStack; + int i = 0; + + if (IsOfType(p, ID_OPENPAR)) + { + int start, end; + if (!IsOfType(p, ID_CLOSEPAR)) while (true) + { + start = p->GivStart(); + pile = pile->TokenStack(); // keeps the result on the stack + + if (first) pStack->SetStartError(start); + first = false; + + CBotInstr* param = CBotExpression::Compile(p, pile); + end = p->GivStart(); + + if (!pile->IsOk()) + { + return pStack->Return(NULL, pile); + } + + if (ret == NULL) ret = param; + else ret->AddNext(param); // construct the list + + if (param != NULL) + { + if (pile->GivTypResult().Eq(99)) + { + delete pStack->TokenStack(); + pStack->SetError(TX_VOID, p->GivStart()); + return NULL; + } + ppVars[i] = pile->GivVar(); + ppVars[i]->GivToken()->SetPos(start, end); + i++; + + if (IsOfType(p, ID_COMMA)) continue; // skips the comma + if (IsOfType(p, ID_CLOSEPAR)) break; + } + + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + delete pStack->TokenStack(); + return NULL; + } + } + ppVars[i] = NULL; + return ret; +} + +////////////////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// compile a method call + +CBotInstrMethode::CBotInstrMethode() +{ + m_Parameters = NULL; + m_MethodeIdent = 0; + name = "CBotInstrMethode"; +} + +CBotInstrMethode::~CBotInstrMethode() +{ + delete m_Parameters; +} + +CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var) +{ + CBotInstrMethode* inst = new CBotInstrMethode(); + inst->SetToken(p); // corresponding token + + if (NULL != var) + { + CBotToken* pp = p; + p = p->GivNext(); + + if (p->GivType() == ID_OPENPAR) + { + inst->m_NomMethod = pp->GivString(); + + // compiles the list of parameters + CBotVar* ppVars[1000]; + inst->m_Parameters = CompileParams(p, pStack, ppVars); + + if (pStack->IsOk()) + { + CBotClass* pClass = var->GivClass(); // pointer to the class + inst->m_ClassName = pClass->GivName(); // name of the class + CBotTypResult r = pClass->CompileMethode(inst->m_NomMethod, var, ppVars, + pStack, inst->m_MethodeIdent); + delete pStack->TokenStack(); // release parameters on the stack + inst->m_typRes = r; + + if (inst->m_typRes.GivType() > 20) + { + pStack->SetError(inst->m_typRes.GivType(), pp); + delete inst; + return NULL; + } + // put the result on the stack to have something + if (inst->m_typRes.GivType() > 0) + { + CBotVar* pResult = CBotVar::Create("", inst->m_typRes); + if (inst->m_typRes.Eq(CBotTypClass)) + { + pResult->SetClass(inst->m_typRes.GivClass()); + } + pStack->SetVar(pResult); + } + return inst; + } + delete inst; + return NULL; + } + } + pStack->SetError(1234, p); + delete inst; + return NULL; +} + +// execute the method call + +bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend) +{ + CBotVar* ppVars[1000]; + CBotStack* pile1 = pj->AddStack(this, true); // a place for the copy of This + + if (pVar->GivPointer() == NULL) + { + pj->SetError(TX_NULLPT, prevToken); + } + + if (pile1->IfStep()) return false; + + CBotStack* pile2 = pile1->AddStack(); // for the next parameters + + if ( pile1->GivState() == 0) + { + CBotVar* pThis = CBotVar::Create(pVar); + pThis->Copy(pVar); + // this value should be taken before the evaluation parameters + // Test.Action (Test = Other); + // action must act on the value before test = Other! + + pThis->SetName("this"); + pThis->SetUniqNum(-2); + pile1->AddVar(pThis); + pile1->IncState(); + } + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + if (pile2->GivState() == 0) + { + if (!p->Execute(pile2)) return false; // interrupted here? + if (!pile2->SetState(1)) return false; // special mark to recognize parameters + } + ppVars[i++] = pile2->GivVar(); // construct the list of pointers + pile2 = pile2->AddStack(); // space on the stack for the result + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotClass* pClass = CBotClass::Find(m_ClassName); + CBotVar* pThis = pile1->FindVar(-2); + CBotVar* pResult = NULL; + if (m_typRes.GivType() > 0) pResult = CBotVar::Create("", m_typRes); + if (m_typRes.Eq(CBotTypClass)) + { + pResult->SetClass(m_typRes.GivClass()); + } + CBotVar* pRes = pResult; + + if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod, + pThis, ppVars, + pResult, pile2, GivToken())) return false; + if (pRes != pResult) delete pRes; + + pVar = NULL; // does not return value for this + return pj->Return(pile2); // release the entire stack +} + +void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain) +{ + if (!bMain) return; + + CBotVar* ppVars[1000]; + CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This + if (pile1 == NULL) return; + + CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming + if (pile2 == NULL) return; + + CBotVar* pThis = pile1->FindVar("this"); + pThis->SetUniqNum(-2); + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + if (pile2->GivState() == 0) + { + p->RestoreState(pile2, true); // interrupted here! + return; + } + ppVars[i++] = pile2->GivVar(); // construct the list of pointers + pile2 = pile2->RestoreStack(); + if (pile2 == NULL) return; + + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotClass* pClass = CBotClass::Find(m_ClassName); + CBotVar* pResult = NULL; + + CBotVar* pRes = pResult; + + pClass->RestoreMethode(m_MethodeIdent, m_NomMethod, + pThis, ppVars, pile2); +} + + +bool CBotInstrMethode::Execute(CBotStack* &pj) +{ + CBotVar* ppVars[1000]; + CBotStack* pile1 = pj->AddStack(this, true); // place for the copy of This + + if (pile1->IfStep()) return false; + + CBotStack* pile2 = pile1->AddStack(); // and for the parameters coming + + if ( pile1->GivState() == 0) + { + CBotVar* pThis = pile1->CopyVar(m_token); + // this value should be taken before the evaluation parameters + // Test.Action (Test = Other); + // Action must act on the value before test = Other! + pThis->SetName("this"); + pile1->AddVar(pThis); + pile1->IncState(); + } + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + if (p != NULL) while ( true) + { + if (pile2->GivState() == 0) + { + if (!p->Execute(pile2)) return false; // interrupted here? + if (!pile2->SetState(1)) return false; // special mark to recognize parameters + } + ppVars[i++] = pile2->GivVar(); // construct the list of pointers + pile2 = pile2->AddStack(); // space on the stack for the results + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotClass* pClass = CBotClass::Find(m_ClassName); + CBotVar* pThis = pile1->FindVar("this"); + CBotVar* pResult = NULL; + if (m_typRes.GivType()>0) pResult = CBotVar::Create("", m_typRes); + if (m_typRes.Eq(CBotTypClass)) + { + pResult->SetClass(m_typRes.GivClass()); + } + CBotVar* pRes = pResult; + + if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod, + pThis, ppVars, + pResult, pile2, GivToken())) return false; // interupted + + // set the new value of this in place of the old variable + CBotVar* old = pile1->FindVar(m_token); + old->Copy(pThis, false); + + if (pRes != pResult) delete pRes; + + return pj->Return(pile2); // release the entire stack +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compile an instruction "new" + +CBotNew::CBotNew() +{ + name = "CBotNew"; + m_Parameters = NULL; + m_nMethodeIdent = 0; +} + +CBotNew::~CBotNew() +{ +} + +CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + if (!IsOfType(p, ID_NEW)) return NULL; + + // verifies that the token is a class name + if (p->GivType() != TokenTypVar) return NULL; + + CBotClass* pClass = CBotClass::Find(p); + if (pClass == NULL) + { + pStack->SetError(TX_BADNEW, p); + return NULL; + } + + CBotNew* inst = new CBotNew(); + inst->SetToken(pp); + + inst->m_vartoken = p; + p = p->GivNext(); + + // creates the object on the "job" + // with a pointer to the object + CBotVar* pVar = CBotVar::Create("", pClass); + + // do the call of the creator + CBotCStack* pStk = pStack->TokenStack(); + { + // check if there are parameters + CBotVar* ppVars[1000]; + inst->m_Parameters = CompileParams(p, pStk, ppVars); + if (!pStk->IsOk()) goto error; + + // constructor exist? + CBotTypResult r = pClass->CompileMethode(pClass->GivName(), pVar, ppVars, pStk, inst->m_nMethodeIdent); + delete pStk->TokenStack(); // release extra stack + int typ = r.GivType(); + + // if there is no constructor, and no parameters either, it's ok + if (typ == TX_UNDEFCALL && inst->m_Parameters == NULL) typ = 0; + pVar->SetInit(true); // mark the instance as init + + if (typ>20) + { + pStk->SetError(typ, inst->m_vartoken.GivEnd()); + goto error; + } + + // if the constructor does not exist, but there are parameters + if (typ<0 && inst->m_Parameters != NULL) + { + pStk->SetError(TX_NOCONST, &inst->m_vartoken); + goto error; + } + + // makes pointer to the object on the stack + pStk->SetVar(pVar); + return pStack->Return(inst, pStk); + } +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// executes instruction "new" + +bool CBotNew::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); //main stack + + if (pile->IfStep()) return false; + + CBotStack* pile1 = pj->AddStack2(); //secondary stack + + CBotVar* pThis = NULL; + + CBotToken* pt = &m_vartoken; + CBotClass* pClass = CBotClass::Find(pt); + + // create the variable "this" pointer type to the stack + + if ( pile->GivState()==0) + { + // create an instance of the requested class + // and initialize the pointer to that object + + + pThis = CBotVar::Create("this", pClass); + pThis->SetUniqNum(-2) ; + + pile1->SetVar(pThis); // place on stack1 + pile->IncState(); + } + + // fetch the this pointer if it was interrupted + if ( pThis == NULL) + { + pThis = pile1->GivVar(); // find the pointer + } + + // is there an assignment or parameters (constructor) + if ( pile->GivState()==1) + { + // evaluates the constructor of the instance + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + pile2 = pile2->AddStack(); // space on the stack for the result + if (pile2->GivState() == 0) + { + if (!p->Execute(pile2)) return false; // interrupted here? + pile2->SetState(1); + } + ppVars[i++] = pile2->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + // create a variable for the result + CBotVar* pResult = NULL; // constructos still void + + if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(), + pThis, ppVars, + pResult, pile2, GivToken())) return false; // interrupt + + pThis->ConstructorSet(); // indicates that the constructor has been called + } + + return pj->Return(pile1); // passes below +} + +void CBotNew::RestoreState(CBotStack* &pj, bool bMain) +{ + if (!bMain) return; + + CBotStack* pile = pj->RestoreStack(this); //primary stack + if (pile == NULL) return; + + CBotStack* pile1 = pj->AddStack2(); //secondary stack + + CBotToken* pt = &m_vartoken; + CBotClass* pClass = CBotClass::Find(pt); + + // create the variable "this" pointer type to the object + + if ( pile->GivState()==0) + { + return; + } + + CBotVar* pThis = pile1->GivVar(); // find the pointer + pThis->SetUniqNum(-2); + + // is ther an assignment or parameters (constructor) + if ( pile->GivState()==1) + { + // evaluates the constructor of the instance + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluate the parameters + // and places the values on the stack + // to be interrupted at any time + + if (p != NULL) while ( true) + { + pile2 = pile2->RestoreStack(); // space on the stack for the result + if (pile2 == NULL) return; + + if (pile2->GivState() == 0) + { + p->RestoreState(pile2, bMain); // interrupt here! + return; + } + ppVars[i++] = pile2->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GivString(), pThis, + ppVars, pile2) ; // interrupt here! + } +} + +///////////////////////////////////////////////////////////// +// check if two results are consistent to make an operation + +bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op) +{ + int t1 = type1.GivType(); + int t2 = type2.GivType(); + + int max = (t1 > t2) ? t1 : t2; + + if (max == 99) return false; // result is void? + + // special case for strin concatenation + if (op == ID_ADD && max >= CBotTypString) return true; + if (op == ID_ASSADD && max >= CBotTypString) return true; + if (op == ID_ASS && t1 == CBotTypString) return true; + + if (max >= CBotTypBoolean) + { + if ( (op == ID_EQ || op == ID_NE) && + (t1 == CBotTypPointer && t2 == CBotTypNullPointer)) return true; + if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && + (t2 == CBotTypPointer && t1 == CBotTypNullPointer)) return true; + if ( (op == ID_EQ || op == ID_NE) && + (t1 == CBotTypArrayPointer && t2 == CBotTypNullPointer)) return true; + if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && + (t2 == CBotTypArrayPointer && t1 == CBotTypNullPointer)) return true; + if (t2 != t1) return false; + if (t1 == CBotTypArrayPointer) return type1.Compare(type2); + if (t1 == CBotTypPointer || + t1 == CBotTypClass || + t1 == CBotTypIntrinsic ) + { + CBotClass* c1 = type1.GivClass(); + CBotClass* c2 = type2.GivClass(); + + return c1->IsChildOf(c2) || c2->IsChildOf(c1); + // accept the case in reverse + // the transaction will be denied at runtime if the pointer is not + // compatible + } + + return true; + } + + type1.SetType(max); + type2.SetType(max); + return true; +} + +// check if two variables are compatible for parameter passing + +bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2) +{ + int t1 = type1.GivType(); + int t2 = type2.GivType(); + + if (t1 == CBotTypIntrinsic) t1 = CBotTypClass; + if (t2 == CBotTypIntrinsic) t2 = CBotTypClass; + + int max = (t1 > t2) ? t1 : t2; + + if (max == 99) return false; // result is void? + + if (max >= CBotTypBoolean) + { + if (t2 != t1) return false; + + if (max == CBotTypArrayPointer) + return TypesCompatibles(type1.GivTypElem(), type2.GivTypElem()); + + if (max == CBotTypClass || max == CBotTypPointer) + return type1.GivClass() == type2.GivClass() ; + + return true ; + } + return true; +} + + +///////////////////////////////////////////////////////////////////////////////////// +// file management + +// necessary because it is not possible to do the fopen in the main program +// fwrite and fread in a dll or using the FILE * returned. + + +FILE* fOpen(const char* name, const char* mode) +{ + return fopen(name, mode); +} + +int fClose(FILE* filehandle) +{ + return fclose(filehandle); +} + +size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle) +{ + return fwrite(buffer, elemsize, length, filehandle); +} + +size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle) +{ + return fread(buffer, elemsize, length, filehandle); +} + +size_t fWrite(const void *buffer, size_t length, FILE* filehandle) +{ + return fwrite(buffer, 1, length, filehandle); +} + +size_t fRead(void *buffer, size_t length, FILE* filehandle) +{ + return fread(buffer, 1, length, filehandle); +} + + +//////////////////////////////////////// + diff --git a/src/CBot/CBot.h b/src/CBot/CBot.h index 3b7d7e8..ebc8e52 100644 --- a/src/CBot/CBot.h +++ b/src/CBot/CBot.h @@ -1,1733 +1,1732 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.////////////////////////////////////////////////////////////////////
-/**
- * \file CBot.h
- * \brief Interpreter of the language CBot for COLOBOT game
- */
-
-
-
-#include "resource.h"
-#include "CBotDll.h" // public definitions
-#include "CBotToken.h" // token management
-
-#define STACKRUN true /// \def return execution directly on a suspended routine
-#define STACKMEM true /// \def preserve memory for the execution stack
-#define MAXSTACK 990 /// \def stack size reserved
-
-#define EOX (CBotStack*)-1 /// \def tag special condition
-
-
-// fix for MSVC instruction __asm int 3 (setting a trap)
-#if defined(__MINGW32__) || defined(__GNUC__)
-#define ASM_TRAP() asm("int $3");
-#else
-#define ASM_TRAP() __asm int 3;
-#endif
-
-/////////////////////////////////////////////////////////////////////
-// forward declaration
-
-class CBotCompExpr; // an expression like
- // () <= ()
-class CBotAddExpr; // an expression like
- // () + ()
-class CBotParExpr; // basic type or instruction in parenthesis
- // Toto.truc
- // 12.5
- // "string"
- // ( expression )
-class CBotExprVar; // a variable name as
- // Toto
- // chose.truc.machin
-class CBotWhile; // while (...) {...};
-class CBotIf; // if (...) {...} else {...}
-class CBotDefParam; // paramerer list of a function
-class CBotRepeat; // repeat (nb) {...}
-
-
-
-////////////////////////////////////////////////////////////////////////
-// Management of the execution stack
-////////////////////////////////////////////////////////////////////////
-
-// actually, externally, the only thing he can do
-// is to create an instance of a stack
-// to use for routine CBotProgram :: Execute (CBotStack)
-
-
-/**\class CBotStack
- * \brief Management of the execution stack.
- * \brief Actually the only thing it can do is to create an instance of a stack
- * \brief to use for routine CBotProgram :: Execute(CBotStack)*/
-class CBotStack
-{
-public:
-#if STACKMEM
- /**
- * \brief FirstStack Allocate first stack
- * \return pointer to created stack
- */
- static CBotStack * FirstStack();
-
- /** \brief Delete Remove current stack */
- void Delete();
-#endif
-
- /**
- * \brief CBotStack Constructor of the stack
- * \param ppapa Not used.
- */
- CBotStack(CBotStack* ppapa);
-
-
- /** \brief ~CBotStack Destructor */
- ~CBotStack();
-
- /**
- * \brief StackOver Check if end of stack is reached
- * \return true if end of stack
- */
- bool StackOver();
-
- /**
- * \brief GivError Get error number of the stack
- * \param [out] start beginning of the stack
- * \param [out] end end of stack
- * \return error number
- */
- int GivError(int& start, int& end);
-
- /**
- * \brief GivError Get error number
- * \return eror number
- */
- int GivError();// rend le numéro d'erreur retourné
-
- /**
- * \brief Reset Reset error at and set user
- * \param [in] pUser User of stack
- */
- void Reset(void* pUser);
-
- /**
- * \brief SetType Determines the type.
- * \param type Type of instruction on the stack.
- */
- void SetType(CBotTypResult& type);
-
- /**
- * \brief GivType Get the type of value on the stack.
- * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic).
- * \return Type number.
- */
- int GivType(int mode = 0);
-
- /**
- * \brief Gives the type of complete value on the stack.
- * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic).
- * \return Type of an element.
- */
- CBotTypResult GivTypResult(int mode = 0);
-
- /**
- * \brief Adds a local variable.
- * \param [in] p Variable to be added.
- */
- void AddVar(CBotVar* p);
-
- /**
- * \brief Fetch a variable by its token.
- * \brief This may be a composite variable
- * \param [in] pToken Token upon which search is performed
- * \param [in] bUpdate Not used. Probably need to be removed
- * \param [in] bModif Not used. Probably need to be removed
- * \return Found variable
- */
- CBotVar* FindVar(CBotToken* &pToken, bool bUpdate = false,
- bool bModif = false);
-
- /**
- * \brief Fetch a variable by its token.
- * \brief This may be a composite variable
- * \param [in] pToken Token upon which search is performed
- * \param [in] bUpdate Not used. Probably need to be removed
- * \param [in] bModif Not used. Probably need to be removed
- * \return Found variable
- */
- CBotVar* FindVar(CBotToken& Token, bool bUpdate = false,
- bool bModif = false);
-
- /**
- * \brief Fetch variable by its name
- * \param [in] name Name of variable to find
- * \return Found variable
- */
- CBotVar* FindVar(const char* name);
-
- /**
- * \brief Fetch a variable on the stack according to its identification number
- * \brief This is faster than comparing names
- * \param [in] ident Identifier of a variable
- * \param [in] bUpdate Not used. Probably need to be removed
- * \param [in] bModif Not used. Probably need to be removed
- * \return Found variable
- */
- CBotVar* FindVar(long ident, bool bUpdate = false,
- bool bModif = false);
-
- /**
- * \brief Find variable by its token and returns a copy of it.
- * \param Token Token upon which search is performed
- * \param bUpdate Not used.
- * \return Found variable, NULL if not found
- */
- CBotVar* CopyVar(CBotToken& Token, bool bUpdate = false);
-
-
- CBotStack* AddStack(CBotInstr* instr = NULL, bool bBlock = false); // étend le stack
- CBotStack* AddStackEOX(CBotCall* instr = NULL, bool bBlock = false); // étend le stack
- CBotStack* RestoreStack(CBotInstr* instr = NULL);
- CBotStack* RestoreStackEOX(CBotCall* instr = NULL);
-
- CBotStack* AddStack2(bool bBlock = false); // étend le stack
- bool Return(CBotStack* pFils); // transmet le résultat au dessus
- bool ReturnKeep(CBotStack* pFils); // transmet le résultat sans réduire la pile
- bool BreakReturn(CBotStack* pfils, const char* name = NULL);
- // en cas de break éventuel
- bool IfContinue(int state, const char* name);
- // ou de "continue"
-
- bool IsOk();
-
- bool SetState(int n, int lim = -10); // sélectionne un état
- int GivState(); // dans quel état j'ère ?
- bool IncState(int lim = -10); // passe à l'état suivant
- bool IfStep(); // faire du pas à pas ?
- bool Execute();
-
- void SetVar( CBotVar* var );
- void SetCopyVar( CBotVar* var );
- CBotVar* GivVar();
- CBotVar* GivCopyVar();
- CBotVar* GivPtVar();
- bool GivRetVar(bool bRet);
- long GivVal();
-
- void SetStartError(int pos);
- void SetError(int n, CBotToken* token = NULL);
- void SetPosError(CBotToken* token);
- void ResetError(int n, int start, int end);
- void SetBreak(int val, const char* name);
-
- void SetBotCall(CBotProgram* p);
- CBotProgram* GivBotCall(bool bFirst = false);
- void* GivPUser();
- bool GivBlock();
-
-
- bool ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype);
- void RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar);
-
- bool SaveState(FILE* pf);
- bool RestoreState(FILE* pf, CBotStack* &pStack);
-
- static
- void SetTimer(int n);
-
- void GetRunPos(const char* &FunctionName, int &start, int &end);
- CBotVar* GivStackVars(const char* &FunctionName, int level);
-
- int m_temp;
-
-private:
- CBotStack* m_next;
- CBotStack* m_next2;
- CBotStack* m_prev;
- friend class CBotInstArray;
-
-#ifdef _DEBUG
- int m_index;
-#endif
- int m_state;
- int m_step;
- static int m_error;
- static int m_start;
- static int m_end;
- static
- CBotVar* m_retvar; // résultat d'un return
-
- CBotVar* m_var; // résultat des opérations
- CBotVar* m_listVar; // les variables déclarées à ce niveau
-
- bool m_bBlock; // fait partie d'un bloc (variables sont locales à ce bloc)
- bool m_bOver; // limites de la pile ?
-// bool m_bDontDelete; // spécial, ne pas détruire les variables au delete
- CBotProgram* m_prog; // les fonctions définies par user
-
- static
- int m_initimer;
- static
- int m_timer;
- static
- CBotString m_labelBreak;
- static
- void* m_pUser;
-
- CBotInstr* m_instr; // l'instruction correspondante
- bool m_bFunc; // une entrée d'une fonction ?
- CBotCall* m_call; // point de reprise dans un call extern
- friend class CBotTry;
-};
-
-// les routines inline doivent être déclarées dans le fichier .h
-
-inline bool CBotStack::IsOk()
-{
- return (m_error == 0);
-}
-
-inline int CBotStack::GivState()
-{
- return m_state;
-}
-
-inline int CBotStack::GivError()
-{
- return m_error;
-}
-
-////////////////////////////////////////////////////////////////////////
-// Gestion de la pile de compilation
-////////////////////////////////////////////////////////////////////////
-
-
-class CBotCStack
-{
-private:
- CBotCStack* m_next;
- CBotCStack* m_prev;
-
- static
- int m_error;
- static
- int m_end;
- int m_start;
-
- CBotVar* m_var; // résultat des opérations
-
- bool m_bBlock; // fait partie d'un bloc (variables sont locales à ce bloc)
- CBotVar* m_listVar;
-
- static
- CBotProgram* m_prog; // liste des fonctions compilées
- static
- CBotTypResult m_retTyp;
-// static
-// CBotToken* m_retClass;
-
-public:
- CBotCStack(CBotCStack* ppapa);
- ~CBotCStack();
-
- bool IsOk();
- int GivError();
- int GivError(int& start, int& end);
- // rend le numéro d'erreur retourné
-
- void SetType(CBotTypResult& type);// détermine le type
- CBotTypResult GivTypResult(int mode = 0); // donne le type de valeur sur le stack
- int GivType(int mode = 0); // donne le type de valeur sur le stack
- CBotClass* GivClass(); // donne la classe de la valeur sur le stack
-
- void AddVar(CBotVar* p); // ajoute une variable locale
- CBotVar* FindVar(CBotToken* &p); // trouve une variable
- CBotVar* FindVar(CBotToken& Token);
- bool CheckVarLocal(CBotToken* &pToken);
- CBotVar* CopyVar(CBotToken& Token); // trouve et rend une copie
-
- CBotCStack* TokenStack(CBotToken* pToken = NULL, bool bBlock = false);
- CBotInstr* Return(CBotInstr* p, CBotCStack* pParent); // transmet le résultat au dessus
- CBotFunction* ReturnFunc(CBotFunction* p, CBotCStack* pParent); // transmet le résultat au dessus
-
- void SetVar( CBotVar* var );
- void SetCopyVar( CBotVar* var );
- CBotVar* GivVar();
-
- void SetStartError(int pos);
- void SetError(int n, int pos);
- void SetError(int n, CBotToken* p);
- void ResetError(int n, int start, int end);
-
- void SetRetType(CBotTypResult& type);
- CBotTypResult GivRetType();
-
-// void SetBotCall(CBotFunction* &pFunc);
- void SetBotCall(CBotProgram* p);
- CBotProgram* GivBotCall();
- CBotTypResult CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent);
- bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
-
- bool NextToken(CBotToken* &p);
-};
-
-
-extern bool SaveVar(FILE* pf, CBotVar* pVar);
-
-
-/////////////////////////////////////////////////////////////////////
-// classes defining an instruction
-class CBotInstr
-{
-private:
- static
- CBotStringArray
- m_labelLvl;
-protected:
- CBotToken m_token; // keeps the token
- CBotString name; // debug
- CBotInstr* m_next; // linked command
- CBotInstr* m_next2b; // second list definition chain
- CBotInstr* m_next3; // third list for indices and fields
- CBotInstr* m_next3b; // necessary for reporting tables
-/*
- for example, the following program
- int x[]; x[1] = 4;
- int y[x[1]][10], z;
- is generated
- CBotInstrArray
- m_next3b-> CBotEmpty
- m_next->
- CBotExpression ....
- m_next->
- CBotInstrArray
- m_next3b-> CBotExpression ('x') ( m_next3-> CBotIndexExpr ('1') )
- m_next3b-> CBotExpression ('10')
- m_next2-> 'z'
- m_next->...
-
-*/
-
- static
- int m_LoopLvl;
- friend class CBotClassInst;
- friend class CBotInt;
- friend class CBotListArray;
-
-public:
- CBotInstr();
- virtual
- ~CBotInstr();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- static
- CBotInstr* CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first = true);
-
- virtual
- bool Execute(CBotStack* &pj);
- virtual
- bool Execute(CBotStack* &pj, CBotVar* pVar);
- virtual
- void RestoreState(CBotStack* &pj, bool bMain);
-
- virtual
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- virtual
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
- virtual
- void RestoreStateVar(CBotStack* &pile, bool bMain);
-
- virtual
- bool CompCase(CBotStack* &pj, int val);
-
- void SetToken(CBotToken* p);
- int GivTokenType();
- CBotToken* GivToken();
-
- void AddNext(CBotInstr* n);
- CBotInstr* GivNext();
- void AddNext3(CBotInstr* n);
- CBotInstr* GivNext3();
- void AddNext3b(CBotInstr* n);
- CBotInstr* GivNext3b();
-
- static
- void IncLvl(CBotString& label);
- static
- void IncLvl();
- static
- void DecLvl();
- static
- bool ChkLvl(const CBotString& label, int type);
-
- bool IsOfClass(CBotString name);
-};
-
-class CBotWhile : public CBotInstr
-{
-private:
- CBotInstr* m_Condition; // la condition
- CBotInstr* m_Block; // les instructions
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotWhile();
- ~CBotWhile();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotRepeat : public CBotInstr
-{
-private:
- /// Number of iterations
- CBotInstr* m_NbIter;
-
- /// Instructions
- CBotInstr* m_Block;
-
- /// Label
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotRepeat();
- ~CBotRepeat();
-
- /// Static method used for compilation
- static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-
- /// Execute
- bool Execute(CBotStack* &pj);
-
- /// Restore state
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotDo : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_Condition; // la condition
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotDo();
- ~CBotDo();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotFor : public CBotInstr
-{
-private:
- CBotInstr* m_Init; // intruction initiale
- CBotInstr* m_Test; // la condition de test
- CBotInstr* m_Incr; // instruction pour l'incrément
- CBotInstr* m_Block; // les instructions
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotFor();
- ~CBotFor();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotBreak : public CBotInstr
-{
-private:
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotBreak();
- ~CBotBreak();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotReturn : public CBotInstr
-{
-private:
- CBotInstr* m_Instr; // le paramètre à retourner
-
-public:
- CBotReturn();
- ~CBotReturn();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotSwitch : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // value à chercher
- CBotInstr* m_Block; // les instructions
-
-public:
- CBotSwitch();
- ~CBotSwitch();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotCase : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // valeur à comparer
-
-public:
- CBotCase();
- ~CBotCase();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
- bool CompCase(CBotStack* &pj, int val);
-};
-
-class CBotCatch : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_Cond; // la condition
- CBotCatch* m_next; // le catch suivant
- friend class CBotTry;
-
-public:
- CBotCatch();
- ~CBotCatch();
- static
- CBotCatch* Compile(CBotToken* &p, CBotCStack* pStack);
- bool TestCatch(CBotStack* &pj, int val);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
- void RestoreCondState(CBotStack* &pj, bool bMain);
-};
-
-class CBotTry : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotCatch* m_ListCatch; // les catches
- CBotInstr* m_FinalInst; // instruction finale
-
-public:
- CBotTry();
- ~CBotTry();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotThrow : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // la valeur à envoyer
-
-public:
- CBotThrow();
- ~CBotThrow();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotStartDebugDD : public CBotInstr
-{
-private:
-
-public:
- CBotStartDebugDD();
- ~CBotStartDebugDD();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
-};
-
-
-class CBotIf : public CBotInstr
-{
-private:
- CBotInstr* m_Condition; // la condition
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_BlockElse; // les instructions
-
-public:
- CBotIf();
- ~CBotIf();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-// définition d'un nombre entier
-
-class CBotInt : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-/// CBotInstr* m_next; // plusieurs définitions enchaînées
-
-public:
- CBotInt();
- ~CBotInt();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un tableau
-
-class CBotInstArray : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_listass; // liste d'assignations pour le tableau
- CBotTypResult
- m_typevar; // type d'éléments
-// CBotString m_ClassName;
-
-public:
- CBotInstArray();
- ~CBotInstArray();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-// définition d'une liste d'assignation pour un tableau
-// int [ ] a [ ] = ( ( 1, 2, 3 ) , ( 3, 2, 1 ) ) ;
-
-class CBotListArray : public CBotInstr
-{
-private:
- CBotInstr* m_expr; // expression pour un élément
- // les autres sont chaînés avec CBotInstr::m_next3;
-public:
- CBotListArray();
- ~CBotListArray();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
- bool Execute(CBotStack* &pj, CBotVar* pVar);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotEmpty : public CBotInstr
-{
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un booléen
-
-class CBotBoolean : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotBoolean();
- ~CBotBoolean();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-// définition d'un nombre réel
-
-class CBotFloat : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotFloat();
- ~CBotFloat();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un elément string
-
-class CBotIString : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotIString();
- ~CBotIString();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// définition d'un elément dans une classe quelconque
-
-class CBotClassInst : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotClass* m_pClass; // référence à la classe
- CBotInstr* m_Parameters; // les paramètres à évaluer pour le constructeur
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
- bool m_hasParams; // il y a des paramètres ?
- long m_nMethodeIdent;
-
-public:
- CBotClassInst();
- ~CBotClassInst();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass = NULL);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotCondition : public CBotInstr
-{
-private:
-
-public:
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-
-// left opérande
-// n'accepte que les expressions pouvant être à gauche d'une assignation
-
-class CBotLeftExpr : public CBotInstr
-{
-private:
- long m_nIdent;
-
-public:
- CBotLeftExpr();
- ~CBotLeftExpr();
- static
- CBotLeftExpr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack, CBotStack* array);
-
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
- void RestoreStateVar(CBotStack* &pile, bool bMain);
-};
-
-
-// gestion des champs d'une instance
-
-class CBotFieldExpr : public CBotInstr
-{
-private:
- friend class CBotExpression;
- int m_nIdent;
-
-public:
- CBotFieldExpr();
- ~CBotFieldExpr();
- void SetUniqNum(int num);
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-// gestion des index dans les tableaux
-
-class CBotIndexExpr : public CBotInstr
-{
-private:
- CBotInstr* m_expr; // expression pour le calcul de l'index
- friend class CBotLeftExpr;
- friend class CBotExprVar;
-
-public:
- CBotIndexExpr();
- ~CBotIndexExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-// une expression du genre
-// x = a;
-// x * y + 3;
-
-class CBotExpression : public CBotInstr
-{
-private:
- CBotLeftExpr* m_leftop; // élément de gauche
- CBotInstr* m_rightop; // élément de droite
-
-public:
- CBotExpression();
- ~CBotExpression();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotListExpression : public CBotInstr
-{
-private:
- CBotInstr* m_Expr; // la 1ère expression à évaluer
-
-public:
- CBotListExpression();
- ~CBotListExpression();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotLogicExpr : public CBotInstr
-{
-private:
- CBotInstr* m_condition; // test à évaluer
- CBotInstr* m_op1; // élément de gauche
- CBotInstr* m_op2; // élément de droite
- friend class CBotTwoOpExpr;
-
-public:
- CBotLogicExpr();
- ~CBotLogicExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-
-class CBotBoolExpr : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-
-
-// une expression éventuellement entre parenthèses ( ... )
-// il n'y a jamais d'instance de cette classe
-// l'objet retourné étant le contenu de la parenthése
-class CBotParExpr : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-// expression unaire
-class CBotExprUnaire : public CBotInstr
-{
-private:
- CBotInstr* m_Expr; // l'expression à évaluer
-public:
- CBotExprUnaire();
- ~CBotExprUnaire();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// toutes les opérations à 2 opérandes
-
-class CBotTwoOpExpr : public CBotInstr
-{
-private:
- CBotInstr* m_leftop; // élément de gauche
- CBotInstr* m_rightop; // élément de droite
-public:
- CBotTwoOpExpr();
- ~CBotTwoOpExpr();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = NULL);
- bool Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-
-
-// un bloc d'instructions { .... }
-class CBotBlock : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true);
- static
- CBotInstr* CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal = false);
-};
-
-
-// le contenu d'un bloc d'instructions ... ; ... ; ... ; ... ;
-class CBotListInstr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr; // les instructions à faire
-
-public:
- CBotListInstr();
- ~CBotListInstr();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotInstrCall : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
-// int m_typeRes; // type du résultat
-// CBotString m_RetClassName; // class du résultat
- CBotTypResult
- m_typRes; // type complet du résultat
- long m_nFuncIdent; // id de la fonction
-
-public:
- CBotInstrCall();
- ~CBotInstrCall();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// un appel d'une méthode
-
-class CBotInstrMethode : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
-// int m_typeRes; // type du résultat
-// CBotString m_RetClassName; // class du résultat
- CBotTypResult
- m_typRes; // type complet du résultat
-
- CBotString m_NomMethod; // nom de la méthode
- long m_MethodeIdent; // identificateur de la méthode
-// long m_nThisIdent; // identificateur pour "this"
- CBotString m_ClassName; // nom de la classe
-
-public:
- CBotInstrMethode();
- ~CBotInstrMethode();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar);
- bool Execute(CBotStack* &pj);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-// expression for the variable name
-
-class CBotExprVar : public CBotInstr
-{
-private:
- long m_nIdent;
- friend class CBotPostIncExpr;
- friend class CBotPreIncExpr;
-
-public:
- CBotExprVar();
- ~CBotExprVar();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int privat=PR_PROTECT);
- static
- CBotInstr* CompileMethode(CBotToken* &p, CBotCStack* pStack);
-
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
- bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
- bool Execute2Var(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep);
- void RestoreStateVar(CBotStack* &pj, bool bMain);
-};
-
-class CBotPostIncExpr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr;
- friend class CBotParExpr;
-
-public:
- CBotPostIncExpr();
- ~CBotPostIncExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotPreIncExpr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr;
- friend class CBotParExpr;
-
-public:
- CBotPreIncExpr();
- ~CBotPreIncExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotLeftExprVar : public CBotInstr
-{
-private:
-public:
- CBotTypResult
- m_typevar; // type de variable déclarée
- long m_nIdent; // identificateur unique pour cette variable
-
-public:
- CBotLeftExprVar();
- ~CBotLeftExprVar();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotExprBool : public CBotInstr
-{
-private:
-
-public:
- CBotExprBool();
- ~CBotExprBool();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-class CBotExprNull : public CBotInstr
-{
-private:
-
-public:
- CBotExprNull();
- ~CBotExprNull();
-
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotExprNan : public CBotInstr
-{
-private:
-
-public:
- CBotExprNan();
- ~CBotExprNan();
-
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-class CBotNew : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
- long m_nMethodeIdent;
-// long m_nThisIdent;
- CBotToken m_vartoken;
-
-public:
- CBotNew();
- ~CBotNew();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-// expression représentant un nombre
-
-class CBotExprNum : public CBotInstr
-{
-private:
- int m_numtype; // et le type de nombre
- long m_valint; // valeur pour un int
- float m_valfloat; // valeur pour un float
-
-public:
- CBotExprNum();
- ~CBotExprNum();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-
-// expression représentant une chaine de caractères
-
-class CBotExprAlpha : public CBotInstr
-{
-private:
-
-public:
- CBotExprAlpha();
- ~CBotExprAlpha();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-};
-
-
-#define MAX(a,b) ((a>b) ? a : b)
-
-
-// classe pour la gestion des nombres entier (int)
-class CBotVarInt : public CBotVar
-{
-private:
- int m_val; // la valeur
- CBotString m_defnum; // le nom si donné par DefineNum
- friend class CBotVar;
-
-public:
- CBotVarInt( const CBotToken* name );
-// ~CBotVarInt();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
-
- void Add(CBotVar* left, CBotVar* right); // addition
- void Sub(CBotVar* left, CBotVar* right); // soustraction
- void Mul(CBotVar* left, CBotVar* right); // multiplication
- int Div(CBotVar* left, CBotVar* right); // division
- int Modulo(CBotVar* left, CBotVar* right); // reste de division
- void Power(CBotVar* left, CBotVar* right); // puissance
-
- bool Lo(CBotVar* left, CBotVar* right);
- bool Hi(CBotVar* left, CBotVar* right);
- bool Ls(CBotVar* left, CBotVar* right);
- bool Hs(CBotVar* left, CBotVar* right);
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- void XOr(CBotVar* left, CBotVar* right);
- void Or(CBotVar* left, CBotVar* right);
- void And(CBotVar* left, CBotVar* right);
-
- void SL(CBotVar* left, CBotVar* right);
- void SR(CBotVar* left, CBotVar* right);
- void ASR(CBotVar* left, CBotVar* right);
-
- void Neg();
- void Not();
- void Inc();
- void Dec();
-
- bool Save0State(FILE* pf);
- bool Save1State(FILE* pf);
-
-};
-
-// classe pour la gestion des nombres réels (float)
-class CBotVarFloat : public CBotVar
-{
-private:
- float m_val; // la valeur
-
-public:
- CBotVarFloat( const CBotToken* name );
-// ~CBotVarFloat();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
-
- void Add(CBotVar* left, CBotVar* right); // addition
- void Sub(CBotVar* left, CBotVar* right); // soustraction
- void Mul(CBotVar* left, CBotVar* right); // multiplication
- int Div(CBotVar* left, CBotVar* right); // division
- int Modulo(CBotVar* left, CBotVar* right); // reste de division
- void Power(CBotVar* left, CBotVar* right); // puissance
-
- bool Lo(CBotVar* left, CBotVar* right);
- bool Hi(CBotVar* left, CBotVar* right);
- bool Ls(CBotVar* left, CBotVar* right);
- bool Hs(CBotVar* left, CBotVar* right);
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- void Neg();
- void Inc();
- void Dec();
-
- bool Save1State(FILE* pf);
-};
-
-
-// classe pour la gestion des chaînes (String)
-class CBotVarString : public CBotVar
-{
-private:
- CBotString m_val; // la valeur
-
-public:
- CBotVarString( const CBotToken* name );
-// ~CBotVarString();
-
- void SetValString(const char* p);
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
- void Add(CBotVar* left, CBotVar* right); // addition
-
- bool Lo(CBotVar* left, CBotVar* right);
- bool Hi(CBotVar* left, CBotVar* right);
- bool Ls(CBotVar* left, CBotVar* right);
- bool Hs(CBotVar* left, CBotVar* right);
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- bool Save1State(FILE* pf);
-};
-
-// classe pour la gestion des boolean
-class CBotVarBoolean : public CBotVar
-{
-private:
- bool m_val; // la valeur
-
-public:
- CBotVarBoolean( const CBotToken* name );
-// ~CBotVarBoolean();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, bool bName=true);
-
- void And(CBotVar* left, CBotVar* right);
- void Or(CBotVar* left, CBotVar* right);
- void XOr(CBotVar* left, CBotVar* right);
- void Not();
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- bool Save1State(FILE* pf);
-};
-
-
-// classe pour la gestion des instances de classe
-class CBotVarClass : public CBotVar
-{
-private:
- static
- CBotVarClass* m_ExClass; // liste des instances existantes à un moment donné
- CBotVarClass* m_ExNext; // pour cette liste générale
- CBotVarClass* m_ExPrev; // pour cette liste générale
-
-private:
- CBotClass* m_pClass; // la définition de la classe
- CBotVarClass* m_pParent; // l'instance dans la classe parent
- CBotVar* m_pVar; // contenu
- friend class CBotVar; // mon papa est un copain
- friend class CBotVarPointer; // et le pointeur aussi
- int m_CptUse; // compteur d'utilisation
- long m_ItemIdent; // identificateur (unique) de l'instance
- bool m_bConstructor; // set si un constructeur a été appelé
-
-public:
- CBotVarClass( const CBotToken* name, const CBotTypResult& type );
-// CBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
- ~CBotVarClass();
-// void InitCBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
-
- void Copy(CBotVar* pSrc, bool bName=true);
- void SetClass(CBotClass* pClass); //, int &nIdent);
- CBotClass* GivClass();
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- CBotVar* GivItemRef(int nIdent);
-
- CBotVar* GivItem(int n, bool bExtend);
- CBotVar* GivItemList();
-
- CBotString GivValString();
-
- bool Save1State(FILE* pf);
- void Maj(void* pUser, bool bContinue);
-
- void IncrementUse(); // une référence en plus
- void DecrementUse(); // une référence en moins
-
- CBotVarClass*
- GivPointer();
- void SetItemList(CBotVar* pVar);
-
- void SetIdent(long n);
-
- static CBotVarClass* Find(long id);
-
-
-// CBotVar* GivMyThis();
-
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-
- void ConstructorSet();
-};
-
-
-// classe pour la gestion des pointeurs à une instances de classe
-class CBotVarPointer : public CBotVar
-{
-private:
- CBotVarClass*
- m_pVarClass; // contenu
- CBotClass* m_pClass; // la classe prévue pour ce pointeur
- friend class CBotVar; // mon papa est un copain
-
-public:
- CBotVarPointer( const CBotToken* name, CBotTypResult& type );
- ~CBotVarPointer();
-
- void Copy(CBotVar* pSrc, bool bName=true);
- void SetClass(CBotClass* pClass);
- CBotClass* GivClass();
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- CBotVar* GivItemRef(int nIdent);
- CBotVar* GivItemList();
-
- CBotString GivValString();
- void SetPointer(CBotVar* p);
- CBotVarClass*
- GivPointer();
-
- void SetIdent(long n); // associe un numéro d'identification (unique)
- long GivIdent(); // donne le numéro d'identification associé
- void ConstructorSet();
-
- bool Save1State(FILE* pf);
- void Maj(void* pUser, bool bContinue);
-
- bool Eq(CBotVar* left, CBotVar* right);
- bool Ne(CBotVar* left, CBotVar* right);
-};
-
-
-// classe pour les tableaux
-
-#define MAXARRAYSIZE 9999
-
-class CBotVarArray : public CBotVar
-{
-private:
- CBotVarClass*
- m_pInstance; // instance gérant le tableau
-
- friend class CBotVar; // papa est un copain
-
-public:
- CBotVarArray( const CBotToken* name, CBotTypResult& type );
- ~CBotVarArray();
-
- void SetPointer(CBotVar* p);
- CBotVarClass*
- GivPointer();
-
- void Copy(CBotVar* pSrc, bool bName=true);
- CBotVar* GivItem(int n, bool bGrow=false); // rend un élément selon son index numérique
- // agrandi le tableau si nécessaire si bExtend
-// CBotVar* GivItem(const char* name); // rend un élément selon son index litéral
- CBotVar* GivItemList(); // donne le premier élément de la liste
-
- CBotString GivValString(); // donne le contenu du tableau dans une chaîne
-
- bool Save1State(FILE* pf);
-};
-
-
-extern CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars);
-
-extern bool TypeCompatible( CBotTypResult& type1, CBotTypResult& type2, int op = 0 );
-extern bool TypesCompatibles( const CBotTypResult& type1, const CBotTypResult& type2 );
-
-extern bool WriteWord(FILE* pf, unsigned short w);
-extern bool ReadWord(FILE* pf, unsigned short& w);
-extern bool ReadLong(FILE* pf, long& w);
-extern bool WriteFloat(FILE* pf, float w);
-extern bool WriteLong(FILE* pf, long w);
-extern bool ReadFloat(FILE* pf, float& w);
-extern bool WriteString(FILE* pf, CBotString s);
-extern bool ReadString(FILE* pf, CBotString& s);
-extern bool WriteType(FILE* pf, CBotTypResult type);
-extern bool ReadType(FILE* pf, CBotTypResult& type);
-
-extern float GivNumFloat( const char* p );
-
-#if false
-extern void DEBUG( const char* text, int val, CBotStack* pile );
-#endif
-
-///////////////////////////////////////////
-// classe pour les appels de routines (externes)
-
-class CBotCall
-{
-private:
- static
- CBotCall* m_ListCalls;
- static
- void* m_pUser;
- long m_nFuncIdent;
-
-private:
- CBotString m_name;
- bool (*m_rExec) (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser) ;
- CBotTypResult
- (*m_rComp) (CBotVar* &pVar, void* pUser) ;
- CBotCall* m_next;
-
-public:
- CBotCall(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
- ~CBotCall();
-
- static
- bool AddFunction(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
-
- static
- CBotTypResult
- CompileCall(CBotToken* &p, CBotVar** ppVars, CBotCStack* pStack, long& nIdent);
- static
- bool CheckCall(const char* name);
-
-// static
-// int DoCall(CBotToken* &p, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
- static
- int DoCall(long& nIdent, CBotToken* token, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
-#if STACKRUN
- bool Run(CBotStack* pStack);
- static
- bool RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack);
-#endif
-
- CBotString GivName();
- CBotCall* Next();
-
- static void SetPUser(void* pUser);
- static void Free();
-};
-
-// classe gérant les méthodes déclarées par AddFunction sur une classe
-
-class CBotCallMethode
-{
-private:
- CBotString m_name;
- bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception);
- CBotTypResult
- (*m_rComp) (CBotVar* pThis, CBotVar* &pVar);
- CBotCallMethode* m_next;
- friend class CBotClass;
- long m_nFuncIdent;
-
-public:
- CBotCallMethode(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
- ~CBotCallMethode();
-
- CBotTypResult
- CompileCall(const char* name, CBotVar* pThis,
- CBotVar** ppVars, CBotCStack* pStack,
- long& nIdent);
-
- int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pFunc);
-
- CBotString GivName();
- CBotCallMethode* Next();
- void AddNext(CBotCallMethode* p);
-
-};
-
-// une liste de paramètres
-
-class CBotDefParam
-{
-private:
- CBotToken m_token; // nom du paramètre
- CBotString m_typename; // nom du type
- CBotTypResult m_type; // type de paramètre
- CBotDefParam* m_next; // paramètre suivant
- long m_nIdent;
-
-public:
- CBotDefParam();
- ~CBotDefParam();
- static
- CBotDefParam* Compile(CBotToken* &p, CBotCStack* pStack);
- bool Execute(CBotVar** ppVars, CBotStack* &pj);
- void RestoreState(CBotStack* &pj, bool bMain);
-
- void AddNext(CBotDefParam* p);
- int GivType();
- CBotTypResult GivTypResult();
- CBotDefParam* GivNext();
-
- CBotString GivParamString();
-};
-
-
-// une déclaration de fonction
-
-class CBotFunction : CBotInstr
-{
-private:
- // gestion d'une liste (static) de fonctions publiques
- static
- CBotFunction* m_listPublic;
- CBotFunction* m_nextpublic;
- CBotFunction* m_prevpublic;
- friend class CBotCStack;
-// long m_nThisIdent;
- long m_nFuncIdent;
- bool m_bSynchro; // méthode synchronisée ?
-
-private:
- CBotDefParam* m_Param; // liste des paramètres
- CBotInstr* m_Block; // le bloc d'instructions
- CBotFunction* m_next;
- CBotToken m_retToken; // si retourne un CBotTypClass
- CBotTypResult m_retTyp; // type complet du résultat
-
- bool m_bPublic; // fonction publique
- bool m_bExtern; // fonction extern
- CBotString m_MasterClass; // nom de la classe qu'on dérive
- CBotProgram* m_pProg;
- friend class CBotProgram;
- friend class CBotClass;
-
- CBotToken m_extern; // pour la position du mot "extern"
- CBotToken m_openpar;
- CBotToken m_closepar;
- CBotToken m_openblk;
- CBotToken m_closeblk;
-public:
- CBotFunction();
- ~CBotFunction();
- static
- CBotFunction* Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* pFunc, bool bLocal = true);
- static
- CBotFunction* Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass);
- bool Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
- void RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
-
- void AddNext(CBotFunction* p);
- CBotTypResult CompileCall(const char* name, CBotVar** ppVars, long& nIdent);
- CBotFunction* FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic = true);
-
- int DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken);
- void RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack);
- int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass);
- void RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass);
- bool CheckParam(CBotDefParam* pParam);
-
- static
- void AddPublic(CBotFunction* pfunc);
-
- CBotString GivName();
- CBotString GivParams();
- bool IsPublic();
- bool IsExtern();
- CBotFunction* Next();
-
- bool GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop);
-};
-
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. +//////////////////////////////////////////////////////////////////// +/** + * \file CBot.h + * \brief Interpreter of the language CBot for COLOBOT game + */ + +#pragma once + +#include "resource.h" +#include "CBotDll.h" // public definitions +#include "CBotToken.h" // token management + +#define STACKRUN true /// \def return execution directly on a suspended routine +#define STACKMEM true /// \def preserve memory for the execution stack +#define MAXSTACK 990 /// \def stack size reserved + +#define EOX (CBotStack*)-1 /// \def tag special condition + + +// fix for MSVC instruction __asm int 3 (setting a trap) +#if defined(__MINGW32__) || defined(__GNUC__) +#define ASM_TRAP() asm("int $3"); +#else +#define ASM_TRAP() __asm int 3; +#endif + +///////////////////////////////////////////////////////////////////// +// forward declaration + +class CBotCompExpr; // an expression like + // () <= () +class CBotAddExpr; // an expression like + // () + () +class CBotParExpr; // basic type or instruction in parenthesis + // Toto.truc + // 12.5 + // "string" + // ( expression ) +class CBotExprVar; // a variable name as + // Toto + // chose.truc.machin +class CBotWhile; // while (...) {...}; +class CBotIf; // if (...) {...} else {...} +class CBotDefParam; // paramerer list of a function +class CBotRepeat; // repeat (nb) {...} + + + +//////////////////////////////////////////////////////////////////////// +// Management of the execution stack +//////////////////////////////////////////////////////////////////////// + +// actually, externally, the only thing it can do +// is to create an instance of a stack +// to use for routine CBotProgram :: Execute (CBotStack) + + +/**\class CBotStack + * \brief Management of the execution stack. + * \brief Actually the only thing it can do is to create an instance of a stack + * \brief to use for routine CBotProgram :: Execute(CBotStack)*/ +class CBotStack +{ +public: +#if STACKMEM + /** + * \brief FirstStack Allocate first stack + * \return pointer to created stack + */ + static CBotStack * FirstStack(); + + /** \brief Delete Remove current stack */ + void Delete(); +#endif + + /** + * \brief CBotStack Constructor of the stack + * \param ppapa Not used. + */ + CBotStack(CBotStack* ppapa); + + + /** \brief ~CBotStack Destructor */ + ~CBotStack(); + + /** + * \brief StackOver Check if end of stack is reached + * \return true if end of stack + */ + bool StackOver(); + + /** + * \brief GivError Get error number of the stack + * \param [out] start beginning of the stack + * \param [out] end end of stack + * \return error number + */ + int GivError(int& start, int& end); + + /** + * \brief GivError Get error number + * \return eror number + */ + int GivError();// rend le numéro d'erreur retourné + + /** + * \brief Reset Reset error at and set user + * \param [in] pUser User of stack + */ + void Reset(void* pUser); + + /** + * \brief SetType Determines the type. + * \param type Type of instruction on the stack. + */ + void SetType(CBotTypResult& type); + + /** + * \brief GivType Get the type of value on the stack. + * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic). + * \return Type number. + */ + int GivType(int mode = 0); + + /** + * \brief Gives the type of complete value on the stack. + * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic). + * \return Type of an element. + */ + CBotTypResult GivTypResult(int mode = 0); + + /** + * \brief Adds a local variable. + * \param [in] p Variable to be added. + */ + void AddVar(CBotVar* p); + + /** + * \brief Fetch a variable by its token. + * \brief This may be a composite variable + * \param [in] pToken Token upon which search is performed + * \param [in] bUpdate Not used. Probably need to be removed + * \param [in] bModif Not used. Probably need to be removed + * \return Found variable + */ + CBotVar* FindVar(CBotToken* &pToken, bool bUpdate = false, + bool bModif = false); + + /** + * \brief Fetch a variable by its token. + * \brief This may be a composite variable + * \param [in] pToken Token upon which search is performed + * \param [in] bUpdate Not used. Probably need to be removed + * \param [in] bModif Not used. Probably need to be removed + * \return Found variable + */ + CBotVar* FindVar(CBotToken& Token, bool bUpdate = false, + bool bModif = false); + + /** + * \brief Fetch variable by its name + * \param [in] name Name of variable to find + * \return Found variable + */ + CBotVar* FindVar(const char* name); + + /** + * \brief Fetch a variable on the stack according to its identification number + * \brief This is faster than comparing names + * \param [in] ident Identifier of a variable + * \param [in] bUpdate Not used. Probably need to be removed + * \param [in] bModif Not used. Probably need to be removed + * \return Found variable + */ + CBotVar* FindVar(long ident, bool bUpdate = false, + bool bModif = false); + + /** + * \brief Find variable by its token and returns a copy of it. + * \param Token Token upon which search is performed + * \param bUpdate Not used. + * \return Found variable, NULL if not found + */ + CBotVar* CopyVar(CBotToken& Token, bool bUpdate = false); + + + CBotStack* AddStack(CBotInstr* instr = NULL, bool bBlock = false); // extends the stack + CBotStack* AddStackEOX(CBotCall* instr = NULL, bool bBlock = false); // extends the stack + CBotStack* RestoreStack(CBotInstr* instr = NULL); + CBotStack* RestoreStackEOX(CBotCall* instr = NULL); + + CBotStack* AddStack2(bool bBlock = false); // extends the stack + bool Return(CBotStack* pFils); // transmits the result over + bool ReturnKeep(CBotStack* pFils); // transmits the result without reducing the stack + bool BreakReturn(CBotStack* pfils, const char* name = NULL); + // in case of eventual break + bool IfContinue(int state, const char* name); + // or "continue" + + bool IsOk(); + + bool SetState(int n, int lim = -10); // select a state + int GivState(); // in what state am I? + bool IncState(int lim = -10); // passes to the next state + bool IfStep(); // do step by step + bool Execute(); + + void SetVar( CBotVar* var ); + void SetCopyVar( CBotVar* var ); + CBotVar* GivVar(); + CBotVar* GivCopyVar(); + CBotVar* GivPtVar(); + bool GivRetVar(bool bRet); + long GivVal(); + + void SetStartError(int pos); + void SetError(int n, CBotToken* token = NULL); + void SetPosError(CBotToken* token); + void ResetError(int n, int start, int end); + void SetBreak(int val, const char* name); + + void SetBotCall(CBotProgram* p); + CBotProgram* GivBotCall(bool bFirst = false); + void* GivPUser(); + bool GivBlock(); + + + bool ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype); + void RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar); + + bool SaveState(FILE* pf); + bool RestoreState(FILE* pf, CBotStack* &pStack); + + static + void SetTimer(int n); + + void GetRunPos(const char* &FunctionName, int &start, int &end); + CBotVar* GivStackVars(const char* &FunctionName, int level); + + int m_temp; + +private: + CBotStack* m_next; + CBotStack* m_next2; + CBotStack* m_prev; + friend class CBotInstArray; + +#ifdef _DEBUG + int m_index; +#endif + int m_state; + int m_step; + static int m_error; + static int m_start; + static int m_end; + static + CBotVar* m_retvar; // result of a return + + CBotVar* m_var; // result of the operations + CBotVar* m_listVar; // variables declared at this level + + bool m_bBlock; // is part of a block (variables are local to this block) + bool m_bOver; // stack limits? +// bool m_bDontDelete; // special, not to destroy the variable during delete + CBotProgram* m_prog; // user-defined functions + + static + int m_initimer; + static + int m_timer; + static + CBotString m_labelBreak; + static + void* m_pUser; + + CBotInstr* m_instr; // the corresponding instruction + bool m_bFunc; // an input of a function? + CBotCall* m_call; // recovery point in a extern call + friend class CBotTry; +}; + +// inline routinees must be declared in file.h + +inline bool CBotStack::IsOk() +{ + return (m_error == 0); +} + +inline int CBotStack::GivState() +{ + return m_state; +} + +inline int CBotStack::GivError() +{ + return m_error; +} + +//////////////////////////////////////////////////////////////////////// +// Management of the stack of compilation +//////////////////////////////////////////////////////////////////////// + + +class CBotCStack +{ +private: + CBotCStack* m_next; + CBotCStack* m_prev; + + static int m_error; + static int m_end; + int m_start; + + CBotVar* m_var; // result of the operations + + bool m_bBlock; // is part of a block (variables are local to this block) + CBotVar* m_listVar; + + static + CBotProgram* m_prog; // list of compiled functions + static + CBotTypResult m_retTyp; +// static +// CBotToken* m_retClass; + +public: + CBotCStack(CBotCStack* ppapa); + ~CBotCStack(); + + bool IsOk(); + int GivError(); + int GivError(int& start, int& end); + // gives error number + + void SetType(CBotTypResult& type);// determines the type + CBotTypResult GivTypResult(int mode = 0); // gives the type of value on the stack + int GivType(int mode = 0); // gives the type of value on the stack + CBotClass* GivClass(); // gives the class of the value on the stack + + void AddVar(CBotVar* p); // adds a local variable + CBotVar* FindVar(CBotToken* &p); // finds a variable + CBotVar* FindVar(CBotToken& Token); + bool CheckVarLocal(CBotToken* &pToken); + CBotVar* CopyVar(CBotToken& Token); // finds and makes a copy + + CBotCStack* TokenStack(CBotToken* pToken = NULL, bool bBlock = false); + CBotInstr* Return(CBotInstr* p, CBotCStack* pParent); // transmits the result upper + CBotFunction* ReturnFunc(CBotFunction* p, CBotCStack* pParent); // transmits the result upper + + void SetVar( CBotVar* var ); + void SetCopyVar( CBotVar* var ); + CBotVar* GivVar(); + + void SetStartError(int pos); + void SetError(int n, int pos); + void SetError(int n, CBotToken* p); + void ResetError(int n, int start, int end); + + void SetRetType(CBotTypResult& type); + CBotTypResult GivRetType(); + +// void SetBotCall(CBotFunction* &pFunc); + void SetBotCall(CBotProgram* p); + CBotProgram* GivBotCall(); + CBotTypResult CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent); + bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam); + + bool NextToken(CBotToken* &p); +}; + + +extern bool SaveVar(FILE* pf, CBotVar* pVar); + + +///////////////////////////////////////////////////////////////////// +// class defining an instruction +class CBotInstr +{ +private: + static + CBotStringArray + m_labelLvl; +protected: + CBotToken m_token; // keeps the token + CBotString name; // debug + CBotInstr* m_next; // linked command + CBotInstr* m_next2b; // second list definition chain + CBotInstr* m_next3; // third list for indices and fields + CBotInstr* m_next3b; // necessary for reporting tables +/* + for example, the following program + int x[]; x[1] = 4; + int y[x[1]][10], z; + is generated + CBotInstrArray + m_next3b-> CBotEmpty + m_next-> + CBotExpression .... + m_next-> + CBotInstrArray + m_next3b-> CBotExpression ('x') ( m_next3-> CBotIndexExpr ('1') ) + m_next3b-> CBotExpression ('10') + m_next2-> 'z' + m_next->... + +*/ + + static + int m_LoopLvl; + friend class CBotClassInst; + friend class CBotInt; + friend class CBotListArray; + +public: + CBotInstr(); + virtual + ~CBotInstr(); + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + static + CBotInstr* CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first = true); + + virtual + bool Execute(CBotStack* &pj); + virtual + bool Execute(CBotStack* &pj, CBotVar* pVar); + virtual + void RestoreState(CBotStack* &pj, bool bMain); + + virtual + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + virtual + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend); + virtual + void RestoreStateVar(CBotStack* &pile, bool bMain); + + virtual + bool CompCase(CBotStack* &pj, int val); + + void SetToken(CBotToken* p); + int GivTokenType(); + CBotToken* GivToken(); + + void AddNext(CBotInstr* n); + CBotInstr* GivNext(); + void AddNext3(CBotInstr* n); + CBotInstr* GivNext3(); + void AddNext3b(CBotInstr* n); + CBotInstr* GivNext3b(); + + static + void IncLvl(CBotString& label); + static + void IncLvl(); + static + void DecLvl(); + static + bool ChkLvl(const CBotString& label, int type); + + bool IsOfClass(CBotString name); +}; + +class CBotWhile : public CBotInstr +{ +private: + CBotInstr* m_Condition; // condition + CBotInstr* m_Block; // instructions + CBotString m_label; // a label if there is + +public: + CBotWhile(); + ~CBotWhile(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotRepeat : public CBotInstr +{ +private: + /// Number of iterations + CBotInstr* m_NbIter; + + /// Instructions + CBotInstr* m_Block; + + /// Label + CBotString m_label; // a label if there is + +public: + CBotRepeat(); + ~CBotRepeat(); + + /// Static method used for compilation + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + + /// Execute + bool Execute(CBotStack* &pj); + + /// Restore state + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotDo : public CBotInstr +{ +private: + CBotInstr* m_Block; // instruction + CBotInstr* m_Condition; // conditions + CBotString m_label; // a label if there is + +public: + CBotDo(); + ~CBotDo(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotFor : public CBotInstr +{ +private: + CBotInstr* m_Init; // initial intruction + CBotInstr* m_Test; // test condition + CBotInstr* m_Incr; // instruction for increment + CBotInstr* m_Block; // instructions + CBotString m_label; // a label if there is + +public: + CBotFor(); + ~CBotFor(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotBreak : public CBotInstr +{ +private: + CBotString m_label; // a label if there is + +public: + CBotBreak(); + ~CBotBreak(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotReturn : public CBotInstr +{ +private: + CBotInstr* m_Instr; // paramter of return + +public: + CBotReturn(); + ~CBotReturn(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotSwitch : public CBotInstr +{ +private: + CBotInstr* m_Value; // value to seek + CBotInstr* m_Block; // instructions + +public: + CBotSwitch(); + ~CBotSwitch(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotCase : public CBotInstr +{ +private: + CBotInstr* m_Value; // value to compare + +public: + CBotCase(); + ~CBotCase(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + bool CompCase(CBotStack* &pj, int val); +}; + +class CBotCatch : public CBotInstr +{ +private: + CBotInstr* m_Block; // instructions + CBotInstr* m_Cond; //condition + CBotCatch* m_next; //following catch + friend class CBotTry; + +public: + CBotCatch(); + ~CBotCatch(); + static + CBotCatch* Compile(CBotToken* &p, CBotCStack* pStack); + bool TestCatch(CBotStack* &pj, int val); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + void RestoreCondState(CBotStack* &pj, bool bMain); +}; + +class CBotTry : public CBotInstr +{ +private: + CBotInstr* m_Block; // instructions + CBotCatch* m_ListCatch; // catches + CBotInstr* m_FinalInst; // final instruction + +public: + CBotTry(); + ~CBotTry(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotThrow : public CBotInstr +{ +private: + CBotInstr* m_Value; // the value to send + +public: + CBotThrow(); + ~CBotThrow(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotStartDebugDD : public CBotInstr +{ +private: + +public: + CBotStartDebugDD(); + ~CBotStartDebugDD(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); +}; + + +class CBotIf : public CBotInstr +{ +private: + CBotInstr* m_Condition; // condition + CBotInstr* m_Block; // instructions + CBotInstr* m_BlockElse; // instructions + +public: + CBotIf(); + ~CBotIf(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +// definition of an integer + +class CBotInt : public CBotInstr +{ +private: + CBotInstr* m_var; // the variable to initialize + CBotInstr* m_expr; // a value to put, if there is +/// CBotInstr* m_next; // several definitions chained + +public: + CBotInt(); + ~CBotInt(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// definition of an array + +class CBotInstArray : public CBotInstr +{ +private: + CBotInstr* m_var; // the variables to initialize + CBotInstr* m_listass; // list of assignments for array + CBotTypResult + m_typevar; // type of elements +// CBotString m_ClassName; + +public: + CBotInstArray(); + ~CBotInstArray(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +// definition of a assignment list for a table +// int [ ] a [ ] = ( ( 1, 2, 3 ) , ( 3, 2, 1 ) ) ; + +class CBotListArray : public CBotInstr +{ +private: + CBotInstr* m_expr; // an expression for an element + // others are linked with CBotInstr :: m_next3; +public: + CBotListArray(); + ~CBotListArray(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type); + bool Execute(CBotStack* &pj, CBotVar* pVar); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotEmpty : public CBotInstr +{ + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// defininition of a boolean + +class CBotBoolean : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotInstr* m_expr; // a value to put, if there is + +public: + CBotBoolean(); + ~CBotBoolean(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +// definition of a real number + +class CBotFloat : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotInstr* m_expr; // a value to put, if there is + +public: + CBotFloat(); + ~CBotFloat(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// definition of an element string + +class CBotIString : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotInstr* m_expr; // a value to put, if there is + +public: + CBotIString(); + ~CBotIString(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// definition of an element of any class + +class CBotClassInst : public CBotInstr +{ +private: + CBotInstr* m_var; // variable to initialise + CBotClass* m_pClass; // reference to the class + CBotInstr* m_Parameters; // parameters to be evaluated for the contructor + CBotInstr* m_expr; // a value to put, if there is + bool m_hasParams; // has it parameters? + long m_nMethodeIdent; + +public: + CBotClassInst(); + ~CBotClassInst(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass = NULL); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotCondition : public CBotInstr +{ +private: + +public: + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); +}; + + +// left operand +// accept the expressions that be to the left of assignment + +class CBotLeftExpr : public CBotInstr +{ +private: + long m_nIdent; + +public: + CBotLeftExpr(); + ~CBotLeftExpr(); + static + CBotLeftExpr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack, CBotStack* array); + + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep); + void RestoreStateVar(CBotStack* &pile, bool bMain); +}; + + +// management of the fields of an instance + +class CBotFieldExpr : public CBotInstr +{ +private: + friend class CBotExpression; + int m_nIdent; + +public: + CBotFieldExpr(); + ~CBotFieldExpr(); + void SetUniqNum(int num); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +// management of indices of the tables + +class CBotIndexExpr : public CBotInstr +{ +private: + CBotInstr* m_expr; // expression for calculating the index + friend class CBotLeftExpr; + friend class CBotExprVar; + +public: + CBotIndexExpr(); + ~CBotIndexExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +// expressions like +// x = a; +// x * y + 3; + +class CBotExpression : public CBotInstr +{ +private: + CBotLeftExpr* m_leftop; // left operand + CBotInstr* m_rightop; // right operant + +public: + CBotExpression(); + ~CBotExpression(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotListExpression : public CBotInstr +{ +private: + CBotInstr* m_Expr; // the first expression to be evaluated + +public: + CBotListExpression(); + ~CBotListExpression(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotLogicExpr : public CBotInstr +{ +private: + CBotInstr* m_condition; // test to evaluate + CBotInstr* m_op1; // left element + CBotInstr* m_op2; // right element + friend class CBotTwoOpExpr; + +public: + CBotLogicExpr(); + ~CBotLogicExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + + +class CBotBoolExpr : public CBotInstr +{ +private: + +public: + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); +}; + + + +// possibly an expression in parentheses ( ... ) +// there is never an instance of this class +// being the object returned inside the parenthesis +class CBotParExpr : public CBotInstr +{ +private: + +public: + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); +}; + +// unary expression +class CBotExprUnaire : public CBotInstr +{ +private: + CBotInstr* m_Expr; // expression to be evaluated +public: + CBotExprUnaire(); + ~CBotExprUnaire(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// all operations with two operands + +class CBotTwoOpExpr : public CBotInstr +{ +private: + CBotInstr* m_leftop; // left element + CBotInstr* m_rightop; // right element +public: + CBotTwoOpExpr(); + ~CBotTwoOpExpr(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = NULL); + bool Execute(CBotStack* &pStack); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + + + +// an instruction block { .... } +class CBotBlock : public CBotInstr +{ +private: + +public: + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true); + static + CBotInstr* CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal = false); +}; + + +// the content of a block of instructions ... ; ... ; ... ; ... ; +class CBotListInstr : public CBotInstr +{ +private: + CBotInstr* m_Instr; // instructions to do + +public: + CBotListInstr(); + ~CBotListInstr(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotInstrCall : public CBotInstr +{ +private: + CBotInstr* m_Parameters; // the parameters to be evaluated +// int m_typeRes; // type of the result +// CBotString m_RetClassName; // class of the result + CBotTypResult + m_typRes; // complete type of the result + long m_nFuncIdent; // id of a function + +public: + CBotInstrCall(); + ~CBotInstrCall(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// a call of method + +class CBotInstrMethode : public CBotInstr +{ +private: + CBotInstr* m_Parameters; // the parameters to be evaluated +// int m_typeRes; // type of the result +// CBotString m_RetClassName; // class of the result + CBotTypResult + m_typRes; // complete type of the result + + CBotString m_NomMethod; // name of the method + long m_MethodeIdent; // identifier of the method +// long m_nThisIdent; // identifier for "this" + CBotString m_ClassName; // name of the class + +public: + CBotInstrMethode(); + ~CBotInstrMethode(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar); + bool Execute(CBotStack* &pj); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +// expression for the variable name + +class CBotExprVar : public CBotInstr +{ +private: + long m_nIdent; + friend class CBotPostIncExpr; + friend class CBotPreIncExpr; + +public: + CBotExprVar(); + ~CBotExprVar(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int privat=PR_PROTECT); + static + CBotInstr* CompileMethode(CBotToken* &p, CBotCStack* pStack); + + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep); + bool Execute2Var(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep); + void RestoreStateVar(CBotStack* &pj, bool bMain); +}; + +class CBotPostIncExpr : public CBotInstr +{ +private: + CBotInstr* m_Instr; + friend class CBotParExpr; + +public: + CBotPostIncExpr(); + ~CBotPostIncExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotPreIncExpr : public CBotInstr +{ +private: + CBotInstr* m_Instr; + friend class CBotParExpr; + +public: + CBotPreIncExpr(); + ~CBotPreIncExpr(); +// static +// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotLeftExprVar : public CBotInstr +{ +private: +public: + CBotTypResult + m_typevar; // type of variable declared + long m_nIdent; // unique identifier for that variable + +public: + CBotLeftExprVar(); + ~CBotLeftExprVar(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotExprBool : public CBotInstr +{ +private: + +public: + CBotExprBool(); + ~CBotExprBool(); + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +class CBotExprNull : public CBotInstr +{ +private: + +public: + CBotExprNull(); + ~CBotExprNull(); + + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotExprNan : public CBotInstr +{ +private: + +public: + CBotExprNan(); + ~CBotExprNan(); + + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +class CBotNew : public CBotInstr +{ +private: + CBotInstr* m_Parameters; // the parameters to be evaluated + long m_nMethodeIdent; +// long m_nThisIdent; + CBotToken m_vartoken; + +public: + CBotNew(); + ~CBotNew(); + + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + +// expression representing a number + +class CBotExprNum : public CBotInstr +{ +private: + int m_numtype; // et the type of number + long m_valint; // value for an int + float m_valfloat; // value for a float + +public: + CBotExprNum(); + ~CBotExprNum(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + + +// expression representing a string + +class CBotExprAlpha : public CBotInstr +{ +private: + +public: + CBotExprAlpha(); + ~CBotExprAlpha(); + static + CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); +}; + + +#define MAX(a,b) ((a>b) ? a : b) + + +// class for the management of integer numbers (int) +class CBotVarInt : public CBotVar +{ +private: + int m_val; // the value + CBotString m_defnum; // the name if given by DefineNum + friend class CBotVar; + +public: + CBotVarInt( const CBotToken* name ); +// ~CBotVarInt(); + + void SetValInt(int val, const char* s = NULL); + void SetValFloat(float val); + int GivValInt(); + float GivValFloat(); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + + void Add(CBotVar* left, CBotVar* right); // addition + void Sub(CBotVar* left, CBotVar* right); // substraction + void Mul(CBotVar* left, CBotVar* right); // multiplication + int Div(CBotVar* left, CBotVar* right); // division + int Modulo(CBotVar* left, CBotVar* right); // remainder of division + void Power(CBotVar* left, CBotVar* right); // power + + bool Lo(CBotVar* left, CBotVar* right); + bool Hi(CBotVar* left, CBotVar* right); + bool Ls(CBotVar* left, CBotVar* right); + bool Hs(CBotVar* left, CBotVar* right); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + void XOr(CBotVar* left, CBotVar* right); + void Or(CBotVar* left, CBotVar* right); + void And(CBotVar* left, CBotVar* right); + + void SL(CBotVar* left, CBotVar* right); + void SR(CBotVar* left, CBotVar* right); + void ASR(CBotVar* left, CBotVar* right); + + void Neg(); + void Not(); + void Inc(); + void Dec(); + + bool Save0State(FILE* pf); + bool Save1State(FILE* pf); + +}; + +// Class for managing real numbers (float) +class CBotVarFloat : public CBotVar +{ +private: + float m_val; // the value + +public: + CBotVarFloat( const CBotToken* name ); +// ~CBotVarFloat(); + + void SetValInt(int val, const char* s = NULL); + void SetValFloat(float val); + int GivValInt(); + float GivValFloat(); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + + void Add(CBotVar* left, CBotVar* right); // addition + void Sub(CBotVar* left, CBotVar* right); // substraction + void Mul(CBotVar* left, CBotVar* right); // multiplication + int Div(CBotVar* left, CBotVar* right); // division + int Modulo(CBotVar* left, CBotVar* right); // remainder of division + void Power(CBotVar* left, CBotVar* right); // power + + bool Lo(CBotVar* left, CBotVar* right); + bool Hi(CBotVar* left, CBotVar* right); + bool Ls(CBotVar* left, CBotVar* right); + bool Hs(CBotVar* left, CBotVar* right); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + void Neg(); + void Inc(); + void Dec(); + + bool Save1State(FILE* pf); +}; + + +// class for management of strings (String) +class CBotVarString : public CBotVar +{ +private: + CBotString m_val; // the value + +public: + CBotVarString( const CBotToken* name ); +// ~CBotVarString(); + + void SetValString(const char* p); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + void Add(CBotVar* left, CBotVar* right); // addition + + bool Lo(CBotVar* left, CBotVar* right); + bool Hi(CBotVar* left, CBotVar* right); + bool Ls(CBotVar* left, CBotVar* right); + bool Hs(CBotVar* left, CBotVar* right); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + bool Save1State(FILE* pf); +}; + +// class for the management of boolean +class CBotVarBoolean : public CBotVar +{ +private: + bool m_val; // the value + +public: + CBotVarBoolean( const CBotToken* name ); +// ~CBotVarBoolean(); + + void SetValInt(int val, const char* s = NULL); + void SetValFloat(float val); + int GivValInt(); + float GivValFloat(); + CBotString GivValString(); + + void Copy(CBotVar* pSrc, bool bName=true); + + void And(CBotVar* left, CBotVar* right); + void Or(CBotVar* left, CBotVar* right); + void XOr(CBotVar* left, CBotVar* right); + void Not(); + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + bool Save1State(FILE* pf); +}; + + +// class management class instances +class CBotVarClass : public CBotVar +{ +private: + static + CBotVarClass* m_ExClass; // list of existing instances at some point + CBotVarClass* m_ExNext; // for this general list + CBotVarClass* m_ExPrev; // for this general list + +private: + CBotClass* m_pClass; // the class definition + CBotVarClass* m_pParent; // the instance of a parent class + CBotVar* m_pVar; // contents + friend class CBotVar; // my daddy is a buddy WHAT? :D(\TODO mon papa est un copain ) + friend class CBotVarPointer; // and also the pointer + int m_CptUse; // counter usage + long m_ItemIdent; // identifier (unique) of an instance + bool m_bConstructor; // set if a constructor has been called + +public: + CBotVarClass( const CBotToken* name, const CBotTypResult& type ); +// CBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent ); + ~CBotVarClass(); +// void InitCBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent ); + + void Copy(CBotVar* pSrc, bool bName=true); + void SetClass(CBotClass* pClass); //, int &nIdent); + CBotClass* GivClass(); + CBotVar* GivItem(const char* name); // return an element of a class according to its name (*) + CBotVar* GivItemRef(int nIdent); + + CBotVar* GivItem(int n, bool bExtend); + CBotVar* GivItemList(); + + CBotString GivValString(); + + bool Save1State(FILE* pf); + void Maj(void* pUser, bool bContinue); + + void IncrementUse(); // a reference to incrementation + void DecrementUse(); // a reference to decrementation + + CBotVarClass* + GivPointer(); + void SetItemList(CBotVar* pVar); + + void SetIdent(long n); + + static CBotVarClass* Find(long id); + + +// CBotVar* GivMyThis(); + + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); + + void ConstructorSet(); +}; + + +// class for the management of pointers to a class instances +class CBotVarPointer : public CBotVar +{ +private: + CBotVarClass* + m_pVarClass; // contents + CBotClass* m_pClass; // class provided for this pointer + friend class CBotVar; // my daddy is a buddy + +public: + CBotVarPointer( const CBotToken* name, CBotTypResult& type ); + ~CBotVarPointer(); + + void Copy(CBotVar* pSrc, bool bName=true); + void SetClass(CBotClass* pClass); + CBotClass* GivClass(); + CBotVar* GivItem(const char* name); // return an element of a class according to its name (*) + CBotVar* GivItemRef(int nIdent); + CBotVar* GivItemList(); + + CBotString GivValString(); + void SetPointer(CBotVar* p); + CBotVarClass* + GivPointer(); + + void SetIdent(long n); // associates an identification number (unique) + long GivIdent(); // gives the identification number associated with + void ConstructorSet(); + + bool Save1State(FILE* pf); + void Maj(void* pUser, bool bContinue); + + bool Eq(CBotVar* left, CBotVar* right); + bool Ne(CBotVar* left, CBotVar* right); +}; + + +// classe pour les tableaux + +#define MAXARRAYSIZE 9999 + +class CBotVarArray : public CBotVar +{ +private: + CBotVarClass* + m_pInstance; // instance manager of table + + friend class CBotVar; // my daddy is a buddy + +public: + CBotVarArray( const CBotToken* name, CBotTypResult& type ); + ~CBotVarArray(); + + void SetPointer(CBotVar* p); + CBotVarClass* + GivPointer(); + + void Copy(CBotVar* pSrc, bool bName=true); + CBotVar* GivItem(int n, bool bGrow=false); // makes an element according to its numeric index + // enlarged the table if necessary if bExtend +// CBotVar* GivItem(const char* name); // makes a element by literal index + CBotVar* GivItemList(); // gives the first item in the list + + CBotString GivValString(); // gets the contents of the array into a string + + bool Save1State(FILE* pf); +}; + + +extern CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars); + +extern bool TypeCompatible( CBotTypResult& type1, CBotTypResult& type2, int op = 0 ); +extern bool TypesCompatibles( const CBotTypResult& type1, const CBotTypResult& type2 ); + +extern bool WriteWord(FILE* pf, unsigned short w); +extern bool ReadWord(FILE* pf, unsigned short& w); +extern bool ReadLong(FILE* pf, long& w); +extern bool WriteFloat(FILE* pf, float w); +extern bool WriteLong(FILE* pf, long w); +extern bool ReadFloat(FILE* pf, float& w); +extern bool WriteString(FILE* pf, CBotString s); +extern bool ReadString(FILE* pf, CBotString& s); +extern bool WriteType(FILE* pf, CBotTypResult type); +extern bool ReadType(FILE* pf, CBotTypResult& type); + +extern float GivNumFloat( const char* p ); + +#if false +extern void DEBUG( const char* text, int val, CBotStack* pile ); +#endif + +/////////////////////////////////////////// +// class for routine calls (external) + +class CBotCall +{ +private: + static + CBotCall* m_ListCalls; + static + void* m_pUser; + long m_nFuncIdent; + +private: + CBotString m_name; + bool (*m_rExec) (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser) ; + CBotTypResult + (*m_rComp) (CBotVar* &pVar, void* pUser) ; + CBotCall* m_next; + +public: + CBotCall(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)); + ~CBotCall(); + + static + bool AddFunction(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)); + + static + CBotTypResult + CompileCall(CBotToken* &p, CBotVar** ppVars, CBotCStack* pStack, long& nIdent); + static + bool CheckCall(const char* name); + +// static +// int DoCall(CBotToken* &p, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype); + static + int DoCall(long& nIdent, CBotToken* token, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype); +#if STACKRUN + bool Run(CBotStack* pStack); + static + bool RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack); +#endif + + CBotString GivName(); + CBotCall* Next(); + + static void SetPUser(void* pUser); + static void Free(); +}; + +// class managing the methods declared by AddFunction on a class + +class CBotCallMethode +{ +private: + CBotString m_name; + bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception); + CBotTypResult + (*m_rComp) (CBotVar* pThis, CBotVar* &pVar); + CBotCallMethode* m_next; + friend class CBotClass; + long m_nFuncIdent; + +public: + CBotCallMethode(const char* name, + bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception), + CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar)); + ~CBotCallMethode(); + + CBotTypResult + CompileCall(const char* name, CBotVar* pThis, + CBotVar** ppVars, CBotCStack* pStack, + long& nIdent); + + int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pFunc); + + CBotString GivName(); + CBotCallMethode* Next(); + void AddNext(CBotCallMethode* p); + +}; + +// a list of parameters + +class CBotDefParam +{ +private: + CBotToken m_token; // name of the parameter + CBotString m_typename; // type name + CBotTypResult m_type; // type of paramteter + CBotDefParam* m_next; // next parameter + long m_nIdent; + +public: + CBotDefParam(); + ~CBotDefParam(); + static + CBotDefParam* Compile(CBotToken* &p, CBotCStack* pStack); + bool Execute(CBotVar** ppVars, CBotStack* &pj); + void RestoreState(CBotStack* &pj, bool bMain); + + void AddNext(CBotDefParam* p); + int GivType(); + CBotTypResult GivTypResult(); + CBotDefParam* GivNext(); + + CBotString GivParamString(); +}; + + +// a function declaration + +class CBotFunction : CBotInstr +{ +private: + // management of list of (static) public functions + static + CBotFunction* m_listPublic; + CBotFunction* m_nextpublic; + CBotFunction* m_prevpublic; + friend class CBotCStack; +// long m_nThisIdent; + long m_nFuncIdent; + bool m_bSynchro; // synchronized method? + +private: + CBotDefParam* m_Param; // parameter list + CBotInstr* m_Block; // the instruction block + CBotFunction* m_next; + CBotToken m_retToken; // if returns CBotTypClass + CBotTypResult m_retTyp; // complete type of the result + + bool m_bPublic; // public function + bool m_bExtern; // extern function + CBotString m_MasterClass; // name of the class we derive + CBotProgram* m_pProg; + friend class CBotProgram; + friend class CBotClass; + + CBotToken m_extern; // for the position of the word "extern" + CBotToken m_openpar; + CBotToken m_closepar; + CBotToken m_openblk; + CBotToken m_closeblk; +public: + CBotFunction(); + ~CBotFunction(); + static + CBotFunction* Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* pFunc, bool bLocal = true); + static + CBotFunction* Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass); + bool Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL); + void RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL); + + void AddNext(CBotFunction* p); + CBotTypResult CompileCall(const char* name, CBotVar** ppVars, long& nIdent); + CBotFunction* FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic = true); + + int DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken); + void RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack); + int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass); + void RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass); + bool CheckParam(CBotDefParam* pParam); + + static + void AddPublic(CBotFunction* pfunc); + + CBotString GivName(); + CBotString GivParams(); + bool IsPublic(); + bool IsExtern(); + CBotFunction* Next(); + + bool GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop); +}; + + diff --git a/src/CBot/CBotAddExpr.cpp b/src/CBot/CBotAddExpr.cpp index d94946e..8e4ed85 100644 --- a/src/CBot/CBotAddExpr.cpp +++ b/src/CBot/CBotAddExpr.cpp @@ -1,142 +1,144 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////
-// expression du genre Opérande1 + Opérande2
-// Opérande1 - Opérande2
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotAddExpr::CBotAddExpr()
-{
- m_leftop =
- m_rightop = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotAddExpr"; // debug
-}
-
-CBotAddExpr::~CBotAddExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-
-// compile une instruction de type A + B
-
-CBotInstr* CBotAddExpr::Compile(CBotToken* &p, CBotStack* pStack)
-{
- CBotStack* pStk = pStack->TokenStack(); // un bout de pile svp
-
- // cherche des instructions qui peuvent convenir à gauche de l'opération + ou -
-
- CBotInstr* left = CBotMulExpr::Compile( p, pStk ); // expression A * B à gauche
- if (left == NULL) return pStack->Return(NULL, pStk); // si erreur, la transmet
-
- // est-ce qu'on a le token + ou - ensuite ?
-
- if ( p->GetType() == ID_ADD ||
- p->GetType() == ID_SUB) // plus ou moins
- {
- CBotAddExpr* inst = new CBotAddExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
- int type1, type2;
- type1 = pStack->GetType(); // de quel type le premier opérande ?
-
- p = p->Next(); // saute le token de l'opération
-
- // cherche des instructions qui peuvent convenir à droite
-
- if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression (...) à droite
- {
- // il y a un second opérande acceptable
-
- type2 = pStack->GetType(); // de quel type le résultat ?
-
- if ( type1 == type2 ) // les résultats sont-ils compatibles
- {
- // si ok, enregistre l'opérande dans l'objet
- inst->m_leftop = left;
- // et rend l'object à qui l'a demandé
- return pStack->Return(inst, pStk);
- }
- }
-
- // en cas d'erreur, libère les éléments
- delete left;
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile
- return pStack->Return(NULL, pStk);
- }
-
- // si on n'a pas affaire à une opération + ou -
- // rend à qui l'a demandé, l'opérande (de gauche) trouvé
- // à la place de l'objet "addition"
- return pStack->Return(left, pStk);
-}
-
-
-
-
-// fait l'opération d'addition ou de soustraction
-
-bool CBotAddExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pSk1 == EOX ) return TRUE;
-
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GetState() == 0 && // 1er état, évalue l'opérande de gauche
- !m_leftop->Execute(pStk1) ) return FALSE; // interrompu ici ?
-
- // passe à l'étape suivante
- pStk1->SetState(1); // prêt pour la suite
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- // qui se trouve sur la pile, justement.
-
- CBotStack* pStk2 = pStk1->AddStack(); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-
- // 2e état, évalue l'opérande de droite
- if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrompu ici ?
-
- int type1 = pStk1->GetType(); // de quels types les résultats ?
- int type2 = pStk2->GetType();
-
- // crée une variable temporaire pour y mettre le résultat
- CBotVar* result = new CBotVar( NULL, MAX(type1, type2));
-
- // fait l'opération selon la demande
- switch (GetTokenType())
- {
- case ID_ADD:
- result->Add(pStk1->GetVar(), pStk2->GetVar()); // additionne
- break;
- case ID_SUB:
- result->Sub(pStk1->GetVar(), pStk2->GetVar()); // soustrait
- break;
- }
- pStk2->SetVar(result); // met le résultat sur la pile
-
- pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk1); // transmet le résultat
-}
-
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +/////////////////////////////////////////////////// +// expressions of type Operand1 + Operand2 +// Operand1 - Operand2 + +#include "CBot.h" + +// various constructors + +CBotAddExpr::CBotAddExpr() +{ + m_leftop = + m_rightop = NULL; // NULL to be able to delete without further + name = "CBotAddExpr"; // debug +} + +CBotAddExpr::~CBotAddExpr() +{ + delete m_leftop; + delete m_rightop; +} + + +// compile une instruction de type A + B + +CBotInstr* CBotAddExpr::Compile(CBotToken* &p, CBotStack* pStack) +{ + CBotStack* pStk = pStack->TokenStack(); // one end of stack please + + // looking statements that may be suitable to the left of the operation + or - + + CBotInstr* left = CBotMulExpr::Compile( p, pStk ); // expression A * B left + if (left == NULL) return pStack->Return(NULL, pStk); // if error, transmit + + // do we have the token + or - next? + + if ( p->GetType() == ID_ADD || + p->GetType() == ID_SUB) // more or less + { + CBotAddExpr* inst = new CBotAddExpr(); // element for operation + inst->SetToken(p); // stores the operation + + int type1, type2; + type1 = pStack->GetType(); // what kind of the first operand? + + p = p->Next(); // skip the token of the operation + + // looking statements that may be suitable for right + + if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression (...) rigth + { + // there is an acceptable second operand + + type2 = pStack->GetType(); // what kind of results? + + if ( type1 == type2 ) // are the results consistent ? + { + // ok so, saves the operand in the object + inst->m_leftop = left; + // and makes the object on demand + return pStack->Return(inst, pStk); + } + } + + // in case of error, free the elements + delete left; + delete inst; + // and transmits the error that is on the stack + return pStack->Return(NULL, pStk); + } + + // if we are not dealing with an operation + or - + // goes to that requested, the operand (left) found + // place the object "addition" + return pStack->Return(left, pStk); +} + + + + +// operation is addition or subtraction + +bool CBotAddExpr::Execute(CBotStack* &pStack) +{ + CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack + // or is found in case of recovery +// if ( pSk1 == EOX ) return TRUE; + + + // according to recovery, it may be in one of two states + + if ( pStk1->GetState() == 0 && // first state, evaluates the left operand + !m_leftop->Execute(pStk1) ) return FALSE; // interrupted here? + + // passes to the next step + pStk1->SetState(1); // ready for further + + // requires a little more stack to not touch the result of the left + // which is on the stack, precisely. + + CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack + // or is found in case of recovery + + // Second state, evaluates the right operand + if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrupted here? + + int type1 = pStk1->GetType(); // what kind of results? + int type2 = pStk2->GetType(); + + // creates a temporary variable to put the result + CBotVar* result = new CBotVar( NULL, MAX(type1, type2)); + + // is the operation as requested + switch (GetTokenType()) + { + case ID_ADD: + result->Add(pStk1->GetVar(), pStk2->GetVar()); // addition + break; + case ID_SUB: + result->Sub(pStk1->GetVar(), pStk2->GetVar()); // subtraction + break; + } + pStk2->SetVar(result); // puts the result on the stack + + pStk1->Return(pStk2); // frees the stack + return pStack->Return(pStk1); // transmits the result +} + + diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index c99185f..692d3c7 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -1,880 +1,882 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-// Gestion des variables de type classe
-//
-
-#include "CBot.h"
-
-
-CBotClass* CBotClass::m_ExClass = NULL;
-
-CBotClass::CBotClass(const char* name, CBotClass* pPapa, bool bIntrinsic)
-{
- m_pParent = pPapa;
- m_name = name;
- m_pVar = NULL;
- m_next = NULL;
- m_pCalls = NULL;
- m_pMethod = NULL;
- m_rMaj = NULL;
- m_IsDef = true;
- m_bIntrinsic= bIntrinsic;
- m_cptLock = 0;
- m_cptOne = 0;
- m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
-
- for ( int j= 0; j< 5 ; j++ )
- {
- m_ProgInLock[j] = NULL;
- }
-
-
- // se place tout seul dans la liste
- if (m_ExClass) m_ExClass->m_ExPrev = this;
- m_ExNext = m_ExClass;
- m_ExPrev = NULL;
- m_ExClass = this;
-
-}
-
-CBotClass::~CBotClass()
-{
- // retire la classe de la liste
- if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
- else m_ExClass = m_ExNext;
-
- if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
- m_ExPrev = NULL;
- m_ExNext = NULL;
-
- delete m_pVar;
- delete m_pCalls;
- delete m_pMethod;
-
- delete m_next; // libère toutes celle de ce niveau
-}
-
-
-void CBotClass::Free()
-{
- while ( m_ExClass != NULL )
- {
- delete m_ExClass;
- }
-}
-
-void CBotClass::Purge()
-{
- if ( this == NULL ) return;
-
- delete m_pVar;
- m_pVar = NULL;
- delete m_pCalls;
- m_pCalls = NULL;
- delete m_pMethod;
- m_pMethod = NULL;
- m_IsDef = false;
-
- m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
-
- m_next->Purge();
- m_next = NULL; // n'appartient plus à cette chaîne
-}
-
-bool CBotClass::Lock(CBotProgram* p)
-{
- int i = m_cptLock++;
-
- if ( i == 0 )
- {
- m_cptOne = 1;
- m_ProgInLock[0] = p;
- return true;
- }
- if ( p == m_ProgInLock[0] )
- {
- m_cptOne++;
- m_cptLock--; // a déjà été compté
- return true;
- }
-
- for ( int j = 1 ; j <= i ; j++)
- {
- if ( p == m_ProgInLock[j] )
- {
- m_cptLock--;
- return false; // déjà en attente
- }
- }
-
- if ( i < 5 ) // maxi 5 en attente
- {
- m_ProgInLock[i] = p; // se place dans la queue
- }
- else
- m_cptLock--;
-
- return false;
-}
-
-void CBotClass::Unlock()
-{
- if ( --m_cptOne > 0 ) return ;
-
- int i = --m_cptLock;
- if ( i<0 )
- {
- m_cptLock = 0;
- return;
- }
-
- for ( int j= 0; j< i ; j++ )
- {
- m_ProgInLock[j] = m_ProgInLock[j+1];
- }
- m_ProgInLock[i] = 0;
-}
-
-void CBotClass::FreeLock(CBotProgram* p)
-{
- CBotClass* pClass = m_ExClass;
-
- while ( pClass != NULL )
- {
- if ( p == pClass->m_ProgInLock[0] )
- {
- pClass->m_cptLock -= pClass->m_cptOne;
- pClass->m_cptOne = 0;
- }
-
- for ( int j = 1; j < 5 ; j++ )
- if ( p == pClass->m_ProgInLock[j] )
- pClass->m_cptLock--;
-
- pClass = pClass->m_ExNext;
- }
-}
-
-
-
-bool CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate)
-{
- CBotToken token(name, CBotString());
- CBotClass* pClass = type.GivClass();
-
- CBotVar* pVar = CBotVar::Create( name, type );
-/// pVar->SetUniqNum(CBotVar::NextUniqNum());
- pVar->SetPrivate( mPrivate );
-
- if ( pClass != NULL )
- {
-// pVar->SetClass(pClass);
- if ( type.Eq(CBotTypClass) )
- {
- // ajoute une instruction new pour initialiser l'object
- pVar->m_InitExpr = new CBotNew() ;
- CBotToken nom( pClass->GivName() );
- pVar->m_InitExpr->SetToken(&nom);
- }
- }
- return AddItem( pVar );
-}
-
-
-bool CBotClass::AddItem(CBotVar* pVar)
-{
- pVar->SetUniqNum(++m_nbVar);
-
- if ( m_pVar == NULL ) m_pVar = pVar;
- else m_pVar->AddNext(pVar);
-
- return true;
-}
-
-void CBotClass::AddNext(CBotClass* pClass)
-{
- CBotClass* p = this;
- while (p->m_next != NULL) p = p->m_next;
-
- p->m_next = pClass;
-}
-
-CBotString CBotClass::GivName()
-{
- return m_name;
-}
-
-CBotClass* CBotClass::GivParent()
-{
- if ( this == NULL ) return NULL;
- return m_pParent;
-}
-
-bool CBotClass::IsChildOf(CBotClass* pClass)
-{
- CBotClass* p = this;
- while ( p != NULL )
- {
- if ( p == pClass ) return true;
- p = p->m_pParent;
- }
- return false;
-}
-
-
-CBotVar* CBotClass::GivVar()
-{
- return m_pVar;
-}
-
-CBotVar* CBotClass::GivItem(const char* name)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->GivNext();
- }
- if ( m_pParent != NULL ) return m_pParent->GivItem(name);
- return NULL;
-}
-
-CBotVar* CBotClass::GivItemRef(int nIdent)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivUniqNum() == nIdent ) return p;
- p = p->GivNext();
- }
- if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent);
- return NULL;
-}
-
-bool CBotClass::IsIntrinsic()
-{
- return m_bIntrinsic;
-}
-
-CBotClass* CBotClass::Find(CBotToken* &pToken)
-{
- return Find(pToken->GivString());
-}
-
-CBotClass* CBotClass::Find(const char* name)
-{
- CBotClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->m_ExNext;
- }
-
- return NULL;
-}
-
-bool CBotClass::AddFunction(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
-{
- // mémorise les pointeurs aux deux fonctions
- CBotCallMethode* p = m_pCalls;
- CBotCallMethode* pp = NULL;
-
- while ( p != NULL )
- {
- if ( name == p->GivName() )
- {
- if ( pp == NULL ) m_pCalls = p->m_next;
- else pp->m_next = p->m_next;
- delete p;
- break;
- }
- pp = p;
- p = p->m_next;
- }
-
- p = new CBotCallMethode(name, rExec, rCompile);
-
- if (m_pCalls == NULL) m_pCalls = p;
- else m_pCalls->AddNext(p); // ajoute à la liste
-
- return true;
-}
-
-bool CBotClass::AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) )
-{
- m_rMaj = rMaj;
- return true;
-}
-
-// compile une méthode associée à une instance de classe
-// la méthode peut être déclarée par AddFunction ou par l'utilisateur
-
-CBotTypResult CBotClass::CompileMethode(const char* name,
- CBotVar* pThis, CBotVar** ppParams,
- CBotCStack* pStack, long& nIdent)
-{
- nIdent = 0; // oublie le précédent s'il y a lieu
-
- // recherche dans les méthodes déclarées par AddFunction
-
- CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent);
- if ( r.GivType() >= 0) return r;
-
- // recherche dans les méthodes déclarées par l'utilisateur
-
- r = m_pMethod->CompileCall(name, ppParams, nIdent);
- if ( r.Eq(TX_UNDEFCALL) && m_pParent != NULL )
- return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent);
- return r;
-}
-
-// exécute une méthode
-
-bool CBotClass::ExecuteMethode(long& nIdent, const char* name,
- CBotVar* pThis, CBotVar** ppParams,
- CBotVar* &pResult, CBotStack* &pStack,
- CBotToken* pToken)
-{
- int ret = m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
- if (ret>=0) return ret;
-
- ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this);
- return ret;
-}
-
-// rétabli la pile d'exécution
-
-void CBotClass::RestoreMethode(long& nIdent, const char* name, CBotVar* pThis,
- CBotVar** ppParams, CBotStack* &pStack)
-{
- m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, this);
-}
-
-
-
-
-bool CBotClass::SaveStaticState(FILE* pf)
-{
- if (!WriteWord( pf, CBOTVERSION*2)) return false;
-
- // sauve l'état des variables statiques dans les classes
- CBotClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if (!WriteWord( pf, 1)) return false;
- // enregistre le nom de la classe
- if (!WriteString( pf, p->GivName() )) return false;
-
- CBotVar* pv = p->GivVar();
- while( pv != NULL )
- {
- if ( pv->IsStatic() )
- {
- if (!WriteWord( pf, 1)) return false;
- if (!WriteString( pf, pv->GivName() )) return false;
-
- if ( !pv->Save0State(pf)) return false; // entête commune
- if ( !pv->Save1State(pf) ) return false; // sauve selon la classe fille
- if ( !WriteWord( pf, 0)) return false;
- }
- pv = pv->GivNext();
- }
-
- if (!WriteWord( pf, 0)) return false;
- p = p->m_ExNext;
- }
-
- if (!WriteWord( pf, 0)) return false;
- return true;
-}
-
-bool CBotClass::RestoreStaticState(FILE* pf)
-{
- CBotString ClassName, VarName;
- CBotClass* pClass;
- unsigned short w;
-
- if (!ReadWord( pf, w )) return false;
- if ( w != CBOTVERSION*2 ) return false;
-
- while (true)
- {
- if (!ReadWord( pf, w )) return false;
- if ( w == 0 ) return true;
-
- if (!ReadString( pf, ClassName )) return false;
- pClass = Find(ClassName);
-
- while (true)
- {
- if (!ReadWord( pf, w )) return false;
- if ( w == 0 ) break;
-
- CBotVar* pVar = NULL;
- CBotVar* pv = NULL;
-
- if (!ReadString( pf, VarName )) return false;
- if ( pClass != NULL ) pVar = pClass->GivItem(VarName);
-
- if (!CBotVar::RestoreState(pf, pv)) return false; // la variable temp
-
- if ( pVar != NULL ) pVar->Copy(pv);
- delete pv;
- }
- }
- return true;
-}
-
-
-/////////////////////////////////////////////////////////////////////
-
-CBotClassInst::CBotClassInst()
-{
- m_next = NULL;
- m_var = NULL;
- m_Parameters = NULL;
- m_expr = NULL;
- m_hasParams = false;
- m_nMethodeIdent = 0;
- name = "CBotClassInst";
-}
-
-CBotClassInst::~CBotClassInst()
-{
- delete m_var;
-// delete m_next; // fait par le destructeur de la classe de base ~CBotInstr()
-}
-
-// définition de pointeur(s) à un objet
-// du style
-// CPoint A, B ;
-
-CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
-{
- // cherche la classe correspondante
- if ( pClass == NULL )
- {
- pStack->SetStartError(p->GivStart());
- pClass = CBotClass::Find(p);
- if ( pClass == NULL )
- {
- // pas trouvé ? c'est bizare
- pStack->SetError(TX_NOCLASS, p);
- return NULL;
- }
- p = p->GivNext();
- }
-
- bool bIntrinsic = pClass->IsIntrinsic();
- CBotTypResult type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer, pClass );
- CBotClassInst* inst = (CBotClassInst*)CompileArray(p, pStack, type);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
-
- CBotCStack* pStk = pStack->TokenStack();
-
- inst = new CBotClassInst();
- /// \TODO Need to be revised and fixed after adding unit tests
- CBotToken token(pClass->GivName(), CBotString(), p->GivStart(), p->GivEnd());
- inst->SetToken(&token);
- CBotToken* vartoken = p;
-
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = type;
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable
- {
- pStk->SetStartError(vartoken->GivStart());
- pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK)) // avec des indices ?
- {
- delete inst; // n'est pas de type CBotInt
- p = vartoken; // revient sur le nom de la variable
-
- // compile une déclaration de tableau
-
- inst = (CBotClassInst*)CBotInstArray::Compile( p, pStk, type );
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- goto suite; // pas d'assignation, variable déjà créée
- }
-
-
- CBotVar* var;
- var = CBotVar::Create(vartoken->GivString(), type); // crée l'instance
-// var->SetClass(pClass);
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
-
- // regarde s'il y a des paramètres
- inst->m_hasParams = (p->GivType() == ID_OPENPAR);
-
- CBotVar* ppVars[1000];
- inst->m_Parameters = CompileParams(p, pStk, ppVars);
- if ( !pStk->IsOk() ) goto error;
-
- // s'il y a des paramètres, fait l'équivalent de l'instruction new
- // CPoint A ( 0, 0 ) est équivalent à
- // CPoint A = new CPoint( 0, 0 )
-
-// if ( NULL != inst->m_Parameters )
- if ( inst->m_hasParams )
- {
- // le constructeur existe-il ?
-// CBotString noname;
- CBotTypResult r = pClass->CompileMethode(pClass->GivName(), var, ppVars, pStk, inst->m_nMethodeIdent);
- delete pStk->TokenStack(); // libère le supplément de pile
- int typ = r.GivType();
-
- if (typ == TX_UNDEFCALL)
- {
- // si le constructeur n'existe pas
- if (inst->m_Parameters != NULL) // avec des paramètres
- {
- pStk->SetError(TX_NOCONST, vartoken);
- goto error;
- }
- typ = 0;
- }
-
- if (typ>20)
- {
- pStk->SetError(typ, vartoken->GivEnd());
- goto error;
- }
-
- }
-
- if (IsOfType(p, ID_ASS)) // avec une assignation ?
- {
- if (inst->m_hasParams)
- {
- pStk->SetError(TX_ENDOF, p->GivStart());
- goto error;
- }
-
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
- CBotClass* result = pStk->GivClass();
- if ( !pStk->GivTypResult(1).Eq(CBotTypNullPointer) &&
- ( !pStk->GivTypResult(1).Eq(CBotTypPointer) ||
- ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
-// if ( !bIntrinsic ) var->SetPointer(pStk->GivVar()->GivPointer());
- if ( !bIntrinsic )
- {
- // n'utilise pas le résultat sur la pile, pour imposer la classe
- CBotVar* pvar = CBotVar::Create("", pClass);
- var->SetPointer( pvar ); // var déjà déclarée pointe l'instance
- delete pvar; // supprime le second pointeur
- }
- var->SetInit(true); // marque le pointeur comme init
- }
- else if (inst->m_hasParams)
- {
- // crée l'objet sur le "tas"
- // avec un pointeur sur cet objet
- if ( !bIntrinsic )
- {
- CBotVar* pvar = CBotVar::Create("", pClass);
- var->SetPointer( pvar ); // var déjà déclarée pointe l'instance
- delete pvar; // supprime le second pointeur
- }
- var->SetInit(2); // marque le pointeur comme init
- }
-suite:
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compile la suivante
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (IsOfType(p, ID_SEP)) // instruction terminée
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// déclaration de l'instance d'une classe, par exemple:
-// CPoint A, B;
-
-bool CBotClassInst::Execute(CBotStack* &pj)
-{
- CBotVar* pThis = NULL;
-
- CBotStack* pile = pj->AddStack(this);//indispensable pour SetState()
-// if ( pile == EOX ) return true;
-
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
-
- bool bIntrincic = pClass->IsIntrinsic();
-
- // crée la variable de type pointeur à l'objet
-
- if ( pile->GivState()==0)
- {
- CBotString name = m_var->m_token.GivString();
- if ( bIntrincic )
- {
- pThis = CBotVar::Create(name, CBotTypResult( CBotTypIntrinsic, pClass ));
- }
- else
- {
- pThis = CBotVar::Create(name, CBotTypResult( CBotTypPointer, pClass ));
- }
-
- pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // lui attribut un numéro unique
- pile->AddVar(pThis); // la place sur la pile
- pile->IncState();
- }
-
- if ( pThis == NULL ) pThis = pile->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent);
-
- if ( pile->GivState()<3)
- {
- // y a-t-il une assignation ou des paramètres (constructeur)
-
-// CBotVarClass* pInstance = NULL;
-
- if ( m_expr != NULL )
- {
- // évalue l'expression pour l'assignation
- if (!m_expr->Execute(pile)) return false;
-
- if ( bIntrincic )
- {
- CBotVar* pv = pile->GivVar();
- if ( pv == NULL || pv->GivPointer() == NULL )
- {
- pile->SetError(TX_NULLPT, &m_token);
- return pj->Return(pile);
- }
- pThis->Copy(pile->GivVar(), false);
- }
- else
- {
- CBotVarClass* pInstance;
- pInstance = ((CBotVarPointer*)pile->GivVar())->GivPointer(); // valeur pour l'assignation
- pThis->SetPointer(pInstance);
- }
- pThis->SetInit(true);
- }
-
- else if ( m_hasParams )
- {
- // évalue le constructeur d'une instance
-
- if ( !bIntrincic && pile->GivState() == 1)
- {
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
-
- // crée une instance de la classe demandée
-
- CBotVarClass* pInstance;
- pInstance = (CBotVarClass*)CBotVar::Create("", pClass);
- pThis->SetPointer(pInstance);
- delete pInstance;
-
- pile->IncState();
- }
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( true )
- {
- pile2 = pile2->AddStack(); // de la place sur la pile pour les résultats
- if ( pile2->GivState() == 0 )
- {
- if (!p->Execute(pile2)) return false; // interrompu ici ?
- pile2->SetState(1);
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // crée une variable pour le résultat
- CBotVar* pResult = NULL; // constructeurs toujours void
-
- if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(),
- pThis, ppVars,
- pResult, pile2, GivToken())) return false; // interrompu
-
- pThis->SetInit(true);
- pThis->ConstructorSet(); // signale que le constructeur a été appelé
- pile->Return(pile2); // libère un bout de pile
-
-// pInstance = pThis->GivPointer();
-
- }
-
-// if ( !bIntrincic ) pThis->SetPointer(pInstance); // le fait pointer l'instance
-
- pile->SetState(3); // fini cette partie
- }
-
- if ( pile->IfStep() ) return false;
-
- if ( m_next2b != NULL &&
- !m_next2b->Execute(pile)) return false; // autre(s) définition(s)
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-
-
-void CBotClassInst::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotVar* pThis = NULL;
-
- CBotStack* pile = pj;
- if ( bMain ) pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- // crée la variable de type pointeur à l'objet
- {
- CBotString name = m_var->m_token.GivString();
- pThis = pile->FindVar(name);
- pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // lui attribut un numéro unique
- }
-
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
- bool bIntrincic = pClass->IsIntrinsic();
-
- if ( bMain && pile->GivState()<3)
- {
- // y a-t-il une assignation ou des paramètres (constructeur)
-
-// CBotVarClass* pInstance = NULL;
-
- if ( m_expr != NULL )
- {
- // évalue l'expression pour l'assignation
- m_expr->RestoreState(pile, bMain);
- return;
- }
-
- else if ( m_hasParams )
- {
- // évalue le constructeur d'une instance
-
- if ( !bIntrincic && pile->GivState() == 1)
- {
- return;
- }
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( true )
- {
- pile2 = pile2->RestoreStack(); // de la place sur la pile pour les résultats
- if ( pile2 == NULL ) return;
-
- if ( pile2->GivState() == 0 )
- {
- p->RestoreState(pile2, bMain); // interrompu ici ?
- return;
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // crée une variable pour le résultat
- CBotVar* pResult = NULL; // constructeurs toujours void
-
- pClass->RestoreMethode(m_nMethodeIdent, pClass->GivName(), pThis, ppVars, pile2);
- return;
- }
- }
-
- if ( m_next2b != NULL )
- m_next2b->RestoreState(pile, bMain); // autre(s) définition(s)
-}
-
-
-// test si un nom de procédure est déjà défini quelque part
-
-bool CBotClass::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
-{
- CBotString name = pToken->GivString();
-
- if ( CBotCall::CheckCall(name) ) return true;
-
- CBotFunction* pp = m_pMethod;
- while ( pp != NULL )
- {
- if ( pToken->GivString() == pp->GivName() )
- {
- // les paramètres sont-ils exactement les mêmes ?
- if ( pp->CheckParam( pParam ) )
- return true;
- }
- pp = pp->Next();
- }
-
- return false;
-}
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/.// + +///////////////////////////////////////////////////////////////////// +// Management of variables of class type +// + +#include "CBot.h" + + +CBotClass* CBotClass::m_ExClass = NULL; + +CBotClass::CBotClass(const char* name, CBotClass* pPapa, bool bIntrinsic) +{ + m_pParent = pPapa; + m_name = name; + m_pVar = NULL; + m_next = NULL; + m_pCalls = NULL; + m_pMethod = NULL; + m_rMaj = NULL; + m_IsDef = true; + m_bIntrinsic= bIntrinsic; + m_cptLock = 0; + m_cptOne = 0; + m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar; + + for ( int j= 0; j< 5 ; j++ ) + { + m_ProgInLock[j] = NULL; + } + + + // is located alone in the list + if (m_ExClass) m_ExClass->m_ExPrev = this; + m_ExNext = m_ExClass; + m_ExPrev = NULL; + m_ExClass = this; + +} + +CBotClass::~CBotClass() +{ + // removes the list of class + if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext; + else m_ExClass = m_ExNext; + + if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev; + m_ExPrev = NULL; + m_ExNext = NULL; + + delete m_pVar; + delete m_pCalls; + delete m_pMethod; + + delete m_next; // releases all of them on this level +} + + +void CBotClass::Free() +{ + while ( m_ExClass != NULL ) + { + delete m_ExClass; + } +} + +void CBotClass::Purge() +{ + if ( this == NULL ) return; + + delete m_pVar; + m_pVar = NULL; + delete m_pCalls; + m_pCalls = NULL; + delete m_pMethod; + m_pMethod = NULL; + m_IsDef = false; + + m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar; + + m_next->Purge(); + m_next = NULL; // no longer belongs to this chain +} + +bool CBotClass::Lock(CBotProgram* p) +{ + int i = m_cptLock++; + + if ( i == 0 ) + { + m_cptOne = 1; + m_ProgInLock[0] = p; + return true; + } + if ( p == m_ProgInLock[0] ) + { + m_cptOne++; + m_cptLock--; // has already been counted + return true; + } + + for ( int j = 1 ; j <= i ; j++) + { + if ( p == m_ProgInLock[j] ) + { + m_cptLock--; + return false; // already pending + } + } + + if ( i < 5 ) // max 5 in query + { + m_ProgInLock[i] = p; // located in a queue + } + else + m_cptLock--; + + return false; +} + +void CBotClass::Unlock() +{ + if ( --m_cptOne > 0 ) return ; + + int i = --m_cptLock; + if ( i<0 ) + { + m_cptLock = 0; + return; + } + + for ( int j= 0; j< i ; j++ ) + { + m_ProgInLock[j] = m_ProgInLock[j+1]; + } + m_ProgInLock[i] = 0; +} + +void CBotClass::FreeLock(CBotProgram* p) +{ + CBotClass* pClass = m_ExClass; + + while ( pClass != NULL ) + { + if ( p == pClass->m_ProgInLock[0] ) + { + pClass->m_cptLock -= pClass->m_cptOne; + pClass->m_cptOne = 0; + } + + for ( int j = 1; j < 5 ; j++ ) + if ( p == pClass->m_ProgInLock[j] ) + pClass->m_cptLock--; + + pClass = pClass->m_ExNext; + } +} + + + +bool CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate) +{ + CBotToken token(name, CBotString()); + CBotClass* pClass = type.GivClass(); + + CBotVar* pVar = CBotVar::Create( name, type ); +/// pVar->SetUniqNum(CBotVar::NextUniqNum()); + pVar->SetPrivate( mPrivate ); + + if ( pClass != NULL ) + { +// pVar->SetClass(pClass); + if ( type.Eq(CBotTypClass) ) + { + // adds a new statement for the object initialization + pVar->m_InitExpr = new CBotNew() ; + CBotToken nom( pClass->GivName() ); + pVar->m_InitExpr->SetToken(&nom); + } + } + return AddItem( pVar ); +} + + +bool CBotClass::AddItem(CBotVar* pVar) +{ + pVar->SetUniqNum(++m_nbVar); + + if ( m_pVar == NULL ) m_pVar = pVar; + else m_pVar->AddNext(pVar); + + return true; +} + +void CBotClass::AddNext(CBotClass* pClass) +{ + CBotClass* p = this; + while (p->m_next != NULL) p = p->m_next; + + p->m_next = pClass; +} + +CBotString CBotClass::GivName() +{ + return m_name; +} + +CBotClass* CBotClass::GivParent() +{ + if ( this == NULL ) return NULL; + return m_pParent; +} + +bool CBotClass::IsChildOf(CBotClass* pClass) +{ + CBotClass* p = this; + while ( p != NULL ) + { + if ( p == pClass ) return true; + p = p->m_pParent; + } + return false; +} + + +CBotVar* CBotClass::GivVar() +{ + return m_pVar; +} + +CBotVar* CBotClass::GivItem(const char* name) +{ + CBotVar* p = m_pVar; + + while ( p != NULL ) + { + if ( p->GivName() == name ) return p; + p = p->GivNext(); + } + if ( m_pParent != NULL ) return m_pParent->GivItem(name); + return NULL; +} + +CBotVar* CBotClass::GivItemRef(int nIdent) +{ + CBotVar* p = m_pVar; + + while ( p != NULL ) + { + if ( p->GivUniqNum() == nIdent ) return p; + p = p->GivNext(); + } + if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent); + return NULL; +} + +bool CBotClass::IsIntrinsic() +{ + return m_bIntrinsic; +} + +CBotClass* CBotClass::Find(CBotToken* &pToken) +{ + return Find(pToken->GivString()); +} + +CBotClass* CBotClass::Find(const char* name) +{ + CBotClass* p = m_ExClass; + + while ( p != NULL ) + { + if ( p->GivName() == name ) return p; + p = p->m_ExNext; + } + + return NULL; +} + +bool CBotClass::AddFunction(const char* name, + bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception), + CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar)) +{ + // stores pointers to the two functions + CBotCallMethode* p = m_pCalls; + CBotCallMethode* pp = NULL; + + while ( p != NULL ) + { + if ( name == p->GivName() ) + { + if ( pp == NULL ) m_pCalls = p->m_next; + else pp->m_next = p->m_next; + delete p; + break; + } + pp = p; + p = p->m_next; + } + + p = new CBotCallMethode(name, rExec, rCompile); + + if (m_pCalls == NULL) m_pCalls = p; + else m_pCalls->AddNext(p); // added to the list + + return true; +} + +bool CBotClass::AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) ) +{ + m_rMaj = rMaj; + return true; +} + +// compiles a method associated with an instance of class +// the method can be declared by the user or AddFunction + +CBotTypResult CBotClass::CompileMethode(const char* name, + CBotVar* pThis, CBotVar** ppParams, + CBotCStack* pStack, long& nIdent) +{ + nIdent = 0; // forget the previous one if necessary + + // find the methods declared by AddFunction + + CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent); + if ( r.GivType() >= 0) return r; + + // find the methods declared by user + + r = m_pMethod->CompileCall(name, ppParams, nIdent); + if ( r.Eq(TX_UNDEFCALL) && m_pParent != NULL ) + return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent); + return r; +} + +// executes a method + +bool CBotClass::ExecuteMethode(long& nIdent, const char* name, + CBotVar* pThis, CBotVar** ppParams, + CBotVar* &pResult, CBotStack* &pStack, + CBotToken* pToken) +{ + int ret = m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken); + if (ret>=0) return ret; + + ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this); + return ret; +} + +// restored the execution stack + +void CBotClass::RestoreMethode(long& nIdent, const char* name, CBotVar* pThis, + CBotVar** ppParams, CBotStack* &pStack) +{ + m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, this); +} + + + + +bool CBotClass::SaveStaticState(FILE* pf) +{ + if (!WriteWord( pf, CBOTVERSION*2)) return false; + + // saves the state of static variables in classes + CBotClass* p = m_ExClass; + + while ( p != NULL ) + { + if (!WriteWord( pf, 1)) return false; + // save the name of the class + if (!WriteString( pf, p->GivName() )) return false; + + CBotVar* pv = p->GivVar(); + while( pv != NULL ) + { + if ( pv->IsStatic() ) + { + if (!WriteWord( pf, 1)) return false; + if (!WriteString( pf, pv->GivName() )) return false; + + if ( !pv->Save0State(pf)) return false; // common header + if ( !pv->Save1State(pf) ) return false; // saves as the child class + if ( !WriteWord( pf, 0)) return false; + } + pv = pv->GivNext(); + } + + if (!WriteWord( pf, 0)) return false; + p = p->m_ExNext; + } + + if (!WriteWord( pf, 0)) return false; + return true; +} + +bool CBotClass::RestoreStaticState(FILE* pf) +{ + CBotString ClassName, VarName; + CBotClass* pClass; + unsigned short w; + + if (!ReadWord( pf, w )) return false; + if ( w != CBOTVERSION*2 ) return false; + + while (true) + { + if (!ReadWord( pf, w )) return false; + if ( w == 0 ) return true; + + if (!ReadString( pf, ClassName )) return false; + pClass = Find(ClassName); + + while (true) + { + if (!ReadWord( pf, w )) return false; + if ( w == 0 ) break; + + CBotVar* pVar = NULL; + CBotVar* pv = NULL; + + if (!ReadString( pf, VarName )) return false; + if ( pClass != NULL ) pVar = pClass->GivItem(VarName); + + if (!CBotVar::RestoreState(pf, pv)) return false; // the temp variable + + if ( pVar != NULL ) pVar->Copy(pv); + delete pv; + } + } + return true; +} + + +///////////////////////////////////////////////////////////////////// + +CBotClassInst::CBotClassInst() +{ + m_next = NULL; + m_var = NULL; + m_Parameters = NULL; + m_expr = NULL; + m_hasParams = false; + m_nMethodeIdent = 0; + name = "CBotClassInst"; +} + +CBotClassInst::~CBotClassInst() +{ + delete m_var; +// delete m_next; // done by the destructor of the base class ~CBotInstr() +} + +// definition of pointer (s) to an object +// style +// CPoint A, B ; + +CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) +{ + // seeks the corresponding classes + if ( pClass == NULL ) + { + pStack->SetStartError(p->GivStart()); + pClass = CBotClass::Find(p); + if ( pClass == NULL ) + { + // not found? is bizare + pStack->SetError(TX_NOCLASS, p); + return NULL; + } + p = p->GivNext(); + } + + bool bIntrinsic = pClass->IsIntrinsic(); + CBotTypResult type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer, pClass ); + CBotClassInst* inst = (CBotClassInst*)CompileArray(p, pStack, type); + if ( inst != NULL || !pStack->IsOk() ) return inst; + + CBotCStack* pStk = pStack->TokenStack(); + + inst = new CBotClassInst(); + /// \TODO Need to be revised and fixed after adding unit tests + CBotToken token(pClass->GivName(), CBotString(), p->GivStart(), p->GivEnd()); + inst->SetToken(&token); + CBotToken* vartoken = p; + + if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) ) + { + ((CBotLeftExprVar*)inst->m_var)->m_typevar = type; + if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable + { + pStk->SetStartError(vartoken->GivStart()); + pStk->SetError(TX_REDEFVAR, vartoken->GivEnd()); + goto error; + } + + if (IsOfType(p, ID_OPBRK)) // with any clues? + { + delete inst; // is not type CBotInt + p = vartoken; // returns to the variable name + + // compiles declaration an array + + inst = (CBotClassInst*)CBotInstArray::Compile( p, pStk, type ); + + if (!pStk->IsOk() ) + { + pStk->SetError(TX_CLBRK, p->GivStart()); + goto error; + } + goto suite; // no assignment, variable already created + } + + + CBotVar* var; + var = CBotVar::Create(vartoken->GivString(), type); // creates the instance +// var->SetClass(pClass); + var->SetUniqNum( + ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum()); + // its attribute a unique number + pStack->AddVar(var); // placed on the stack + + // look if there are parameters + inst->m_hasParams = (p->GivType() == ID_OPENPAR); + + CBotVar* ppVars[1000]; + inst->m_Parameters = CompileParams(p, pStk, ppVars); + if ( !pStk->IsOk() ) goto error; + + // if there are parameters, is the equivalent to the stament "new" + // CPoint A ( 0, 0 ) is equivalent to + // CPoint A = new CPoint( 0, 0 ) + +// if ( NULL != inst->m_Parameters ) + if ( inst->m_hasParams ) + { + // the constructor is there? +// CBotString noname; + CBotTypResult r = pClass->CompileMethode(pClass->GivName(), var, ppVars, pStk, inst->m_nMethodeIdent); + delete pStk->TokenStack(); // releases the supplement stack + int typ = r.GivType(); + + if (typ == TX_UNDEFCALL) + { + // si le constructeur n'existe pas + if (inst->m_Parameters != NULL) // with parameters + { + pStk->SetError(TX_NOCONST, vartoken); + goto error; + } + typ = 0; + } + + if (typ>20) + { + pStk->SetError(typ, vartoken->GivEnd()); + goto error; + } + + } + + if (IsOfType(p, ID_ASS)) // with a assignment? + { + if (inst->m_hasParams) + { + pStk->SetError(TX_ENDOF, p->GivStart()); + goto error; + } + + if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) ) + { + goto error; + } + CBotClass* result = pStk->GivClass(); + if ( !pStk->GivTypResult(1).Eq(CBotTypNullPointer) && + ( !pStk->GivTypResult(1).Eq(CBotTypPointer) || + ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ? + { + pStk->SetError(TX_BADTYPE, p->GivStart()); + goto error; + } +// if ( !bIntrinsic ) var->SetPointer(pStk->GivVar()->GivPointer()); + if ( !bIntrinsic ) + { + // does not use the result on the stack, to impose the class + CBotVar* pvar = CBotVar::Create("", pClass); + var->SetPointer( pvar ); // variable already declared instance pointer + delete pvar; // removes the second pointer + } + var->SetInit(true); // marks the pointer as init + } + else if (inst->m_hasParams) + { + // creates the object on the "job" (\TODO "tas") + // with a pointer to the object + if ( !bIntrinsic ) + { + CBotVar* pvar = CBotVar::Create("", pClass); + var->SetPointer( pvar ); // variable already declared instance pointer + delete pvar; // removes the second pointer + } + var->SetInit(2); // marks the pointer as init + } +suite: + if (IsOfType(p, ID_COMMA)) // several chained definitions + { + if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compiles the following + { + return pStack->Return(inst, pStk); + } + } + + if (IsOfType(p, ID_SEP)) // complete instruction + { + return pStack->Return(inst, pStk); + } + + pStk->SetError(TX_ENDOF, p->GivStart()); + } + +error: + delete inst; + return pStack->Return(NULL, pStk); +} + +// declaration of the instance of a class, for example: +// CPoint A, B; + +bool CBotClassInst::Execute(CBotStack* &pj) +{ + CBotVar* pThis = NULL; + + CBotStack* pile = pj->AddStack(this);//essential for SetState() +// if ( pile == EOX ) return true; + + CBotToken* pt = &m_token; + CBotClass* pClass = CBotClass::Find(pt); + + bool bIntrincic = pClass->IsIntrinsic(); + + // creates the variable of type pointer to the object + + if ( pile->GivState()==0) + { + CBotString name = m_var->m_token.GivString(); + if ( bIntrincic ) + { + pThis = CBotVar::Create(name, CBotTypResult( CBotTypIntrinsic, pClass )); + } + else + { + pThis = CBotVar::Create(name, CBotTypResult( CBotTypPointer, pClass )); + } + + pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // its attribute as unique number + pile->AddVar(pThis); // place on the stack + pile->IncState(); + } + + if ( pThis == NULL ) pThis = pile->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent); + + if ( pile->GivState()<3) + { + // ss there an assignment or parameters (contructor) + +// CBotVarClass* pInstance = NULL; + + if ( m_expr != NULL ) + { + // evaluates the expression for the assignment + if (!m_expr->Execute(pile)) return false; + + if ( bIntrincic ) + { + CBotVar* pv = pile->GivVar(); + if ( pv == NULL || pv->GivPointer() == NULL ) + { + pile->SetError(TX_NULLPT, &m_token); + return pj->Return(pile); + } + pThis->Copy(pile->GivVar(), false); + } + else + { + CBotVarClass* pInstance; + pInstance = ((CBotVarPointer*)pile->GivVar())->GivPointer(); // value for the assignment + pThis->SetPointer(pInstance); + } + pThis->SetInit(true); + } + + else if ( m_hasParams ) + { + // evaluates the constructor of an instance + + if ( !bIntrincic && pile->GivState() == 1) + { + CBotToken* pt = &m_token; + CBotClass* pClass = CBotClass::Find(pt); + + // creates an instance of the requested class + + CBotVarClass* pInstance; + pInstance = (CBotVarClass*)CBotVar::Create("", pClass); + pThis->SetPointer(pInstance); + delete pInstance; + + pile->IncState(); + } + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluates the parameters + // and places the values ​​on the stack + // to (can) be interrupted (broken) at any time + + if ( p != NULL) while ( true ) + { + pile2 = pile2->AddStack(); // place on the stack for the results + if ( pile2->GivState() == 0 ) + { + if (!p->Execute(pile2)) return false; // interrupted here? + pile2->SetState(1); + } + ppVars[i++] = pile2->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + // creates a variable for the result + CBotVar* pResult = NULL; // constructor still void + + if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(), + pThis, ppVars, + pResult, pile2, GivToken())) return false; // interrupt + + pThis->SetInit(true); + pThis->ConstructorSet(); // indicates that the constructor has been called + pile->Return(pile2); // releases a piece of stack + +// pInstance = pThis->GivPointer(); + + } + +// if ( !bIntrincic ) pThis->SetPointer(pInstance); // a pointer to the instance + + pile->SetState(3); // finished this part + } + + if ( pile->IfStep() ) return false; + + if ( m_next2b != NULL && + !m_next2b->Execute(pile)) return false; // other (s) definition (s) + + return pj->Return( pile ); // transmits below (further) +} + + + +void CBotClassInst::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotVar* pThis = NULL; + + CBotStack* pile = pj; + if ( bMain ) pile = pj->RestoreStack(this); + if ( pile == NULL ) return; + + // creates the variable of type pointer to the object + { + CBotString name = m_var->m_token.GivString(); + pThis = pile->FindVar(name); + pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // its attribute a unique number + } + + CBotToken* pt = &m_token; + CBotClass* pClass = CBotClass::Find(pt); + bool bIntrincic = pClass->IsIntrinsic(); + + if ( bMain && pile->GivState()<3) + { + // is there an assignment or parameters (constructor) + +// CBotVarClass* pInstance = NULL; + + if ( m_expr != NULL ) + { + // evaluates the expression for the assignment + m_expr->RestoreState(pile, bMain); + return; + } + + else if ( m_hasParams ) + { + // evaluates the constructor of an instance + + if ( !bIntrincic && pile->GivState() == 1) + { + return; + } + + CBotVar* ppVars[1000]; + CBotStack* pile2 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluates the parameters + // and the values an the stack + // for the ability to be interrupted at any time (\TODO pour pouvoir être interrompu n'importe quand) + + if ( p != NULL) while ( true ) + { + pile2 = pile2->RestoreStack(); // place on the stack for the results + if ( pile2 == NULL ) return; + + if ( pile2->GivState() == 0 ) + { + p->RestoreState(pile2, bMain); // interrupted here? + return; + } + ppVars[i++] = pile2->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + // creates a variable for the result + CBotVar* pResult = NULL; // constructor still void + + pClass->RestoreMethode(m_nMethodeIdent, pClass->GivName(), pThis, ppVars, pile2); + return; + } + } + + if ( m_next2b != NULL ) + m_next2b->RestoreState(pile, bMain); // other(s) definition(s) +} + + +// test if a procedure name is already defined somewhere + +bool CBotClass::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) +{ + CBotString name = pToken->GivString(); + + if ( CBotCall::CheckCall(name) ) return true; + + CBotFunction* pp = m_pMethod; + while ( pp != NULL ) + { + if ( pToken->GivString() == pp->GivName() ) + { + // are their parameters exactly the same? + if ( pp->CheckParam( pParam ) ) + return true; + } + pp = pp->Next(); + } + + return false; +} + diff --git a/src/CBot/CBotCompExpr.cpp b/src/CBot/CBotCompExpr.cpp index 0f296d5..8ae507f 100644 --- a/src/CBot/CBotCompExpr.cpp +++ b/src/CBot/CBotCompExpr.cpp @@ -1,131 +1,133 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////
-// expression du genre Opérande1 > Opérande2
-// Opérande1 != Opérande2
-// etc.
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotCompExpr::CBotCompExpr()
-{
- m_leftop =
- m_rightop = NULL;
- name = "CBotCompExpr";
-}
-
-CBotCompExpr::~CBotCompExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-fichier plus utilise;
-
-// compile une instruction de type A < B
-
-CBotInstr* CBotCompExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->AddStack();
-
- CBotInstr* left = CBotAddExpr::Compile( p, pStk ); // expression A + B à gauche
- if (left == NULL) return pStack->Return(NULL, pStk); // erreur
-
- if ( p->GetType() == ID_HI ||
- p->GetType() == ID_LO ||
- p->GetType() == ID_HS ||
- p->GetType() == ID_LS ||
- p->GetType() == ID_EQ ||
- p->GetType() == ID_NE) // les diverses comparaisons
- {
- CBotCompExpr* inst = new CBotCompExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
- int type1, type2;
- type1 = pStack->GetType();
-
- p = p->Next();
- if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression A + B à droite
- {
- type2 = pStack->GetType();
- // les résultats sont-ils compatibles
- if ( type1 == type2 )
- {
- inst->m_leftop = left;
- pStk->SetVar(new CBotVar(NULL, CBotTypBoolean));
- // le résultat est un boolean
- return pStack->Return(inst, pStk);
- }
- }
-
- delete left;
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- return pStack->Return(left, pStk);
-}
-
-
-// fait l'opération
-
-bool CBotCompExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this);
-// if ( pStk1 == EOX ) return TRUE;
-
- if ( pStk1->GetState() == 0 && !m_leftop->Execute(pStk1) ) return FALSE; // interrompu ici ?
-
- pStk1->SetState(1); // opération terminée
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- CBotStack* pStk2 = pStk1->AddStack();
-
- if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrompu ici ?
-
- int type1 = pStk1->GetType();
- int type2 = pStk2->GetType();
-
- CBotVar* result = new CBotVar( NULL, CBotTypBoolean );
-
- switch (GetTokenType())
- {
- case ID_LO:
- result->Lo(pStk1->GetVar(), pStk2->GetVar()); // inférieur
- break;
- case ID_HI:
- result->Hi(pStk1->GetVar(), pStk2->GetVar()); // supérieur
- break;
- case ID_LS:
- result->Ls(pStk1->GetVar(), pStk2->GetVar()); // inférieur ou égal
- break;
- case ID_HS:
- result->Hs(pStk1->GetVar(), pStk2->GetVar()); // supérieur ou égal
- break;
- case ID_EQ:
- result->Eq(pStk1->GetVar(), pStk2->GetVar()); // égal
- break;
- case ID_NE:
- result->Ne(pStk1->GetVar(), pStk2->GetVar()); // différent
- break;
- }
- pStk2->SetVar(result); // met le résultat sur la pile
-
- pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk1); // transmet le résultat
-}
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +/////////////////////////////////////////////////// +// expression of type Opérande1 > Opérande2 +// Opérande1 != Opérande2 +// etc. + +#include "CBot.h" + +// various constructeurs + +CBotCompExpr::CBotCompExpr() +{ + m_leftop = + m_rightop = NULL; + name = "CBotCompExpr"; +} + +CBotCompExpr::~CBotCompExpr() +{ + delete m_leftop; + delete m_rightop; +} + +fichier plus utilise; + +// compile instruction of type A < B + +CBotInstr* CBotCompExpr::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCStack* pStk = pStack->AddStack(); + + CBotInstr* left = CBotAddExpr::Compile( p, pStk ); // expression A + B left + if (left == NULL) return pStack->Return(NULL, pStk); // error + + if ( p->GetType() == ID_HI || + p->GetType() == ID_LO || + p->GetType() == ID_HS || + p->GetType() == ID_LS || + p->GetType() == ID_EQ || + p->GetType() == ID_NE) // the various comparisons + { + CBotCompExpr* inst = new CBotCompExpr(); // element for operation + inst->SetToken(p); // stores the operation + + int type1, type2; + type1 = pStack->GetType(); + + p = p->Next(); + if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression A + B right + { + type2 = pStack->GetType(); + // are the results compatible + if ( type1 == type2 ) + { + inst->m_leftop = left; + pStk->SetVar(new CBotVar(NULL, CBotTypBoolean)); + // the result is a boolean + return pStack->Return(inst, pStk); + } + } + + delete left; + delete inst; + return pStack->Return(NULL, pStk); + } + + return pStack->Return(left, pStk); +} + + +// perform the operation + +bool CBotCompExpr::Execute(CBotStack* &pStack) +{ + CBotStack* pStk1 = pStack->AddStack(this); +// if ( pStk1 == EOX ) return TRUE; + + if ( pStk1->GetState() == 0 && !m_leftop->Execute(pStk1) ) return FALSE; // interrupted here ? + + pStk1->SetState(1); // finished + + // requires a little more stack to not touch the result of the left + CBotStack* pStk2 = pStk1->AddStack(); + + if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrupted here ? + + int type1 = pStk1->GetType(); + int type2 = pStk2->GetType(); + + CBotVar* result = new CBotVar( NULL, CBotTypBoolean ); + + switch (GetTokenType()) + { + case ID_LO: + result->Lo(pStk1->GetVar(), pStk2->GetVar()); // lower + break; + case ID_HI: + result->Hi(pStk1->GetVar(), pStk2->GetVar()); // higher + break; + case ID_LS: + result->Ls(pStk1->GetVar(), pStk2->GetVar()); // lower or equal + break; + case ID_HS: + result->Hs(pStk1->GetVar(), pStk2->GetVar()); // higher of equal + break; + case ID_EQ: + result->Eq(pStk1->GetVar(), pStk2->GetVar()); // equal + break; + case ID_NE: + result->Ne(pStk1->GetVar(), pStk2->GetVar()); // not equal + break; + } + pStk2->SetVar(result); // puts the result on the stack + + pStk1->Return(pStk2); // frees the stack + return pStack->Return(pStk1); // transmit the result +} + diff --git a/src/CBot/CBotDll.h b/src/CBot/CBotDll.h index f2e2297..269ef94 100644 --- a/src/CBot/CBotDll.h +++ b/src/CBot/CBotDll.h @@ -1,1071 +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/.////////////////////////////////////////////////////////////////////////
-#ifndef _CBOTDLL_H_
-#define _CBOTDLL_H_
-/**
- * \file CBotDll.h
- * \brief Library for interpretation of CBOT language
- */
-
-#include <stdio.h>
-#include "resource.h"
-#include <map>
-#include <cstring>
-
-
-#define CBOTVERSION 104
-
-////////////////////////////////////////////////////////////////////////
-// forward declaration of needed classes
-
-class CBotToken; // program turned into "tokens
-class CBotStack; // for the execution stack
-class CBotClass; // class of object
-class CBotInstr; // instruction to be executed
-class CBotFunction; // user functions
-class CBotVar; // variables
-class CBotVarClass; // instance of class
-class CBotVarPointer; // pointer to an instance of class
-class CBotCall; // fonctions
-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 of an object
- * \param type type of created result, see CBotType
- */
- CBotTypResult(int type);
-
- /**
- * \brief CBotTypResult constructor for simple types (CBotTypInt to CBotTypString)
- * \param type type of created result, see CBotType
- * \param name
- */
- // pour les types simples (CBotTypInt à CBotTypString)
- CBotTypResult(int type, const char* name);
- // pour les types pointeur et classe intrinsic
- CBotTypResult(int type, CBotClass* pClass);
- // idem à partir de l'instance d'une classe
- CBotTypResult(int type, CBotTypResult elem);
- // pour les tableaux de variables
-
- CBotTypResult(const CBotTypResult& typ);
- // pour les assignations
- CBotTypResult();
- // pour par défaut
- ~CBotTypResult();
-
- int GivType(int mode = 0) const;
- // rend le type CBotTyp* du résultat
-
- void SetType(int n);
- // modifie le type
-
- CBotClass* GivClass() const;
- // rend le pointeur à la classe (pour les CBotTypClass, CBotTypPointer)
-
- int GivLimite() const;
- // rend la taille limite du tableau (CBotTypArray)
-
- void SetLimite(int n);
- // fixe une limite au tableau
-
- void SetArray(int* max );
- // idem avec une liste de dimension (tableaux de tableaux)
-
- CBotTypResult& GivTypElem() const;
- // rend le type des éléments du tableau (CBotTypArray)
-
- bool Compare(const CBotTypResult& typ) const;
- // compare si les types sont compatibles
- bool Eq(int type) const;
- // compare le type
-
- CBotTypResult&
- operator=(const CBotTypResult& src);
- // copie un type complet dans un autre
-private:
- int m_type;
- CBotTypResult* m_pNext; // pour les types de types
- CBotClass* m_pClass; // pour les dérivés de classe
- int m_limite; // limitation des tableaux
- friend class CBotVarClass;
- friend class CBotVarPointer;
-};
-
-/*
-// pour définir un résultat en sortie, utiliser par exemple
-
- // pour rendre un simple Float
- return CBotTypResult( CBotTypFloat );
-
-
- // pour rendre un tableau de string
- return CBotTypResult( CBotTypArray, CBotTypResult( CBotTypString ) );
-
- // pour rendre un tableau de tableau de "point"
- CBotTypResult typPoint( CBotTypIntrinsic, "point" );
- CBotTypResult arrPoint( CBotTypArray, typPoint );
- return CBotTypResult( CBotTypArray, arrPoint );
-*/
-
-
-////////////////////////////////////////////////////////////////////////
-// Gestion des erreurs compilation et exécution
-////////////////////////////////////////////////////////////////////////
-
-// voici la liste des erreurs pouvant être retournées par le module
-// pour la compilation
-
-#define CBotErrOpenPar 5000 // manque la parenthèse ouvrante
-#define CBotErrClosePar 5001 // manque la parenthèse fermante
-#define CBotErrNotBoolean 5002 // l'expression doit être un boolean
-#define CBotErrUndefVar 5003 // variable non déclarée
-#define CBotErrBadLeft 5004 // assignation impossible ( 5 = ... )
-#define CBotErrNoTerminator 5005 // point-virgule attendu
-#define CBotErrCaseOut 5006 // case en dehors d'un switch
-// CBotErrNoTerm 5007, plus utile
-#define CBotErrCloseBlock 5008 // manque " } "
-#define CBotErrElseWhitoutIf 5009 // else sans if correspondant
-#define CBotErrOpenBlock 5010 // manque " { "
-#define CBotErrBadType1 5011 // mauvais type pour l'assignation
-#define CBotErrRedefVar 5012 // redéfinition de la variable
-#define CBotErrBadType2 5013 // 2 opérandes de type incompatibles
-#define CBotErrUndefCall 5014 // routine inconnue
-#define CBotErrNoDoubleDots 5015 // " : " attendu
-// CBotErrWhile 5016, plus utile
-#define CBotErrBreakOutside 5017 // break en dehors d'une boucle
-#define CBotErrUndefLabel 5019 // label inconnu
-#define CBotErrLabel 5018 // label ne peut se mettre ici
-#define CBotErrNoCase 5020 // manque " case "
-#define CBotErrBadNum 5021 // nombre attendu
-#define CBotErrVoid 5022 // " void " pas possible ici
-#define CBotErrNoType 5023 // déclaration de type attendue
-#define CBotErrNoVar 5024 // nom de variable attendu
-#define CBotErrNoFunc 5025 // nom de fonction attendu
-#define CBotErrOverParam 5026 // trop de paramètres
-#define CBotErrRedefFunc 5027 // cette fonction existe déjà
-#define CBotErrLowParam 5028 // pas assez de paramètres
-#define CBotErrBadParam 5029 // mauvais types de paramètres
-#define CBotErrNbParam 5030 // mauvais nombre de paramètres
-#define CBotErrUndefItem 5031 // élément n'existe pas dans la classe
-#define CBotErrUndefClass 5032 // variable n'est pas une classe
-#define CBotErrNoConstruct 5033 // pas de constructeur approprié
-#define CBotErrRedefClass 5034 // classe existe déjà
-#define CBotErrCloseIndex 5035 // " ] " attendu
-#define CBotErrReserved 5036 // mot réservé (par un DefineNum)
-#define CBotErrBadNew 5037 // mauvais paramètre pour new
-#define CBotErrOpenIndex 5038 // " [ " attendu
-#define CBotErrBadString 5039 // chaîne de caractère attendue
-#define CBotErrBadIndex 5040 // mauvais type d'index "[ false ]"
-#define CBotErrPrivate 5041 // élément protégé
-#define CBotErrNoPublic 5042 // manque le mot "public"
-
-// voici la liste des erreurs pouvant être retournées par le module
-// pour l'exécution
-
-#define CBotErrZeroDiv 6000 // division par zéro
-#define CBotErrNotInit 6001 // variable non initialisée
-#define CBotErrBadThrow 6002 // throw d'une valeur négative
-#define CBotErrNoRetVal 6003 // fonction n'a pas retourné de résultat
-#define CBotErrNoRun 6004 // Run() sans fonction active
-#define CBotErrUndefFunc 6005 // appel d'une fonction qui n'existe plus
-#define CBotErrNotClass 6006 // cette classe n'existe pas
-#define CBotErrNull 6007 // pointeur null
-#define CBotErrNan 6008 // calcul avec un NAN
-#define CBotErrOutArray 6009 // index hors du tableau
-#define CBotErrStackOver 6010 // dépassement de la pile
-#define CBotErrDeletedPtr 6011 // pointeur à un objet détruit
-
-#define CBotErrFileOpen 6012 // ouverture du fichier impossible
-#define CBotErrNotOpen 6013 // canal pas ouvert
-#define CBotErrRead 6014 // erreur à la lecture
-#define CBotErrWrite 6015 // erreur à l'écriture
-
-// d'autres valeurs peuvent être rendues
-// par exemple les exceptions rendues par les routines externes
-// et les " throw " avec un nombre quelconque.
-
-
-////////////////////////////////////////////////////////////////////////
-//
-// car CString fait partie de MFC pas utilisé ici.
-//
-// ( toutes les fonctions ne sont pas encore implémentées )
-
-/** \brief CBotString Class used to work on strings */
-class CBotString
-{
-public:
- CBotString();
- CBotString(const char* p);
- CBotString(const CBotString& p);
- ~CBotString();
-
- void Empty();
- bool IsEmpty() const;
- int GivLength();
- int Find(const char c);
- int Find(const char* lpsz);
- int ReverseFind(const char c);
- int ReverseFind(const char* lpsz);
- bool LoadString(unsigned int id);
- CBotString Mid(int nFirst, int nCount) const;
- CBotString Mid(int nFirst) const;
- CBotString Mid(int start, int lg=-1);
- CBotString Left(int nCount) const;
- CBotString Right(int nCount) const;
- int Compare(const char* lpsz) const;
- void MakeUpper();
- void MakeLower();
-
-
- /**
- * \brief Overloaded oprators to work on CBotString classes
- */
- const CBotString& operator=(const CBotString& stringSrc);
- const CBotString& operator=(const char ch);
- const CBotString& operator=(const char* pString);
- const CBotString& operator+(const CBotString& str);
- friend CBotString operator+(const CBotString& string, const char* lpsz);
-
- const CBotString& operator+=(const char ch);
- const CBotString& operator+=(const CBotString& str);
- bool operator==(const CBotString& str);
- bool operator==(const char* p);
- bool operator!=(const CBotString& str);
- bool operator!=(const char* p);
- bool operator>(const CBotString& str);
- bool operator>(const char* p);
- bool operator>=(const CBotString& str);
- bool operator>=(const char* p);
- bool operator<(const CBotString& str);
- bool operator<(const char* p);
- bool operator<=(const CBotString& str);
- bool operator<=(const char* p);
-
- operator const char*() const; // as a C string
-
-
-private:
-
- /** \brief Pointer to string */
- char* m_ptr;
-
- /** \brief Length of the string */
- int m_lg;
-
- /** \brief Keeps the string corresponding to keyword ID */
- static const std::map<EID, char *> s_keywordString;
-
- /**
- * \brief MapIdToString maps given ID to its string equivalent
- * \param id Provided identifier
- * \return string if found, else NullString
- */
- static const char * MapIdToString(EID id);
-};
-
-
-// idem avec la gestion en tableau
-
-class CBotStringArray : public CBotString
-{
-private:
- int m_nSize; // nombre d'éléments
- int m_nMaxSize; // taille réservée
- CBotString* m_pData; // ^aux données
-
-public:
- CBotStringArray();
- ~CBotStringArray();
- void SetSize(int nb);
- int GivSize();
- void Add(const CBotString& str);
- CBotString& operator[](int nIndex);
-
- CBotString& ElementAt(int nIndex);
-};
-
-// différents mode pour GetPosition
-enum CBotGet
-{
- GetPosExtern = 1,
- GetPosNom = 2,
- GetPosParam = 3,
- GetPosBloc = 4
-};
-
-////////////////////////////////////////////////////////////////////
-// classe principale gérant un programme CBot
-//
-
-class CBotProgram
-{
-private:
- CBotFunction* m_Prog; // les fonctions définies par l'utilisateur
- CBotFunction* m_pRun; // la fonction de base pour l'exécution
- CBotClass* m_pClass; // les classes définies dans cette partie
- CBotStack* m_pStack; // la pile d'exécution
- CBotVar* m_pInstance; // instance de la classe parent
- friend class CBotFunction;
-
- int m_ErrorCode;
- int m_ErrorStart;
- int m_ErrorEnd;
-
- long m_Ident; // identificateur associé
-
-public:
- static
- CBotString m_DebugVarStr; // a fin de debug
- bool m_bDebugDD; // idem déclanchable par robot
-
- bool m_bCompileClass;
-
-public:
- static
- void Init();
- // initialise le module (défini les mots clefs pour les erreurs)
- // doit être fait une fois (et une seule) au tout début
- static
- void Free();
- // libère les zones mémoires statiques
-
- static
- int GivVersion();
- // donne la version de la librairie CBOT
-
-
- CBotProgram();
- CBotProgram(CBotVar* pInstance);
- ~CBotProgram();
-
- bool Compile( const char* program, CBotStringArray& ListFonctions, void* pUser = NULL);
- // compile le programme donné en texte
- // retourne false s'il y a une erreur à la compilation
- // voir GetCompileError() pour récupérer l'erreur
- // ListFonctions retourne le nom des fonctions déclarées extern
- // pUser permet de passer un pointeur pour les routines définies par AddFunction
-
- void SetIdent(long n);
- // associe un identificateur avec l'instance CBotProgram
-
- long GivIdent();
- // redonne l'identificateur
-
- int GivError();
- bool GetError(int& code, int& start, int& end);
- bool GetError(int& code, int& start, int& end, CBotProgram* &pProg);
- // si true
- // donne l'erreur trouvée à la compilation
- // ou à l'exécution
- // start et end délimite le bloc où se trouve l'erreur
- // pProg permet de savoir dans quel "module" s'est produite l'erreur d'exécution
- static
- CBotString GivErrorText(int code);
-
-
- bool Start(const char* name);
- // définie quelle fonction doit être exécutée
- // retourne false si la fontion name n'est pas trouvée
- // le programme ne fait rien, il faut appeller Run() pour cela
-
- bool Run(void* pUser = NULL, int timer = -1);
- // exécute le programme
- // retourne false si le programme a été suspendu
- // retourne true si le programme s'est terminé avec ou sans erreur
- // timer = 0 permet de faire une avance pas à pas
-
- bool GetRunPos(const char* &FunctionName, int &start, int &end);
- // donne la position dans le programme en exécution
- // retourne false si on n'est pas en exécution (programme terminé)
- // FunctionName est un pointeur rendu sur le nom de la fonction
- // start et end la position dans le texte du token en traitement
-
- CBotVar* GivStackVars(const char* &FunctionName, int level);
- // permet d'obtenir le pointeur aux variables sur la pile d'exécution
- // level est un paramètre d'entrée, 0 pour le dernier niveau, -1, -2, etc pour les autres niveau
- // la valeur retournée (CBotVar*) est une liste de variable (ou NULL)
- // qui peut être traité que la liste des paramètres reçu par une routine
- // FunctionName donne le nom de la fonction où se trouvent ces variables
- // FunctionName == NULL signifiant qu'on est plus dans le programme (selon level)
-
- void Stop();
- // arrête l'exécution du programme
- // quitte donc le mode "suspendu"
-
- static
- void SetTimer(int n);
- // défini le nombre de pas (parties d'instructions) à faire
- // dans Run() 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));
- // cet appel permet d'ajouter de manière externe (**)
- // une nouvelle fonction utilisable par le programme CBot
-
- static
- bool DefineNum(const char* name, long val);
-
- bool SaveState(FILE* pf);
- // sauvegarde l'état d'exécution dans le fichier
- // le fichier doit avoir été ouvert avec l'appel fopen de cette dll
- // sinon le système plante
- bool RestoreState(FILE* pf);
- // rétablie l'état de l'exécution depuis le fichier
- // le programme compilé doit évidemment être identique
-
- bool GetPosition(const char* name, int& start, int& stop,
- CBotGet modestart = GetPosExtern,
- CBotGet modestop = GetPosBloc);
- // donne la position d'une routine dans le texte d'origine
- // le mode permet de choisir l'élément à trouver pour le début et la fin
- // voir les modes ci-dessus dans CBotGet
-
-
- CBotFunction* GivFunctions();
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// routines pour la gestion d'un fichier (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:
- Pour définir une fonction externe, il faut procéder ainsi:
-
- a) définir une routine pour la compilation
- cette routine reçois la liste des paramètres (sans valeurs)
- et retourne soit un type de résultat (CBotTyp... ou 0 = void)
- soit un numéro d'erreur
- b) définir une routine pour l'exécution
- cette rourine reCoit la liste des paramètres (avec valeurs),
- une variable pour stocker le résultat (selon le type donné à la compilation)
-
- Par exemple, une routine qui calcule la moyenne d'une liste de paramètres */
-
-int cMoyenne(CBotVar* &pVar, CBotString& ClassName)
-{
- if ( pVar == NULL ) return 6001; // il n'y a aucun paramètre !
-
- while ( pVar != NULL )
- {
- if ( pVar->GivType() > CBotTypDouble ) return 6002; // ce n'est pas un nombre
- pVar = pVar -> GivNext();
- }
-
- return CBotTypFloat; // le type du résultat pourrait dépendre des paramètres !
-}
-
-
-bool rMoyenne(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); // retourne la valeur moyenne
-
- return true; // opération totalement terminée
-}
-
-#endif
-
-/////////////////////////////////////////////////////////////////////////////////
-// Classe pour la gestion des variables
-
-// peuvent être utile à l'exterieur du module
-// ( il n'est pour l'instant pas prévu de pouvoir créer ces objets en externe )
-
-// résultats pour GivInit()
-#define IS_UNDEF 0 // variable indéfinie
-#define IS_DEF 1 // variable définie
-#define IS_NAN 999 // variable définie comme étant not a number
-
-// type de variable SetPrivate / IsPrivate
-#define PR_PUBLIC 0 // variable publique
-#define PR_READ 1 // read only
-#define PR_PROTECT 2 // protected (héritage)
-#define PR_PRIVATE 3 // strictement privée
-
-class CBotVar
-{
-protected:
- CBotToken* m_token; // le token correspondant
-
- CBotVar* m_next; // liste de variables
- friend class CBotStack;
- friend class CBotCStack;
- friend class CBotInstrCall;
- friend class CBotProgram;
-
- CBotTypResult m_type; // type de valeur
-
- int m_binit; // pas initialisée ?
- CBotVarClass* m_pMyThis; // ^élément this correspondant
- void* m_pUserPtr; // ^données user s'il y a lieu
- bool m_bStatic; // élément static (dans une classe)
- int m_mPrivate; // élément public, protected ou private ?
-
- CBotInstr* m_InitExpr; // expression pour le contenu initial
- CBotInstr* m_LimExpr; // liste des limites pour un tableau
- friend class CBotClass;
- friend class CBotVarClass;
- friend class CBotVarPointer;
- friend class CBotVarArray;
-
- long m_ident; // identificateur unique
- static long m_identcpt; // compteur
-
-public:
- CBotVar();
-virtual ~CBotVar( ); // destructeur
-
- static
- CBotVar* Create( const char* name, CBotTypResult type);
- // idem à partir du type complet
-
- static
- CBotVar* Create( const char* name, CBotClass* pClass);
- // idem pour une instance d'une classe connue
-
- 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);
- // associe un pointeur utilisateur à une instance
-
- virtual void SetIdent(long UniqId);
- // associe un identificateur unique à une instance
- // ( c'est à l'utilisateur de s'assurer que l'id est unique)
-
- void* GivUserPtr();
- // rend le pointeur associé à la variable
-
- CBotString GivName(); // le nom de la variable, s'il est connu
- ////////////////////////////////////////////////////////////////////////////////////
- void SetName(const char* name); // change le nom de la variable
-
- int GivType(int mode = 0); // rend le type de base (int) de la variable
- ////////////////////////////////////////////////////////////////////////////////////////
-
- CBotTypResult GivTypResult(int mode = 0); // rend le type complet de la variable
-
-
- CBotToken* GivToken();
- void SetType(CBotTypResult& type);
-
- void SetInit(int bInit); // met la variable dans l'état IS_UNDEF, IS_DEF, IS_NAN
-
- int GivInit(); // donne l'état de la 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
-
- virtual
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- virtual
- CBotVar* GivItemRef(int nIdent); // idem à partir du n° ref
-
- virtual
- CBotVar* GivItem(int row, bool bGrow = false);
-
- virtual
- CBotVar* GivItemList(); // donne la liste des éléments
-
- CBotVar* GivStaticVar(); // rend le pointeur à la variable si elle est statique
-
- bool IsElemOfClass(const char* name);
- // dit si l'élément appartient à la classe "name"
- // rend true si l'objet est d'une classe fille
-
- CBotVar* GivNext(); // prochaine variable dans la liste (paramètres)
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- void AddNext(CBotVar* pVar); // ajoute dans une liste
-
- virtual
- void Copy(CBotVar* pSrc, bool bName = true); // fait une copie de la variable
-
- virtual void SetValInt(int val, const char* name = NULL);
- // initialise avec une valeur entière (#)
- /////////////////////////////////////////////////////////////////////////////////
-
- virtual void SetValFloat(float val); // initialise avec une valeur réelle (#)
- ////////////////////////////////////////////////////////////////////////////////
-
- virtual void SetValString(const char* p);// initialise avec une valeur chaîne (#)
- ////////////////////////////////////////////////////////////////////////////////
-
- virtual int GivValInt(); // demande la valeur entière (#)
- ////////////////////////////////////////////////////////////////////////
-
- virtual float GivValFloat(); // demande la valeur réelle (#)
- ///////////////////////////////////////////////////////////////////////
-
- virtual
- CBotString GivValString(); // demande la valeur chaîne (#)
- ///////////////////////////////////////////////////////////////////////
-
- 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); // soustraction
- virtual void Mul(CBotVar* left, CBotVar* right); // multiplication
- virtual int Div(CBotVar* left, CBotVar* right); // division
- virtual int Modulo(CBotVar* left, CBotVar* right); // reste de division
- virtual void Power(CBotVar* left, CBotVar* right); // puissance
-
- 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 (#)
- les méthodes SetValInt() SetValFloat() et SetValString()
- ne peuvent êtes appellées qu'avec des objets respectivement entier, réelle ou chaîne
- toujours s'assurer du type de la variable avant d'appeller ces méthodes
-
- if ( pVar->GivType() == CBotInt() ) pVar->SetValFloat( 3.3 ); // plante !!
-
- les méthodes GivValInt(), GivValFloat() et GivValString()
- font des conversions de valeur,
- GivValString() fonctionne sur des nombres (rend la chaîne correspondante)
- par contre il ne faut pas faire de GivValInt() avec une variable de type chaîne !
-*/
-
-
-
-////////////////////////////////////////////////////////////////////////
-// Gestion des classes
-////////////////////////////////////////////////////////////////////////
-
-// classe pour définir de nouvelle classes dans le language CBOT
-// par exemple pour définir la classe CPoint (x,y)
-
-class CBotClass
-{
-private:
- static
- CBotClass* m_ExClass; // liste des classes existante à un moment donné
- CBotClass* m_ExNext; // pour cette liste générale
- CBotClass* m_ExPrev; // pour cette liste générale
-
-private:
- CBotClass* m_pParent; // classe parent
- CBotString m_name; // nom de cette classe-ci
- int m_nbVar; // nombre de variables dans la chaîne
- CBotVar* m_pVar; // contenu de la classe
- bool m_bIntrinsic; // classe intrinsèque
- CBotClass* m_next; // chaine les classe
- CBotCallMethode* m_pCalls; // liste des méthodes définie en externe
- CBotFunction* m_pMethod; // liste des méthodes compilées
- void (*m_rMaj) ( CBotVar* pThis, void* pUser );
- friend class CBotVarClass;
- int m_cptLock; // pour Lock / UnLock
- int m_cptOne; // pour réentrance Lock
- CBotProgram* m_ProgInLock[5];// processus en attente pour synchro
-
-public:
- bool m_IsDef; // marque si est définie ou pas encore
-
- CBotClass( const char* name,
- CBotClass* pParent, bool bIntrinsic = false ); // constructeur
- // Dès qu'une classe est créée, elle est connue
- // partout dans CBot
- // le mode intrinsic donne une classe qui n'est pas gérée par des pointeurs
-
- ~CBotClass( ); // destructeur
-
- bool AddFunction(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
- // cet appel permet d'ajouter de manière externe (**)
- // une nouvelle méthode utilisable par les objets de cette classe
-
- bool AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) );
- // défini la routine qui sera appellée pour mettre à jour les élements de la classe
-
- bool AddItem(CBotString name, CBotTypResult type, int mPrivate = PR_PUBLIC);
- // ajoute un élément à la classe
-// bool AddItem(CBotString name, CBotClass* pClass);
- // idem pour des éléments appartenant à pClass
- bool AddItem(CBotVar* pVar);
- // idem en passant le pointeur à une instance d'une variable
- // l'objet est pris tel quel, il ne faut donc pas le détruire
-
-
-
- // idem en donnant un élément de type CBotVar
- void AddNext(CBotClass* pClass);
-
- CBotString GivName(); // rend le nom de la classe
- CBotClass* GivParent(); // donne la classe père (ou NULL)
-
- // dit si une classe est dérivée (Extends) d'une autre
- // rend true aussi si les classes sont identiques
- bool IsChildOf(CBotClass* pClass);
-
- static
- CBotClass* Find(CBotToken* &pToken); // trouve une classe d'après son nom
-
- static
- CBotClass* Find(const char* name);
-
- CBotVar* GivVar(); // rend la liste des variables
- CBotVar* GivItem(const char* name); // l'une des variables selon son nom
- 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);
-
- // compile une classe déclarée par l'utilisateur
- 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 // nombre limite des DefineNum
-
-/////////////////////////////////////////////////////////////////////////////////////
-// gestion des jetons (tokens)
-
-#define TokenTypKeyWord 1 // un mot clef du language (voir TokenKeyWord)
-#define TokenTypNum 2 // un nombre
-#define TokenTypString 3 // une chaine
-#define TokenTypVar 4 // un nom de variable
-#define TokenTypDef 5 // une valeur selon DefineNum
-
-#define TokenKeyWord 2000 // les mots clefs du langage
-#define TokenKeyDeclare 2100 // mots clefs pour déclarations (int, float,..)
-#define TokenKeyVal 2200 // les mots représentant une "valeur" (true, false, null, nan)
-#define TokenKeyOp 2300 // les opérateurs
-
-
-class CBotToken
-{
-private:
- static
- CBotStringArray m_ListKeyWords; // liste des mots clefs du language
- static
- int m_ListIdKeyWords[200]; // les codes correspondants
-
- static
- CBotStringArray m_ListKeyDefine; // les noms définis par un DefineNum
- static
- long m_ListKeyNums[MAXDEFNUM]; // les valeurs associées
-
-private:
- CBotToken* m_next; // suivant dans la liste
- CBotToken* m_prev;
- int m_type; // type de Token
- long m_IdKeyWord; // numéro du mot clef si c'en est un
- // ou valeur du "define"
-
- CBotString m_Text; // mot trouvé comme token
- CBotString m_Sep; // séparateurs qui suivent
-
- int m_start; // position dans le texte d'origine (programme)
- int m_end; // itou pour la fin du token
-
- static
- int GivKeyWords(const char* w); // est-ce un mot clef ?
- static
- bool GivKeyDefNum(const char* w, CBotToken* &token);
-
- static
- void LoadKeyWords(); // fait la liste des mots clefs
-
-public:
- 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);
- // constructeur
- ~CBotToken(); // destructeur
-
- int GivType(); // rend le type du token
-
- CBotString& GivString(); // rend la chaine correspondant à ce token
-
- CBotString& GivSep(); // rend le séparateur suivant le token
-
- int GivStart(); // position du début dans le texte
- int GivEnd(); // position de fin dans le texte
-
- CBotToken* GivNext(); // rend le suivant dans la liste
- CBotToken* GivPrev(); // rend le Précédent dans la liste
-
- static
- CBotToken* CompileTokens(const char* p, int& error);
- // transforme tout le programme
- 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();
- void AddNext(CBotToken* p); // ajoute un token (une copie)
-
- static
- CBotToken* NextToken(char* &program, int& error, bool first = false);
- // trouve le prochain token
- const CBotToken&
- operator=(const CBotToken& src);
-
- static
- void Free();
-};
-
-
-
-#if 0
-////////////////////////////////////////////////////////////////////////
-// Exemples d'utilisation
-// Définition de classes et de fonctions
-
-
-// définie la classe globale CPoint
-// --------------------------------
- m_pClassPoint = new CBotClass("CPoint", NULL);
- // ajoute le composant ".x"
- m_pClassPoint->AddItem("x", CBotTypResult(CBotTypFloat));
- // ajoute le composant ".y"
- m_pClassPoint->AddItem("y", CBotTypResult(CBotTypFloat));
- // le joueur peut alors utiliser les instructions
- // CPoint position; position.x = 12; position.y = -13.6
-
-// définie la classe CColobotObject
-// --------------------------------
-// cette classe gère tous les objets dans le monde de COLOBOT
-// le programme utilisateur "main" appartient à cette classe
- m_pClassObject = new CBotClass("CColobotObject", m_pClassBase);
- // ajoute le composant ".position"
- m_pClassObject->AddItem("position", m_pClassPoint);
- // ajoute le composant ".type"
- m_pClassObject->AddItem("type", CBotTypResult(CBotTypShort));
- // ajoute une définition de constante
- m_pClassObject->AddConst("ROBOT", CBotTypShort, 1); // ROBOT équivalent à la valeur 1
- // ajoute la routine FIND
- m_pClassObject->AddFunction( rCompFind, rDoFind );
- // le joueur peut maintenant utiliser les instructions
- // CColobotObject chose; chose = FIND( ROBOT )
-
-
-
-// définie la classe CColobotRobot dérivée de CColobotObject
-// ---------------------------------------------------------
-// les programmes "main" associés aux robots font partie de cette classe
- m_pClassRobot = new CBotClass("CColobotRobot", m_pClassObject);
- // ajoute la routine GOTO
- m_pClassRobot->AddFunction( rCompGoto, rDoGoto );
- // le joueur peut maintenant faire
- // GOTO( FIND ( ROBOT ) );
-
-
-// crée une instance de la classe Robot
-// ------------------------------------
-// par exemple un nouveau robot qui vient d'être fabriqué
- CBotVar* m_pMonRobot = new CBotVar("MonRobot", m_pClassRobot);
-
-// compile le programme main pour ce robot-là
-// ------------------------------------------
- CString LeProgramme( "void main() {GOTO(0, 0); return 0;}" );
- if ( !m_pMonRobot->Compile( LeProgramme ) ) {gestion d'erreur...};
-
-// construit une pile pour l'interpréteur
-// --------------------------------------
- CBotStack* pStack = new CBotStack(NULL);
-
-// exécute le programme main
-// -------------------------
- while( false = m_pMonRobot->Execute( "main", pStack ))
- {
- // programme suspendu
- // on pourrait passer la main à un autre (en sauvegardant pStack pour ce robot-là)
- };
- // programme "main" terminé !
-
-
-
-
-// routine implémentant l'instruction GOTO( CPoint pos )
-bool rDoGoto( CBotVar* pVar, CBotVar* pResult, int& exception )
-{
- if (pVar->GivType() != CBotTypeClass ||
- pVar->IsElemOfClas("CPoint") ) { exception = 6522; return false; )
- // le paramètre n'est pas de la bonne classe ?
- // NB en fait ce contrôle est déjà fait par la routine pour la compilation
-
- m_PosToGo.Copy( pVar ); // garde la position à atteindre (object type CBotVar)
-
- // ou alors
- CBotVar* temp;
- temp = pVar->GivItem("x"); // trouve forcément pour un object de type "CPoint"
- ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
- m_PosToGo.x = temp->GivValFloat();
-
- temp = pVar->GivItem("y"); // trouve forcément pour un object de type "CPoint"
- ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
- m_PosToGo.y = temp->GivValFloat();
-
- return (m_CurentPos == m_PosToGo); // rend true si la position est atteinte
- // rend false s'il faut patienter encore
-}
-
-#endif
-#endif //_CBOTDLL_H_
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. +//////////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef _CBOTDLL_H_ +#define _CBOTDLL_H_ +/** + * \file CBotDll.h + * \brief Library for interpretation of CBOT language + */ + +#include <stdio.h> +#include "resource.h" +#include <map> +#include <cstring> + + +#define CBOTVERSION 104 + +//////////////////////////////////////////////////////////////////////// +// forward declaration of needed classes + +class CBotToken; // program turned into "tokens +class CBotStack; // for the execution stack +class CBotClass; // class of object +class CBotInstr; // instruction to be executed +class CBotFunction; // user functions +class CBotVar; // variables +class CBotVarClass; // instance of class +class CBotVarPointer; // pointer to an instance of class +class CBotCall; // functions +class CBotCallMethode; // methods +class CBotDefParam; // parameter list +class CBotCStack; // stack + + +//////////////////////////////////////////////////////////////////////// +// Variables management +//////////////////////////////////////////////////////////////////////// + +/** \brief CBotType Defines known types. This types are modeled on Java types. Do not change the order of elements */ +enum CBotType +{ + CBotTypVoid = 0, + CBotTypByte = 1, //n + CBotTypShort = 2, //n + CBotTypChar = 3, //n + CBotTypInt = 4, + CBotTypLong = 5, //n + CBotTypFloat = 6, + CBotTypDouble = 7, //n + CBotTypBoolean = 8, + CBotTypString = 9, + + CBotTypArrayPointer = 10, // array of variables + CBotTypArrayBody = 11, // same but creates an instance + + CBotTypPointer = 12, // pointer to an instance + CBotTypNullPointer = 13, // null pointer is special + CBotTypClass = 15, + CBotTypIntrinsic = 16 // instance of a class intrinsic +}; +//n = not implemented yet + +// for SetUserPtr when deleting an object +#define OBJECTDELETED ((void*)-1) +// value set before initialization +#define OBJECTCREATED ((void*)-2) + + +/** \brief CBotTypResult class to define the complete type of a result*/ +class CBotTypResult +{ +public: + /** + * \brief CBotTypResult constructor for simple types (CBotTypInt to CBotTypString) + * \param type type of created result, see CBotType + */ + CBotTypResult(int type); + // for simple types (CBotTypInt à CBotTypString) + + + CBotTypResult(int type, const char* name); + // for pointer types and intrinsic classes + + CBotTypResult(int type, CBotClass* pClass); + // for the instance of a class + + CBotTypResult(int type, CBotTypResult elem); + // for arrays of variables + + CBotTypResult(const CBotTypResult& typ); + // for assignments + + CBotTypResult(); + // for default + + ~CBotTypResult(); + + int GivType(int mode = 0) const; + // returns type CBotType* as a result + + void SetType(int n); + // modifies a type + + CBotClass* GivClass() const; + // makes the pointer to the class (for CBotTypClass, CBotTypPointer) + + int GivLimite() const; + // returns limit size of table (CBotTypArray) + + void SetLimite(int n); + // set limit to the table + + void SetArray(int* max ); + // set limits for a list of dimensions (arrays of arrays) + + CBotTypResult& GivTypElem() const; + // returns type of array elements (CBotTypArray) + // rend le type des éléments du tableau (CBotTypArray) + + bool Compare(const CBotTypResult& typ) const; + // compares whether the types are compatible + bool Eq(int type) const; + // compare type + + CBotTypResult& operator=(const CBotTypResult& src); + // copy a complete type in another + +private: + int m_type; + CBotTypResult* m_pNext; // for the types of type + CBotClass* m_pClass; // for the derivatives of class + int m_limite; // limits of tables + friend class CBotVarClass; + friend class CBotVarPointer; +}; + +/* +// to define a result as output, using for example + + // to return a simple Float + return CBotTypResult( CBotTypFloat ); + + + // to return a string array + return CBotTypResult( CBotTypArray, CBotTypResult( CBotTypString ) ); + + // to return un array of array of "point" class + CBotTypResult typPoint( CBotTypIntrinsic, "point" ); + CBotTypResult arrPoint( CBotTypArray, typPoint ); + return CBotTypResult( CBotTypArray, arrPoint ); +*/ + + +//////////////////////////////////////////////////////////////////////// +// Error Handling of compilation and execution +//////////////////////////////////////////////////////////////////////// + +// Here are the list of errors that can be returned by the module +// for compilation + +#define CBotErrOpenPar 5000 // missing the opening parenthesis +#define CBotErrClosePar 5001 // missing the closing parenthesis +#define CBotErrNotBoolean 5002 // expression must be a boolean +#define CBotErrUndefVar 5003 // undeclared variable +#define CBotErrBadLeft 5004 // assignment impossible ( 5 = ... ) +#define CBotErrNoTerminator 5005 // semicolon expected +#define CBotErrCaseOut 5006 // case outside a switch +// CBotErrNoTerm 5007, plus utile +#define CBotErrCloseBlock 5008 // missing " } " +#define CBotErrElseWhitoutIf 5009 // else without matching if +#define CBotErrOpenBlock 5010 // missing " { " +#define CBotErrBadType1 5011 // wrong type for the assignment +#define CBotErrRedefVar 5012 // redefinition of the variable +#define CBotErrBadType2 5013 // Two operands are incompatible +#define CBotErrUndefCall 5014 // routine undefined +#define CBotErrNoDoubleDots 5015 // " : " expected +// CBotErrWhile 5016, plus utile +#define CBotErrBreakOutside 5017 // break outside of a loop +#define CBotErrUndefLabel 5019 // label udnefined +#define CBotErrLabel 5018 // label ne peut se mettre ici (label can not get here) +#define CBotErrNoCase 5020 // missing " case " +#define CBotErrBadNum 5021 // expected number +#define CBotErrVoid 5022 // " void " not possible here +#define CBotErrNoType 5023 // type declaration expected +#define CBotErrNoVar 5024 // variable name expected +#define CBotErrNoFunc 5025 // expected function name +#define CBotErrOverParam 5026 // too many parameters +#define CBotErrRedefFunc 5027 // this function already exists +#define CBotErrLowParam 5028 // not enough parameters +#define CBotErrBadParam 5029 // wrong types of parameters +#define CBotErrNbParam 5030 // wrong number of parameters +#define CBotErrUndefItem 5031 // element does not exist in the class +#define CBotErrUndefClass 5032 // variable is not a class +#define CBotErrNoConstruct 5033 // no appropriate constructor +#define CBotErrRedefClass 5034 // class already exists +#define CBotErrCloseIndex 5035 // " ] " expected +#define CBotErrReserved 5036 // reserved word (for a DefineNum) +#define CBotErrBadNew 5037 // wrong setting for new +#define CBotErrOpenIndex 5038 // " [ " expected +#define CBotErrBadString 5039 // expected string +#define CBotErrBadIndex 5040 // wrong index type "[ false ]" +#define CBotErrPrivate 5041 // protected item +#define CBotErrNoPublic 5042 // missing word "public" + +// here is the list of errors that can be returned by the module +// for the execution + +#define CBotErrZeroDiv 6000 // division by zero +#define CBotErrNotInit 6001 // uninitialized variable +#define CBotErrBadThrow 6002 // throw a negative value +#define CBotErrNoRetVal 6003 // function did not return results +#define CBotErrNoRun 6004 // Run() without active function +#define CBotErrUndefFunc 6005 // calling a function that no longer exists +#define CBotErrNotClass 6006 // this class does not exist +#define CBotErrNull 6007 // null pointer +#define CBotErrNan 6008 // calculation with a NAN +#define CBotErrOutArray 6009 // index out of array +#define CBotErrStackOver 6010 // stack overflow +#define CBotErrDeletedPtr 6011 // pointer to an object destroyed + +#define CBotErrFileOpen 6012 // cannot open the file +#define CBotErrNotOpen 6013 // channel not open +#define CBotErrRead 6014 // error while reading +#define CBotErrWrite 6015 // writing error + + +// other values ​​may be returned +// for example exceptions returned by external routines +// and " throw " with any number. + + +//////////////////////////////////////////////////////////////////////// +// +// as part of MFC CString not used here. +// +// ( all functions are not implemented yet ) + +/** \brief CBotString Class used to work on strings */ +class CBotString +{ +public: + CBotString(); + CBotString(const char* p); + CBotString(const CBotString& p); + ~CBotString(); + + void Empty(); + bool IsEmpty() const; + int GivLength(); + int Find(const char c); + int Find(const char* lpsz); + int ReverseFind(const char c); + int ReverseFind(const char* lpsz); + bool LoadString(unsigned int id); + CBotString Mid(int nFirst, int nCount) const; + CBotString Mid(int nFirst) const; + CBotString Mid(int start, int lg=-1); + CBotString Left(int nCount) const; + CBotString Right(int nCount) const; + int Compare(const char* lpsz) const; + void MakeUpper(); + void MakeLower(); + + + /** + * \brief Overloaded oprators to work on CBotString classes + */ + const CBotString& operator=(const CBotString& stringSrc); + const CBotString& operator=(const char ch); + const CBotString& operator=(const char* pString); + const CBotString& operator+(const CBotString& str); + friend CBotString operator+(const CBotString& string, const char* lpsz); + + const CBotString& operator+=(const char ch); + const CBotString& operator+=(const CBotString& str); + bool operator==(const CBotString& str); + bool operator==(const char* p); + bool operator!=(const CBotString& str); + bool operator!=(const char* p); + bool operator>(const CBotString& str); + bool operator>(const char* p); + bool operator>=(const CBotString& str); + bool operator>=(const char* p); + bool operator<(const CBotString& str); + bool operator<(const char* p); + bool operator<=(const CBotString& str); + bool operator<=(const char* p); + + operator const char*() const; // as a C string + + +private: + + /** \brief Pointer to string */ + char* m_ptr; + + /** \brief Length of the string */ + int m_lg; + + /** \brief Keeps the string corresponding to keyword ID */ + static const std::map<EID, char *> s_keywordString; + + /** + * \brief MapIdToString maps given ID to its string equivalent + * \param id Provided identifier + * \return string if found, else NullString + */ + static const char * MapIdToString(EID id); +}; + + +// Class used to array management + +class CBotStringArray : public CBotString +{ +private: + int m_nSize; // number of elements + int m_nMaxSize; // reserved size + CBotString* m_pData; // ^data + +public: + CBotStringArray(); + ~CBotStringArray(); + void SetSize(int nb); + int GivSize(); + void Add(const CBotString& str); + CBotString& operator[](int nIndex); + + CBotString& ElementAt(int nIndex); +}; + +// different modes for GetPosition +enum CBotGet +{ + GetPosExtern = 1, + GetPosNom = 2, + GetPosParam = 3, + GetPosBloc = 4 +}; + +//////////////////////////////////////////////////////////////////// +// main class managing CBot program +// + +class CBotProgram +{ +private: + CBotFunction* m_Prog; // the user-defined functions + CBotFunction* m_pRun; // the basic function for the execution + CBotClass* m_pClass; // classes defined in this part + CBotStack* m_pStack; // execution stack + CBotVar* m_pInstance; // instance of the parent class + friend class CBotFunction; + + int m_ErrorCode; + int m_ErrorStart; + int m_ErrorEnd; + + long m_Ident; // associated identifier + +public: + static CBotString m_DebugVarStr; // end of a debug + bool m_bDebugDD; // idem déclanchable par robot \TODO ??? + bool m_bCompileClass; + +public: + static void Init(); + // initializes the module (defined keywords for errors) + // should be done once (and only one) at the beginning + static + void Free(); + // frees the static memory areas + + static + int GivVersion(); + // gives the version of the library CBOT + + + CBotProgram(); + CBotProgram(CBotVar* pInstance); + ~CBotProgram(); + + bool Compile( const char* program, CBotStringArray& ListFonctions, void* pUser = NULL); + // compiles the program given in text + // returns false if an error at compile + // see GetCompileError () to retrieve the error + // ListFonctions returns the names of functions declared as extern + // pUser can pass a pointer to routines defined by AddFunction + + void SetIdent(long n); + // associates an identifier with the instance CBotProgram + + long GivIdent(); + // gives the identifier + + int GivError(); + bool GetError(int& code, int& start, int& end); + bool GetError(int& code, int& start, int& end, CBotProgram* &pProg); + // if true + // gives the error found in the compilation + // or execution + // delimits the start and end block where the error + // pProg lets you know what "module" has produced runtime error + static CBotString GivErrorText(int code); + + + bool Start(const char* name); + // defines what function should be executed + // returns false if the funtion name is not found + // the program does nothing, we must call Run () for this + + bool Run(void* pUser = NULL, int timer = -1); + // executes the program + // returns false if the program was suspended + // returns true if the program ended with or without error + // timer = 0 allows to advance step by step + + bool GetRunPos(const char* &FunctionName, int &start, int &end); + // gives the position in the executing program + // returns false if it is not running (program completion) + // FunctionName is a pointer made to the name of the function + // start and end position in the text of the token processing + + CBotVar* GivStackVars(const char* &FunctionName, int level); + // provides the pointer to the variables on the execution stack + // level is an input parameter, 0 for the last level, -1, -2, etc. for the other levels + // the return value (CBotVar *) is a variable list (or NULL) + // that can be processed as the list of parameters received by a routine + // FunctionName gives the name of the function where are these variables + // FunctionName == NULL means that is more in a program (depending on level) + + void Stop(); + // stops execution of the program + // therefore quits "suspend" mode + + static + void SetTimer(int n); + // defines the number of steps (parts of instructions) to done + // in Run() before rendering hand "false" \TODO avant de rendre la main "false" + + static + bool AddFunction(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)); + // call this to add externally (**) + // a new function used by the program CBoT + + static + bool DefineNum(const char* name, long val); + + bool SaveState(FILE* pf); + // backup the execution status in the file + // the file must have been opened with the fopen call this dll (\TODO this library??) + // if the system crashes + bool RestoreState(FILE* pf); + // restores the state of execution from file + // the compiled program must obviously be the same + + bool GetPosition(const char* name, int& start, int& stop, + CBotGet modestart = GetPosExtern, + CBotGet modestop = GetPosBloc); + // gives the position of a routine in the original text + // the user can select the item to find from the beginning to the end + // see the above modes in CBotGet + + + CBotFunction* GivFunctions(); +}; + + +/////////////////////////////////////////////////////////////////////////////// +// routines for file management (* FILE) + FILE* fOpen(const char* name, const char* mode); + int fClose(FILE* filehandle); + size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle); + size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle); + + +#if 0 +/* +(**) Note: + To define an external function, proceed as follows: + + a) define a routine for compilation + this routine receive list of parameters (no values) + and either returns a result type (CBotTyp... or 0 = void) + or an error number + b) define a routine for the execution + this routine receive list of parameters (with valeurs), + a variable to store the result (according to the given type at compile time) + + For example, a routine which calculates the mean of a parameter list */ + +int cMean(CBotVar* &pVar, CBotString& ClassName) +{ + if ( pVar == NULL ) return 6001; // there is no parameter! + + while ( pVar != NULL ) + { + if ( pVar->GivType() > CBotTypDouble ) return 6002; // this is not a number + pVar = pVar -> GivNext(); + } + + return CBotTypFloat; // the type of the result may depend on the parameters! +} + + +bool rMean(CBotVar* pVar, CBotVar* pResult, int& Exception) +{ + float total = 0; + int nb = 0; + while (pVar != NULL) + { + total += pVar->GivValFloat(); + pVar = pVar->GivNext(); + nb++; + } + pResult->SetValFloat(total/nb); // returns the mean value + + return true; // operation fully completed +} + +#endif + +///////////////////////////////////////////////////////////////////////////////// +// Class for managing variables + +// may be useful to the outside of the module +// ( it is currently not expected to be able to create these objects in outer ) + +// results of GivInit() +#define IS_UNDEF 0 // undefined variable +#define IS_DEF 1 // variable defined +#define IS_NAN 999 // variable defined as not a number + +// variable type SetPrivate / IsPrivate +#define PR_PUBLIC 0 // public variable +#define PR_READ 1 // read only +#define PR_PROTECT 2 // protected (inheritance) +#define PR_PRIVATE 3 // strictly private + +class CBotVar +{ +protected: + CBotToken* m_token; // the corresponding token + + CBotVar* m_next; // list of variables + friend class CBotStack; + friend class CBotCStack; + friend class CBotInstrCall; + friend class CBotProgram; + + CBotTypResult m_type; // type of value + + int m_binit; // not initialized? + CBotVarClass* m_pMyThis; // ^ corresponding this element + void* m_pUserPtr; // ^user data if necessary + bool m_bStatic; // static element (in class) + int m_mPrivate; // element public, protected or private? + + CBotInstr* m_InitExpr; // expression for the original content + CBotInstr* m_LimExpr; // list of limits for a table + friend class CBotClass; + friend class CBotVarClass; + friend class CBotVarPointer; + friend class CBotVarArray; + + long m_ident; // unique identifier + static long m_identcpt; // counter + +public: + CBotVar(); +virtual ~CBotVar( ); // destructor + + static + CBotVar* Create( const char* name, CBotTypResult type); + // creates from a complete type + + static + CBotVar* Create( const char* name, CBotClass* pClass); + // creates from one instance of a known class + + static + CBotVar* Create( const CBotToken* name, int type ); + static + CBotVar* Create( const CBotToken* name, CBotTypResult type ); + + static + CBotVar* Create( const char* name, int type, CBotClass* pClass); + + static + CBotVar* Create( CBotVar* pVar ); + + + void SetUserPtr(void* pUser); + // associate a user pointer to an instance + + virtual void SetIdent(long UniqId); + // associates a unique identifier to an instance + // ( it is used to ensure that the id is unique) + + void* GivUserPtr(); + // makes the pointer associated with the variable + + CBotString GivName(); // the name of the variable, if known + //////////////////////////////////////////////////////////////////////////////////// + void SetName(const char* name); // changes the name of the variable + + int GivType(int mode = 0); // returns the base type (int) of the variable + // TODO check it + //////////////////////////////////////////////////////////////////////////////////////// + + CBotTypResult GivTypResult(int mode = 0); // returns the complete type of the variable + + + CBotToken* GivToken(); + void SetType(CBotTypResult& type); + + void SetInit(int bInit); // is the variable in the state IS_UNDEF, IS_DEF, IS_NAN + + int GivInit(); // gives the state of the variable + + void SetStatic(bool bStatic); + bool IsStatic(); + + void SetPrivate(int mPrivate); + bool IsPrivate(int mode = PR_PROTECT); + int GivPrivate(); + + virtual + void ConstructorSet(); + + void SetVal(CBotVar* var); // remprend une valeur + // TODO remprend value + virtual + CBotVar* GivItem(const char* name); // returns an element of a class according to its name (*) + virtual + CBotVar* GivItemRef(int nIdent); // idem à partir du n° ref + // TODO ditto from ref no. + virtual + CBotVar* GivItem(int row, bool bGrow = false); + + virtual + CBotVar* GivItemList(); // lists the elements + + CBotVar* GivStaticVar(); // makes the pointer to the variable if it is static + + bool IsElemOfClass(const char* name); + // said if the element belongs to the class "name" + // makes true if the object is a subclass + + CBotVar* GivNext(); // next variable in the list (parameters) + //////////////////////////////////////////////////////////////////////////////////////////// + + void AddNext(CBotVar* pVar); // added to a list + + virtual + void Copy(CBotVar* pSrc, bool bName = true); // makes a copy of the variable + + virtual void SetValInt(int val, const char* name = NULL); + // initialized with an integer value (#) + ///////////////////////////////////////////////////////////////////////////////// + + virtual void SetValFloat(float val); // initialized with a real value (#) + //////////////////////////////////////////////////////////////////////////////// + + virtual void SetValString(const char* p);// initialized with a string value (#) + //////////////////////////////////////////////////////////////////////////////// + + virtual int GivValInt(); // request the full value (#) + //////////////////////////////////////////////////////////////////////// + + virtual float GivValFloat(); // gets real value (#) + /////////////////////////////////////////////////////////////////////// + + virtual + CBotString GivValString(); // request the string value (#) + /////////////////////////////////////////////////////////////////////// + + virtual void SetClass(CBotClass* pClass); + virtual + CBotClass* GivClass(); + + virtual void SetPointer(CBotVar* p); + virtual + CBotVarClass* GivPointer(); +// virtual void SetIndirection(CBotVar* pVar); + + virtual void Add(CBotVar* left, CBotVar* right); // addition + virtual void Sub(CBotVar* left, CBotVar* right); // subtraction + virtual void Mul(CBotVar* left, CBotVar* right); // multiplication + virtual int Div(CBotVar* left, CBotVar* right); // division + virtual int Modulo(CBotVar* left, CBotVar* right); // remainder of division + virtual void Power(CBotVar* left, CBotVar* right); // power + + virtual bool Lo(CBotVar* left, CBotVar* right); + virtual bool Hi(CBotVar* left, CBotVar* right); + virtual bool Ls(CBotVar* left, CBotVar* right); + virtual bool Hs(CBotVar* left, CBotVar* right); + virtual bool Eq(CBotVar* left, CBotVar* right); + virtual bool Ne(CBotVar* left, CBotVar* right); + + virtual void And(CBotVar* left, CBotVar* right); + virtual void Or(CBotVar* left, CBotVar* right); + virtual void XOr(CBotVar* left, CBotVar* right); + virtual void ASR(CBotVar* left, CBotVar* right); + virtual void SR(CBotVar* left, CBotVar* right); + virtual void SL(CBotVar* left, CBotVar* right); + + virtual void Neg(); + virtual void Not(); + virtual void Inc(); + virtual void Dec(); + + + virtual bool Save0State(FILE* pf); + virtual bool Save1State(FILE* pf); + static bool RestoreState(FILE* pf, CBotVar* &pVar); + + void debug(); + +// virtual +// CBotVar* GivMyThis(); + + virtual + void Maj(void* pUser = NULL, bool bContinue = true); + + void SetUniqNum(long n); + long GivUniqNum(); + static long NextUniqNum(); +}; + +/* NOTE (#) + methods SetValInt() SetValFloat() et SetValString() + can be called with objects which are respectively integer, real or string + Always be sure of the type of the variable before calling these methods + + if ( pVar->GivType() == CBotInt() ) pVar->SetValFloat( 3.3 ); // plante !! + + methods GivValInt(), GivValFloat() et GivValString() + use value conversions, + GivValString() works on numbers (makes the corresponding string) + but do not make GivValInt () with a string variable! +*/ + + + +//////////////////////////////////////////////////////////////////////// +// management of classes +//////////////////////////////////////////////////////////////////////// + +// class to define new classes in the language CBOT +// for example to define the class CPoint (x, y) + +class CBotClass +{ +private: + static + CBotClass* m_ExClass; // list of classes existing at a given time + CBotClass* m_ExNext; // for this general list + CBotClass* m_ExPrev; // for this general list + +private: + CBotClass* m_pParent; // parent class + CBotString m_name; // name of this class + int m_nbVar; // number of variables in the chain + CBotVar* m_pVar; // content of the class + bool m_bIntrinsic; // intrinsic class + CBotClass* m_next; // the string class + CBotCallMethode* m_pCalls; // list of methods defined in external + CBotFunction* m_pMethod; // compiled list of methods + void (*m_rMaj) ( CBotVar* pThis, void* pUser ); + friend class CBotVarClass; + int m_cptLock; // for Lock / UnLock + int m_cptOne; // Lock for reentrancy + CBotProgram* m_ProgInLock[5];// processes waiting for sync + +public: + bool m_IsDef; // mark if is set or not + + CBotClass( const char* name, + CBotClass* pParent, bool bIntrinsic = false ); // constructor + // Once a class is created, it is known + // around CBoT + // intrinsic mode gives a class that is not managed by pointers + + ~CBotClass( ); // destructor + + bool AddFunction(const char* name, + bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception), + CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar)); + // this call allows to add as external (**) + // new method used by the objects of this class + + bool AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) ); + // defines routine to be called to update the elements of the class + + bool AddItem(CBotString name, CBotTypResult type, int mPrivate = PR_PUBLIC); + // adds an element to the class +// bool AddItem(CBotString name, CBotClass* pClass); + // the same for elements belonging to pClass + bool AddItem(CBotVar* pVar); + // adds an item by passing the pointer to an instance of a variable + // the object is taken as is, so do not destroyed + + + + // adds an element by giving an element of type CBotVar + void AddNext(CBotClass* pClass); + + CBotString GivName(); // gives the name of the class + CBotClass* GivParent(); // gives the parent class (or NULL) + + // true if a class is derived (Extends) of another + // return true also if the classes are identical + bool IsChildOf(CBotClass* pClass); + + static + CBotClass* Find(CBotToken* &pToken); // trouve une classe d'après son nom + // return a class by it's its name + static + CBotClass* Find(const char* name); + + CBotVar* GivVar(); // return the list of variables + CBotVar* GivItem(const char* name); // one of the variables according to its name + CBotVar* GivItemRef(int nIdent); + + CBotTypResult CompileMethode(const char* name, CBotVar* pThis, CBotVar** ppParams, + CBotCStack* pStack, long& nIdent); + + bool ExecuteMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotVar* &pResult, CBotStack* &pStack, CBotToken* pToken); + void RestoreMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotStack* &pStack); + + // compiles a class declared by the user + static + CBotClass* Compile(CBotToken* &p, CBotCStack* pStack); + static + CBotClass* Compile1(CBotToken* &p, CBotCStack* pStack); + + bool CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond); + + bool IsIntrinsic(); + void Purge(); + static + void Free(); + + static + bool SaveStaticState(FILE* pf); + + static + bool RestoreStaticState(FILE* pf); + + bool Lock(CBotProgram* p); + void Unlock(); + static + void FreeLock(CBotProgram* p); + + bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam); + +}; + +#define MAXDEFNUM 1000 // limited number of DefineNum + +///////////////////////////////////////////////////////////////////////////////////// +// Token management (tokens) + +#define TokenTypKeyWord 1 // a keyword of the language (see TokenKeyWord) +#define TokenTypNum 2 // number +#define TokenTypString 3 // string +#define TokenTypVar 4 // a variable name +#define TokenTypDef 5 // value according DefineNum + +#define TokenKeyWord 2000 // keywords of the language +#define TokenKeyDeclare 2100 // keywords of declarations (int, float,..) +#define TokenKeyVal 2200 // keywords representing the value (true, false, null, nan) +#define TokenKeyOp 2300 // operators + +/** \class Responsible for token management */ +class CBotToken +{ +private: + static + CBotStringArray m_ListKeyWords; // list of keywords of language + static + int m_ListIdKeyWords[200]; // the corresponding codes + + static + CBotStringArray m_ListKeyDefine; // names defined by a DefineNum + static + long m_ListKeyNums[MAXDEFNUM]; // the ​​associated values + +private: + CBotToken* m_next; // following in the list + CBotToken* m_prev; + int m_type; // type of Token + long m_IdKeyWord; // number of the keyword if it is a + // or value of the "define" + + CBotString m_Text; // word found as token + CBotString m_Sep; // following separators + + int m_start; // position in the original text (program) + int m_end; // the same for the end of the token + + /** + * \brief Check whether given parameter is a keyword + */ + static + int GivKeyWords(const char* w); // is it a keyword? + static + bool GivKeyDefNum(const char* w, CBotToken* &token); + + /** + * \brief Loads the list of keywords + */ + static + void LoadKeyWords(); + +public: + /** + * \brief Constructors + */ + CBotToken(); + CBotToken(const CBotToken* pSrc); + CBotToken(const CBotString& mot, const CBotString& sep, int start=0, int end=0); + CBotToken(const char* mot, const char* sep = NULL); + + /** + * \brief Destructor + */ + ~CBotToken(); + /** + * \brief Returns the type of token + */ + int GivType(); + + /** + * \brief makes the string corresponding to this token + */ + CBotString& GivString(); + + /** + * \brief makes the following separator token + */ + CBotString& GivSep(); + + /** + * \brief position of the beginning in the text + */ + int GivStart(); + /** + * \brief end position in the text + */ + int GivEnd(); + + /** + * \brief gives the next token in the list + */ + CBotToken* GivNext(); + /** + * \brief gives the previous token in a list + */ + CBotToken* GivPrev(); + + /** + * \brief transforms the entire program + */ + static + CBotToken* CompileTokens(const char* p, int& error); + + /** + * \brief releases the list + */ + static + void Delete(CBotToken* pToken); // libère la liste + + + // fonctions non utiles en export + static + bool DefineNum(const char* name, long val); + void SetString(const char* name); + + void SetPos(int start, int end); + long GivIdKey(); + /** + * \brief adds a token (a copy) + */ + void AddNext(CBotToken* p); + + /** + * finds the next token + */ + static + CBotToken* NextToken(char* &program, int& error, bool first = false); + + const CBotToken& + operator=(const CBotToken& src); + + static + void Free(); +}; + + + +#if 0 +//////////////////////////////////////////////////////////////////////// +// Examples of use +// Definition classes and functions + + +// define the global class CPoint +// -------------------------------- + m_pClassPoint = new CBotClass("CPoint", NULL); + // adds the component ".x" + m_pClassPoint->AddItem("x", CBotTypResult(CBotTypFloat)); + // adds the component ".y" + m_pClassPoint->AddItem("y", CBotTypResult(CBotTypFloat)); + // the player can then use the instructions + // CPoint position; position.x = 12; position.y = -13.6 + +// define class CColobotObject +// -------------------------------- +// This class manages all the objects in the world of COLOBOT +// the "main" user program belongs to this class + m_pClassObject = new CBotClass("CColobotObject", m_pClassBase); + // adds the component ".position" + m_pClassObject->AddItem("position", m_pClassPoint); + // adds the component ".type" + m_pClassObject->AddItem("type", CBotTypResult(CBotTypShort)); + // adds a definition of constant + m_pClassObject->AddConst("ROBOT", CBotTypShort, 1); // ROBOT equivalent to the value 1 + // adds the FIND routine + m_pClassObject->AddFunction( rCompFind, rDoFind ); + // the player can now use the instructions + // CColobotObject chose; chose = FIND( ROBOT ) + + + +// define class CColobotRobot derived from CColobotObject +// --------------------------------------------------------- +// programs "main" associated with robots as a part of this class + m_pClassRobot = new CBotClass("CColobotRobot", m_pClassObject); + // add routine GOTO + m_pClassRobot->AddFunction( rCompGoto, rDoGoto ); + // the player can now use + // GOTO( FIND ( ROBOT ) ); + + +// creates an instance of the class Robot +// ------------------------------------ +// for example a new robot which has just been manufactured + CBotVar* m_pMonRobot = new CBotVar("MonRobot", m_pClassRobot); + +// compiles the program by hand for this robot +// ------------------------------------------ + CString LeProgramme( "void main() {GOTO(0, 0); return 0;}" ); + if ( !m_pMonRobot->Compile( LeProgramme ) ) {error handling ...}; + +// build a stack for interpreter +// -------------------------------------- + CBotStack* pStack = new CBotStack(NULL); + +// executes the main program +// ------------------------- + while( false = m_pMonRobot->Execute( "main", pStack )) + { + // program suspended + // could be pass a handle to another (safeguarding pstack for the robot one) + }; + // programme "main" finished ! + + + + +// routine that implements the GOTO (CPoint pos) +bool rDoGoto( CBotVar* pVar, CBotVar* pResult, int& exception ) +{ + if (pVar->GivType() != CBotTypeClass || + pVar->IsElemOfClas("CPoint") ) { exception = 6522; return false; ) + // the parameter is not the right class? + // in fact the control is done to the routine of compilation + + m_PosToGo.Copy( pVar ); // keeps the target position (object type CBotVar) + + // or so + CBotVar* temp; + temp = pVar->GivItem("x"); // is necessary for the object of type CPoint + ASSERT (temp != NULL && temp->GivType() == CBotTypFloat); + m_PosToGo.x = temp->GivValFloat(); + + temp = pVar->GivItem("y"); // is necessary for the object of type CPoint + ASSERT (temp != NULL && temp->GivType() == CBotTypFloat); + m_PosToGo.y = temp->GivValFloat(); + + return (m_CurentPos == m_PosToGo); // makes true if the position is reached + // returns false if one had wait yet +} + +#endif +#endif //_CBOTDLL_H_ + diff --git a/src/CBot/CBotFunction.cpp b/src/CBot/CBotFunction.cpp index 363b939..756c6cb 100644 --- a/src/CBot/CBotFunction.cpp +++ b/src/CBot/CBotFunction.cpp @@ -1,1644 +1,1647 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-// compilation des diverses fonctions déclarées par l'utilisateur
-//
-
-#include "CBot.h"
-
-// les divers constructeurs / destructeurs
-// pour libérer tout selon l'arbre établi
-CBotFunction::CBotFunction()
-{
- m_Param = NULL; // liste des paramètres vide
- m_Block = NULL; // le bloc d'instructions
- m_next = NULL; // les fonctions peuvent être chaînées
- m_bPublic = false; // fonction non publique
- m_bExtern = false; // fonction non externe
- m_nextpublic = NULL;
- m_prevpublic = NULL;
- m_pProg = NULL;
-// m_nThisIdent = 0;
- m_nFuncIdent = 0;
- m_bSynchro = false;
-}
-
-CBotFunction* CBotFunction::m_listPublic = NULL;
-
-CBotFunction::~CBotFunction()
-{
- delete m_Param; // liste des paramètres vide
- delete m_Block; // le bloc d'instructions
- delete m_next;
-
- // enlève de la liste publique s'il y a lieu
- if ( m_bPublic )
- {
- if ( m_nextpublic != NULL )
- {
- m_nextpublic->m_prevpublic = m_prevpublic;
- }
- if ( m_prevpublic != NULL)
- {
- m_prevpublic->m_nextpublic = m_nextpublic;
- }
- else
- {
- // si prev = next = null peut ne pas être dans la liste !
- if ( m_listPublic == this ) m_listPublic = m_nextpublic;
- }
- }
-}
-
-bool CBotFunction::IsPublic()
-{
- return m_bPublic;
-}
-
-bool CBotFunction::IsExtern()
-{
- return m_bExtern;
-}
-
-bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop)
-{
- start = m_extern.GivStart();
- stop = m_closeblk.GivEnd();
-
- if (modestart == GetPosExtern)
- {
- start = m_extern.GivStart();
- }
- if (modestop == GetPosExtern)
- {
- stop = m_extern.GivEnd();
- }
- if (modestart == GetPosNom)
- {
- start = m_token.GivStart();
- }
- if (modestop == GetPosNom)
- {
- stop = m_token.GivEnd();
- }
- if (modestart == GetPosParam)
- {
- start = m_openpar.GivStart();
- }
- if (modestop == GetPosParam)
- {
- stop = m_closepar.GivEnd();
- }
- if (modestart == GetPosBloc)
- {
- start = m_openblk.GivStart();
- }
- if (modestop == GetPosBloc)
- {
- stop = m_closeblk.GivEnd();
- }
-
- return true;
-}
-
-
-CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
-{
- while ( IsOfType( p, ID_OPBRK ) )
- {
- if ( !IsOfType( p, ID_CLBRK ) )
- {
- pile->SetError(TX_CLBRK, p->GivStart());
- return CBotTypResult( -1 );
- }
- type = CBotTypResult( CBotTypArrayPointer, type );
- }
- return type;
-}
-
-CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
-{
- CBotClass* pClass = NULL;
-
- switch (p->GivType())
- {
- case ID_INT:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
- case ID_FLOAT:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
- case ID_BOOLEAN:
- case ID_BOOL:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypBoolean ));
- case ID_STRING:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypString ));
- case ID_VOID:
- p = p->GivNext();
- return CBotTypResult( 0 );
-
- case TokenTypVar:
- pClass = CBotClass::Find(p);
- if ( pClass != NULL)
- {
- p = p->GivNext();
- return ArrayType(p, pile,
- pClass->IsIntrinsic() ?
- CBotTypResult( CBotTypIntrinsic, pClass ) :
- CBotTypResult( CBotTypPointer, pClass ) );
- }
- }
- return CBotTypResult( -1 );
-}
-
-// compile une nouvelle fonction
-// bLocal permet de mettre la déclaration des paramètres au même niveau
-// que le éléments appartenant à la classe pour les méthodes
-CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal)
-{
- CBotToken* pp;
- CBotFunction* func = finput;
- if ( func == NULL ) func = new CBotFunction();
-
- CBotCStack* pStk = pStack->TokenStack(p, bLocal);
-
-// func->m_nFuncIdent = CBotVar::NextUniqNum();
-
- while (true)
- {
- if ( IsOfType(p, ID_PUBLIC) )
- {
- func->m_bPublic = true;
- continue;
- }
- pp = p;
- if ( IsOfType(p, ID_EXTERN) )
- {
- func->m_extern = pp; // pour la position du mot "extern"
- func->m_bExtern = true;
-// func->m_bPublic = true; // donc aussi publique!
- continue;
- }
- break;
- }
-
- func->m_retToken = *p;
-// CBotClass* pClass;
- func->m_retTyp = TypeParam(p, pStk); // type du résultat
-
- if (func->m_retTyp.GivType() >= 0)
- {
- CBotToken* pp = p;
- func->m_token = *p;
-
- if ( IsOfType(p, ID_NOT) )
- {
- CBotToken d("~" + p->GivString());
- func->m_token = d;
- }
-
- // un nom de fonction est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe
- {
- func->m_MasterClass = pp->GivString();
- CBotClass* pClass = CBotClass::Find(pp);
- if ( pClass == NULL ) goto bad;
-
-// pp = p;
- func->m_token = *p;
- if (!IsOfType(p, TokenTypVar)) goto bad;
-
- }
- func->m_openpar = p;
- func->m_Param = CBotDefParam::Compile( p, pStk );
- func->m_closepar = p->GivPrev();
- if (pStk->IsOk())
- {
- pStk->SetRetType(func->m_retTyp); // pour savoir de quel type les return
-
- if (!func->m_MasterClass.IsEmpty())
- {
- // rend "this" connu
- CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass ));
- pThis->SetInit(2);
-// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() va pas
- pThis->SetUniqNum(-2);
- pStk->AddVar(pThis);
-
- // initialise les variables selon This
- // n'enregistre que le pointeur à la première,
- // le reste est chainé
- CBotVar* pv = pThis->GivItemList();
-// int num = 1;
- while (pv != NULL)
- {
- CBotVar* pcopy = CBotVar::Create(pv);
-// pcopy->SetInit(2);
- pcopy->Copy(pv);
- pcopy->SetPrivate(pv->GivPrivate());
-// pcopy->SetUniqNum(pv->GivUniqNum()); //num++);
- pStk->AddVar(pcopy);
- pv = pv->GivNext();
- }
- }
-
- // et compile le bloc d'instruction qui suit
- func->m_openblk = p;
- func->m_Block = CBotBlock::Compile(p, pStk, false);
- func->m_closeblk = p->GivPrev();
- if ( pStk->IsOk() )
- {
- if ( func->m_bPublic ) // fonction publique, la rend connue pour tous
- {
- CBotFunction::AddPublic(func);
- }
- return pStack->ReturnFunc(func, pStk);
- }
- }
- }
-bad:
- pStk->SetError(TX_NOFONC, p);
- }
- pStk->SetError(TX_NOTYP, p);
- if ( finput == NULL ) delete func;
- return pStack->ReturnFunc(NULL, pStk);
-}
-
-// pré-compile une nouvelle fonction
-CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
-{
- CBotFunction* func = new CBotFunction();
- func->m_nFuncIdent = CBotVar::NextUniqNum();
-
- CBotCStack* pStk = pStack->TokenStack(p, true);
-
- while (true)
- {
- if ( IsOfType(p, ID_PUBLIC) )
- {
- // func->m_bPublic = true; // sera fait en passe 2
- continue;
- }
- if ( IsOfType(p, ID_EXTERN) )
- {
- func->m_bExtern = true;
- continue;
- }
- break;
- }
-
- func->m_retToken = *p;
- func->m_retTyp = TypeParam(p, pStack); // type du résultat
-
- if (func->m_retTyp.GivType() >= 0)
- {
- CBotToken* pp = p;
- func->m_token = *p;
- // un nom de fonction est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe
- {
- func->m_MasterClass = pp->GivString();
- CBotClass* pClass = CBotClass::Find(pp);
- if ( pClass == NULL )
- {
- pStk->SetError(TX_NOCLASS, pp);
- goto bad;
- }
-
- pp = p;
- func->m_token = *p;
- if (!IsOfType(p, TokenTypVar)) goto bad;
-
- }
- func->m_Param = CBotDefParam::Compile( p, pStk );
- if (pStk->IsOk())
- {
- // regarde si la fonction existe ailleurs
- if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) &&
- ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) )
- {
- if (IsOfType(p, ID_OPBLK))
- {
- int level = 1;
- // et saute le bloc d'instructions qui suit
- do
- {
- int type = p->GivType();
- p = p->GivNext();
- if (type == ID_OPBLK) level++;
- if (type == ID_CLBLK) level--;
- }
- while (level > 0 && p != NULL);
-
- return pStack->ReturnFunc(func, pStk);
- }
- pStk->SetError(TX_OPENBLK, p);
- }
- }
- pStk->SetError(TX_REDEF, pp);
- }
-bad:
- pStk->SetError(TX_NOFONC, p);
- }
- pStk->SetError(TX_NOTYP, p);
- delete func;
- return pStack->ReturnFunc(NULL, pStk);
-}
-
-#ifdef _DEBUG
-static int xx = 0;
-#endif
-
-bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
-{
- CBotStack* pile = pj->AddStack(this, 2); // un bout de pile local à cette fonction
-// if ( pile == EOX ) return true;
-
- pile->SetBotCall(m_pProg); // bases pour les routines
-
- if ( pile->GivState() == 0 )
- {
- if ( !m_Param->Execute(ppVars, pile) ) return false; // défini les paramètres
- pile->IncState();
- }
-
- if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() )
- {
- // rend "this" connu
- CBotVar* pThis ;
- if ( pInstance == NULL )
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass ));
- pThis->SetInit(2);
- }
- else
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass ));
- pThis->SetPointer(pInstance);
- pThis->SetInit(2);
- }
-
-// pThis->SetUniqNum(m_nThisIdent);
- pThis->SetUniqNum(-2);
- pile->AddVar(pThis);
-
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return false;
-
- if ( !m_Block->Execute(pile) )
- {
- if ( pile->GivError() < 0 )
- pile->SetError( 0 );
- else
- return false;
- }
-
- return pj->Return(pile);
-}
-
-
-void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
-{
- CBotStack* pile = pj->RestoreStack(this); // un bout de pile local à cette fonction
- if ( pile == NULL ) return;
- CBotStack* pile2 = pile;
-
- pile->SetBotCall(m_pProg); // bases pour les routines
-
- if ( pile->GivBlock() < 2 )
- {
- CBotStack* pile2 = pile->RestoreStack(NULL); // un bout de pile local à cette fonction
- if ( pile2 == NULL ) return;
- pile->SetState(pile->GivState() + pile2->GivState());
- pile2->Delete();
- }
-
- m_Param->RestoreState(pile2, true); // les paramètres
-
- if ( !m_MasterClass.IsEmpty() )
- {
- CBotVar* pThis = pile->FindVar("this");
- pThis->SetInit(2);
- pThis->SetUniqNum(-2);
- }
-
- m_Block->RestoreState(pile2, true);
-}
-
-void CBotFunction::AddNext(CBotFunction* p)
-{
- CBotFunction* pp = this;
- while (pp->m_next != NULL) pp = pp->m_next;
-
- pp->m_next = p;
-}
-
-
-CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent)
-{
- nIdent = 0;
- CBotTypResult type;
-
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
- return type;
-}
-
-
-// trouve une fonction selon son identificateur unique
-// si l'identificateur n'est pas trouvé, cherche selon le nom et les paramètres
-
-CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic)
-{
- TypeOrError.SetType(TX_UNDEFCALL); // pas de routine de ce nom
- CBotFunction* pt;
-
- if ( nIdent )
- {
- if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- TypeOrError = pt->m_retTyp;
- return pt;
- }
- }
-
- // recherche dans la liste des fonctions publiques
-
- for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- TypeOrError = pt->m_retTyp;
- return pt;
- }
- }
- }
-
- if ( name == NULL ) return NULL;
-
- int delta = 99999; // cherche la signature la plus faible
- CBotFunction* pFunc = NULL; // la meilleure fonction trouvée
-
- if ( this != NULL )
- {
- for ( pt = this ; pt != NULL ; pt = pt->m_next )
- {
- if ( pt->m_token.GivString() == name )
- {
- int i = 0;
- int alpha = 0; // signature des paramètres
- // les paramètres sont-ils compatibles ?
- CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus
- CBotVar* pw = ppVars[i++]; // liste des paramètres fournis
- while ( pv != NULL && pw != NULL)
- {
- if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
- {
- if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
- break;
- }
- int d = pv->GivType() - pw->GivType(2);
- alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !!
-
- pv = pv->GivNext();
- pw = ppVars[i++];
- }
- if ( pw != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
- continue; // trop de paramètres
- }
- if ( pv != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
- continue; // pas assez de paramètres
- }
-
- if (alpha == 0) // signature parfaite
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // une meilleur signature ?
- {
- pFunc = pt;
- delta = alpha;
- }
- }
- }
- }
-
- if ( bPublic )
- {
- for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
- {
- if ( pt->m_token.GivString() == name )
- {
- int i = 0;
- int alpha = 0; // signature des paramètres
- // les paramètres sont-ils compatibles ?
- CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus
- CBotVar* pw = ppVars[i++]; // liste des paramètres fournis
- while ( pv != NULL && pw != NULL)
- {
- if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
- {
- if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
- break;
- }
- int d = pv->GivType() - pw->GivType(2);
- alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !!
-
- pv = pv->GivNext();
- pw = ppVars[i++];
- }
- if ( pw != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
- continue; // trop de paramètres
- }
- if ( pv != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
- continue; // pas assez de paramètres
- }
-
- if (alpha == 0) // signature parfaite
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // une meilleur signature ?
- {
- pFunc = pt;
- delta = alpha;
- }
- }
- }
- }
-
- if ( pFunc != NULL )
- {
- nIdent = pFunc->m_nFuncIdent;
- TypeOrError = pFunc->m_retTyp;
- return pFunc;
- }
- return NULL;
-}
-
-
-// fait un appel à une fonction
-
-int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
-{
- CBotTypResult type;
- CBotFunction* pt = NULL;
-
- pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- CBotStack* pStk1 = pStack->AddStack(pt, 2); // pour mettre "this"
-// if ( pStk1 == EOX ) return true;
-
- pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- if ( pStk1->IfStep() ) return false;
-
- CBotStack* pStk3 = pStk1->AddStack(NULL, true); // paramètres
-
- // prépare les paramètres sur la pile
-
- if ( pStk1->GivState() == 0 )
- {
- if ( !pt->m_MasterClass.IsEmpty() )
- {
- CBotVar* pInstance = m_pProg->m_pInstance;
- // rend "this" connu
- CBotVar* pThis ;
- if ( pInstance == NULL )
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass ));
- pThis->SetInit(2);
- }
- else
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass ));
- pThis->SetPointer(pInstance);
- pThis->SetInit(2);
- }
-
- pThis->SetUniqNum(-2);
- pStk1->AddVar(pThis);
-
- }
-
- // initialise les variables selon paramètres
- pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu
-
- pStk1->IncState();
- }
-
- // finalement exécute la fonction trouvée
-
- if ( !pStk3->GivRetVar( // remet le résultat sur la pile
- pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu
- {
- if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
- {
-#ifdef _DEBUG
- if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return false;
-#endif
- pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure
- }
- return false; // interrompu !
- }
-
- return pStack->Return( pStk3 );
- }
- return -1;
-}
-
-void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack)
-{
- CBotTypResult type;
- CBotFunction* pt = NULL;
- CBotStack* pStk1;
- CBotStack* pStk3;
-
- // recherche la fonction pour remettre l'identificateur ok
-
- pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- pStk1 = pStack->RestoreStack(pt);
- if ( pStk1 == NULL ) return;
-
- pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- if ( pStk1->GivBlock() < 2 )
- {
- CBotStack* pStk2 = pStk1->RestoreStack(NULL); // plus utilisé
- if ( pStk2 == NULL ) return;
- pStk3 = pStk2->RestoreStack(NULL);
- if ( pStk3 == NULL ) return;
- }
- else
- {
- pStk3 = pStk1->RestoreStack(NULL);
- if ( pStk3 == NULL ) return;
- }
-
- // prépare les paramètres sur la pile
-
- {
- if ( !pt->m_MasterClass.IsEmpty() )
- {
- CBotVar* pInstance = m_pProg->m_pInstance;
- // rend "this" connu
- CBotVar* pThis = pStk1->FindVar("this");
- pThis->SetInit(2);
- pThis->SetUniqNum(-2);
- }
- }
-
- if ( pStk1->GivState() == 0 )
- {
- pt->m_Param->RestoreState(pStk3, true);
- return;
- }
-
- // initialise les variables selon paramètres
- pt->m_Param->RestoreState(pStk3, false);
- pt->m_Block->RestoreState(pStk3, true);
- }
-}
-
-
-
-// fait un appel d'une méthode
-// note : this est déjà sur la pile, le pointeur pThis est juste là pour simplifier
-
-int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
-{
- CBotTypResult type;
- CBotProgram* pProgCurrent = pStack->GivBotCall();
-
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false);
-
- if ( pt != NULL )
- {
-// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack);
-
- CBotStack* pStk = pStack->AddStack(pt, 2);
-// if ( pStk == EOX ) return true;
-
- pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module
- CBotStack* pStk3 = pStk->AddStack(NULL, true); // pour mettre les paramètres passés
-
- // prépare les paramètres sur la pile
-
- if ( pStk->GivState() == 0 )
- {
- // met la variable "this" sur la pile
- CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
- pthis->Copy(pThis, false);
- pthis->SetUniqNum(-2); // valeur spéciale
- pStk->AddVar(pthis);
-
- CBotClass* pClass = pThis->GivClass()->GivParent();
- if ( pClass )
- {
- // met la variable "super" sur la pile
- CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer);
- psuper->Copy(pThis, false); // en fait identique à "this"
- psuper->SetUniqNum(-3); // valeur spéciale
- pStk->AddVar(psuper);
- }
- // initialise les variables selon paramètres
- pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu
- pStk->IncState();
- }
-
- if ( pStk->GivState() == 1 )
- {
- if ( pt->m_bSynchro )
- {
- CBotProgram* pProgBase = pStk->GivBotCall(true);
- if ( !pClass->Lock(pProgBase) ) return false; // attend de pouvoir
- }
- pStk->IncState();
- }
- // finalement appelle la fonction trouvée
-
- if ( !pStk3->GivRetVar( // remet le résultat sur la pile
- pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu
- {
- if ( !pStk3->IsOk() )
- {
- if ( pt->m_bSynchro )
- {
- pClass->Unlock(); // libère la fonction
- }
-
- if ( pt->m_pProg != pProgCurrent )
- {
- pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure
- }
- }
- return false; // interrompu !
- }
-
- if ( pt->m_bSynchro )
- {
- pClass->Unlock(); // libère la fonction
- }
-
- return pStack->Return( pStk3 );
- }
- return -1;
-}
-
-void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
-{
- CBotTypResult type;
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- CBotStack* pStk = pStack->RestoreStack(pt);
- if ( pStk == NULL ) return;
- pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- CBotVar* pthis = pStk->FindVar("this");
- pthis->SetUniqNum(-2);
-
- CBotStack* pStk3 = pStk->RestoreStack(NULL); // pour mettre les paramètres passés
- if ( pStk3 == NULL ) return;
-
- pt->m_Param->RestoreState(pStk3, true); // les paramètres
-
- if ( pStk->GivState() > 1 && // vérouillage est effectif ?
- pt->m_bSynchro )
- {
- CBotProgram* pProgBase = pStk->GivBotCall(true);
- pClass->Lock(pProgBase); // vérouille la classe
- }
-
- // finalement appelle la fonction trouvée
-
- pt->m_Block->RestoreState(pStk3, true); // interrompu !
- }
-}
-
-// regarde si la "signature" des paramètres est identique
-bool CBotFunction::CheckParam(CBotDefParam* pParam)
-{
- CBotDefParam* pp = m_Param;
- while ( pp != NULL && pParam != NULL )
- {
- CBotTypResult type1 = pp->GivType();
- CBotTypResult type2 = pParam->GivType();
- if ( !type1.Compare(type2) ) return false;
- pp = pp->GivNext();
- pParam = pParam->GivNext();
- }
- return ( pp == NULL && pParam == NULL );
-}
-
-CBotString CBotFunction::GivName()
-{
- return m_token.GivString();
-}
-
-CBotString CBotFunction::GivParams()
-{
- if ( m_Param == NULL ) return CBotString("()");
-
- CBotString params = "( ";
- CBotDefParam* p = m_Param; // liste des paramètres
-
- while (p != NULL)
- {
- params += p->GivParamString();
- p = p->GivNext();
- if ( p != NULL ) params += ", ";
- }
-
- params += " )";
- return params;
-}
-
-CBotFunction* CBotFunction::Next()
-{
- return m_next;
-}
-
-void CBotFunction::AddPublic(CBotFunction* func)
-{
- if ( m_listPublic != NULL )
- {
- func->m_nextpublic = m_listPublic;
- m_listPublic->m_prevpublic = func;
- }
- m_listPublic = func;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////
-// gestion des paramètres
-
-
-CBotDefParam::CBotDefParam()
-{
- m_next = NULL;
- m_nIdent = 0;
-}
-
-CBotDefParam::~CBotDefParam()
-{
- delete m_next;
-}
-
-
-// compile une liste de paramètres
-CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- // surtout pas de pStack->TokenStack ici
- // les variables déclarées doivent rester visibles par la suite
-
- pStack->SetStartError(p->GivStart());
-
- if (IsOfType(p, ID_OPENPAR))
- {
- CBotDefParam* list = NULL;
-
- while (!IsOfType(p, ID_CLOSEPAR))
- {
- CBotDefParam* param = new CBotDefParam();
- if (list == NULL) list = param;
- else list->AddNext(param); // ajoute à la liste
-
- CBotClass* pClass = NULL;//= CBotClass::Find(p);
- param->m_typename = p->GivString();
- CBotTypResult type = param->m_type = TypeParam(p, pStack);
-// if ( type == CBotTypPointer ) type = CBotTypClass; // il faut créer un nouvel objet
-
- if (param->m_type.GivType() > 0)
- {
- CBotToken* pp = p;
- param->m_token = *p;
- if (pStack->IsOk() && IsOfType(p, TokenTypVar) )
- {
-
- // variable déjà déclarée ?
- if (pStack->CheckVarLocal(pp))
- {
- pStack->SetError(TX_REDEFVAR, pp);
- break;
- }
-
- if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
- CBotVar* var = CBotVar::Create(pp->GivString(), type); // crée la variable
-// if ( pClass ) var->SetClass(pClass);
- var->SetInit(2); // la marque initialisée
- param->m_nIdent = CBotVar::NextUniqNum();
- var->SetUniqNum(param->m_nIdent);
- pStack->AddVar(var); // la place sur la pile
-
- if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR)
- continue;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStack->SetError(TX_NOTYP, p);
- delete list;
- return NULL;
- }
- return list;
- }
- pStack->SetError(TX_OPENPAR, p->GivStart());
- return NULL;
-}
-
-void CBotDefParam::AddNext(CBotDefParam* p)
-{
- CBotDefParam* pp = this;
- while (pp->m_next != NULL) pp = pp->m_next;
-
- pp->m_next = p;
-}
-
-
-bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
-{
- int i = 0;
- CBotDefParam* p = this;
-
- while ( p != NULL )
- {
- // crée une variable locale sur la pile
- CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type);
-
- // procède ainsi pour faire la transformation des types :
- if ( ppVars != NULL && ppVars[i] != NULL )
- {
- switch (p->m_type.GivType())
- {
- case CBotTypInt:
- newvar->SetValInt(ppVars[i]->GivValInt());
- break;
- case CBotTypFloat:
- newvar->SetValFloat(ppVars[i]->GivValFloat());
- break;
- case CBotTypString:
- newvar->SetValString(ppVars[i]->GivValString());
- break;
- case CBotTypBoolean:
- newvar->SetValInt(ppVars[i]->GivValInt());
- break;
- case CBotTypIntrinsic:
- ((CBotVarClass*)newvar)->Copy(ppVars[i], false);
- break;
- case CBotTypPointer:
- case CBotTypArrayPointer:
- {
- newvar->SetPointer(ppVars[i]->GivPointer());
- }
- break;
- default:
- ASM_TRAP();
- }
- }
- newvar->SetUniqNum(p->m_nIdent);
- pj->AddVar(newvar); // place la variable
- p = p->m_next;
- i++;
- }
-
- return true;
-}
-
-void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
-{
- int i = 0;
- CBotDefParam* p = this;
-
- while ( p != NULL )
- {
- // crée une variable locale sur la pile
- CBotVar* var = pj->FindVar(p->m_token.GivString());
- var->SetUniqNum(p->m_nIdent);
- p = p->m_next;
- }
-}
-
-int CBotDefParam::GivType()
-{
- return m_type.GivType();
-}
-
-CBotTypResult CBotDefParam::GivTypResult()
-{
- return m_type;
-}
-
-CBotDefParam* CBotDefParam::GivNext()
-{
- return m_next;
-}
-
-CBotString CBotDefParam::GivParamString()
-{
- CBotString param;
-
- param = m_typename;
- param += ' ';
-
- param += m_token.GivString();
- return param;
-}
-
-
-
-//////////////////////////////////////////////////////////////////////////
-// retour des paramètres
-
-CBotReturn::CBotReturn()
-{
- m_Instr = NULL;
- name = "CBotReturn"; // debug
-}
-
-CBotReturn::~CBotReturn()
-{
- delete m_Instr;
-}
-
-CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
-
- if (!IsOfType(p, ID_RETURN)) return NULL; // ne devrait jamais arriver
-
- CBotReturn* inst = new CBotReturn(); // crée l'objet
- inst->SetToken( pp );
-
- CBotTypResult type = pStack->GivRetType();
-
- if ( type.GivType() == 0 ) // retourne void ?
- {
- if ( IsOfType( p, ID_SEP ) ) return inst;
- pStack->SetError( TX_BADTYPE, pp );
- return NULL;
- }
-
- inst->m_Instr = CBotExpression::Compile(p, pStack);
- if ( pStack->IsOk() )
- {
- CBotTypResult retType = pStack->GivTypResult(2);
- if (TypeCompatible(retType, type, ID_ASS))
- {
- if ( IsOfType( p, ID_SEP ) )
- return inst;
-
- pStack->SetError(TX_ENDOF, p->GivStart());
- }
- pStack->SetError(TX_BADTYPE, p->GivStart());
- }
-
- delete inst;
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-bool CBotReturn::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return true;
-
- if ( pile->GivState() == 0 )
- {
- if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // évalue le résultat
- // le résultat est sur la pile
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return false;
-
- pile->SetBreak(3, CBotString());
- return pj->Return(pile);
-}
-
-void CBotReturn::RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState() == 0 )
- {
- if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // évalue le résultat
- return;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Les appels à ces fonctions
-
-CBotInstrCall::CBotInstrCall()
-{
- m_Parameters = NULL;
- m_nFuncIdent = 0;
- name = "CBotInstrCall";
-}
-
-CBotInstrCall::~CBotInstrCall()
-{
- delete m_Parameters;
-}
-
-CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotVar* ppVars[1000];
-
- int i = 0;
-
- CBotToken* pp = p;
- p = p->GivNext();
-
- pStack->SetStartError(p->GivStart());
- CBotCStack* pile = pStack;
-
- if ( IsOfType(p, ID_OPENPAR) )
- {
- int start, end;
- CBotInstrCall* inst = new CBotInstrCall();
- inst->SetToken(pp);
-
- // compile la liste des paramètres
- if (!IsOfType(p, ID_CLOSEPAR)) while (true)
- {
- start = p->GivStart();
- pile = pile->TokenStack(); // garde les résultats sur la pile
-
- CBotInstr* param = CBotExpression::Compile(p, pile);
- end = p->GivStart();
- if ( inst->m_Parameters == NULL ) inst->m_Parameters = param;
- else inst->m_Parameters->AddNext(param); // construit la liste
-
- if ( !pile->IsOk() )
- {
- delete inst;
- return pStack->Return(NULL, pile);
- }
-
- if ( param != NULL )
- {
- if ( pile->GivTypResult().Eq(99) )
- {
- delete pStack->TokenStack();
- pStack->SetError(TX_VOID, p->GivStart());
- delete inst;
- return NULL;
- }
- ppVars[i] = pile->GivVar();
- ppVars[i]->GivToken()->SetPos(start, end);
- i++;
-
- if (IsOfType(p, ID_COMMA)) continue; // saute la virgule
- if (IsOfType(p, ID_CLOSEPAR)) break;
- }
-
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- delete pStack->TokenStack();
- delete inst;
- return NULL;
- }
- ppVars[i] = NULL;
-
- // la routine est-elle connue ?
-// CBotClass* pClass = NULL;
- inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent);
- if ( inst->m_typRes.GivType() >= 20 )
- {
-// if (pVar2!=NULL) pp = pVar2->RetToken();
- pStack->SetError( inst->m_typRes.GivType(), pp );
- delete pStack->TokenStack();
- delete inst;
- return NULL;
- }
-
- delete pStack->TokenStack();
- if ( inst->m_typRes.GivType() > 0 )
- {
- CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
- pStack->SetVar(pRes); // pour connaître le type du résultat
- }
- else pStack->SetVar(NULL); // routine retourne void
-
- return inst;
- }
- p = pp;
- delete pStack->TokenStack();
- return NULL;
-}
-
-bool CBotInstrCall::Execute(CBotStack* &pj)
-{
- CBotVar* ppVars[1000];
- CBotStack* pile = pj->AddStack(this);
- if ( pile->StackOver() ) return pj->Return( pile );
-
- CBotStack* pile1 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
- if ( p != NULL) while ( true )
- {
- pile = pile->AddStack(); // de la place sur la pile pour les résultats
- if ( pile->GivState() == 0 )
- {
- if (!p->Execute(pile)) return false; // interrompu ici ?
- pile->SetState(1); // marque spéciale pour reconnaîre les paramètres
- }
- ppVars[i++] = pile->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotStack* pile2 = pile->AddStack();
- if ( pile2->IfStep() ) return false;
-
- if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return false; // interrompu
-
- return pj->Return(pile2); // libère toute la pile
-}
-
-void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- CBotStack* pile1 = pile;
-
- int i = 0;
- CBotVar* ppVars[1000];
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
- if ( p != NULL) while ( true )
- {
- pile = pile->RestoreStack(); // de la place sur la pile pour les résultats
- if ( pile == NULL ) return;
- if ( pile->GivState() == 0 )
- {
- p->RestoreState(pile, bMain); // interrompu ici !
- return;
- }
- ppVars[i++] = pile->GivVar(); // construit la liste des paramètres
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotStack* pile2 = pile->RestoreStack();
- if ( pile2 == NULL ) return;
-
- pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// déclaration des classes par l'utilisateur
-
-// pré-compile une nouvelle class
-// l'analyse est complète à l'execption du corps des routines
-
-CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
-{
- if ( !IsOfType(p, ID_PUBLIC) )
- {
- pStack->SetError(TX_NOPUBLIC, p);
- return NULL;
- }
-
- if ( !IsOfType(p, ID_CLASS) ) return NULL;
-
- CBotString name = p->GivString();
-
- CBotClass* pOld = CBotClass::Find(name);
- if ( pOld != NULL && pOld->m_IsDef )
- {
- pStack->SetError( TX_REDEFCLASS, p );
- return NULL;
- }
-
- // un nom pour la classe est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- CBotClass* pPapa = NULL;
- if ( IsOfType( p, ID_EXTENDS ) )
- {
- CBotString name = p->GivString();
- pPapa = CBotClass::Find(name);
-
- if (!IsOfType(p, TokenTypVar) || pPapa == NULL )
- {
- pStack->SetError( TX_NOCLASS, p );
- return NULL;
- }
- }
- CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld;
- classe->Purge(); // vide les anciennes définitions
- classe->m_IsDef = false; // définition en cours
-
- if ( !IsOfType( p, ID_OPBLK) )
- {
- pStack->SetError(TX_OPENBLK, p);
- return NULL;
- }
-
- while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
- {
- classe->CompileDefItem(p, pStack, false);
- }
-
- if (pStack->IsOk()) return classe;
- }
- pStack->SetError(TX_ENDOF, p);
- return NULL;
-}
-
-bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
-{
- bool bStatic = false;
- int mProtect = PR_PUBLIC;
- bool bSynchro = false;
-
- while (IsOfType(p, ID_SEP)) ;
-
- CBotTypResult type( -1 );
-
- if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true;
- CBotToken* pBase = p;
-
- if ( IsOfType(p, ID_STATIC) ) bStatic = true;
- if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC;
- if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE;
- if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT;
- if ( IsOfType(p, ID_STATIC) ) bStatic = true;
-
-// CBotClass* pClass = NULL;
- type = TypeParam(p, pStack); // type du résultat
-
- if ( type.Eq(-1) )
- {
- pStack->SetError(TX_NOTYP, p);
- return false;
- }
-
- while (pStack->IsOk())
- {
- CBotToken* pp = p;
- IsOfType(p, ID_NOT); // saute le ~ éventuel (destructeur)
-
- if (IsOfType(p, TokenTypVar))
- {
- CBotInstr* limites = NULL;
- while ( IsOfType( p, ID_OPBRK ) ) // un tableau ?
- {
- CBotInstr* i = NULL;
-
- if ( p->GivType() != ID_CLBRK )
- i = CBotExpression::Compile( p, pStack ); // expression pour la valeur
- else
- i = new CBotEmpty(); // spécial si pas de formule
-
- type = CBotTypResult(CBotTypArrayPointer, type);
-
- if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) )
- {
- pStack->SetError(TX_CLBRK, p->GivStart());
- return false;
- }
-
-/* CBotVar* pv = pStack->GivVar();
- if ( pv->GivType()>= CBotTypBoolean )
- {
- pStack->SetError(TX_BADTYPE, p->GivStart());
- return false;
- }*/
-
- if (limites == NULL) limites = i;
- else limites->AddNext3(i);
- }
-
- if ( p->GivType() == ID_OPENPAR )
- {
- if ( !bSecond )
- {
- p = pBase;
- CBotFunction* f =
- CBotFunction::Compile1(p, pStack, this);
-
- if ( f == NULL ) return false;
-
- if (m_pMethod == NULL) m_pMethod = f;
- else m_pMethod->AddNext(f);
- }
- else
- {
- // retrouve la méthode précompilée en passe 1
- CBotFunction* pf = m_pMethod;
- CBotFunction* prev = NULL;
- while ( pf != NULL )
- {
- if (pf->GivName() == pp->GivString()) break;
- prev = pf;
- pf = pf->Next();
- }
-
- bool bConstructor = (pp->GivString() == GivName());
- CBotCStack* pile = pStack->TokenStack(NULL, true);
-
- // rend "this" connu
- CBotToken TokenThis(CBotString("this"), CBotString());
- CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) );
- pThis->SetUniqNum(-2);
- pile->AddVar(pThis);
-
- if ( m_pParent )
- {
- // rend "super" connu
- CBotToken TokenSuper(CBotString("super"), CBotString());
- CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) );
- pThis->SetUniqNum(-3);
- pile->AddVar(pThis);
- }
-
-// int num = 1;
- CBotClass* my = this;
- while (my != NULL)
- {
- // place une copie des varibles de la classe (this) sur la pile
- CBotVar* pv = my->m_pVar;
- while (pv != NULL)
- {
- CBotVar* pcopy = CBotVar::Create(pv);
- pcopy->SetInit(!bConstructor || pv->IsStatic());
- pcopy->SetUniqNum(pv->GivUniqNum());
- pile->AddVar(pcopy);
- pv = pv->GivNext();
- }
- my = my->m_pParent;
- }
-
- // compile une méthode
- p = pBase;
- CBotFunction* f =
- CBotFunction::Compile(p, pile, NULL/*, false*/);
-
- if ( f != NULL )
- {
- f->m_pProg = pStack->GivBotCall();
- f->m_bSynchro = bSynchro;
- // remplace l'élément dans la chaîne
- f->m_next = pf->m_next;
- pf->m_next = NULL;
- delete pf;
- if (prev == NULL) m_pMethod = f;
- else prev->m_next = f;
- }
- pStack->Return(NULL, pile);
- }
-
- return pStack->IsOk();
- }
-
- // définition d'un élément
- if (type.Eq(0))
- {
- pStack->SetError(TX_ENDOF, p);
- return false;
- }
-
- CBotInstr* i = NULL;
- if ( IsOfType(p, ID_ASS ) )
- {
- if ( type.Eq(CBotTypArrayPointer) )
- {
- i = CBotListArray::Compile(p, pStack, type.GivTypElem());
- }
- else
- {
- // il y a une assignation à calculer
- i = CBotTwoOpExpr::Compile(p, pStack);
- }
- if ( !pStack->IsOk() ) return false;
- }
-
-
- if ( !bSecond )
- {
- CBotVar* pv = CBotVar::Create(pp->GivString(), type);
- pv -> SetStatic( bStatic );
- pv -> SetPrivate( mProtect );
-
- AddItem( pv );
-
- pv->m_InitExpr = i;
- pv->m_LimExpr = limites;
-
-
- if ( pv->IsStatic() && pv->m_InitExpr != NULL )
- {
- CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante
- while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // évalue l'expression sans timer
- pv->SetVal( pile->GivVar() ) ;
- pile->Delete();
- }
- }
- else
- delete i;
-
- if ( IsOfType(p, ID_COMMA) ) continue;
- if ( IsOfType(p, ID_SEP) ) break;
- }
- pStack->SetError(TX_ENDOF, p);
- }
- return pStack->IsOk();
-}
-
-
-CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- if ( !IsOfType(p, ID_PUBLIC) ) return NULL;
- if ( !IsOfType(p, ID_CLASS) ) return NULL;
-
- CBotString name = p->GivString();
-
- // un nom pour la classe est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- // la classe à été créée par Compile1
- CBotClass* pOld = CBotClass::Find(name);
-
- if ( IsOfType( p, ID_EXTENDS ) )
- {
- IsOfType(p, TokenTypVar); // forcément
- }
- IsOfType( p, ID_OPBLK); // forcément
-
- while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
- {
- pOld->CompileDefItem(p, pStack, true);
- }
-
- pOld->m_IsDef = true; // définition terminée
- if (pStack->IsOk()) return pOld;
- }
- pStack->SetError(TX_ENDOF, p);
- return NULL;
-}
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +/////////////////////////////////////////////////////////////////////// +// compilation of various functions declared by the user +// + +#include "CBot.h" + +// various constructors / destructors +// \TODO translation:to liberate all according to esteblished tree +// pour libérer tout selon l'arbre établi +CBotFunction::CBotFunction() +{ + m_Param = NULL; // empty parameter list + m_Block = NULL; // the instruction block + m_next = NULL; // functions can be chained + m_bPublic = false; // function not public + m_bExtern = false; // function not extern + m_nextpublic = NULL; + m_prevpublic = NULL; + m_pProg = NULL; +// m_nThisIdent = 0; + m_nFuncIdent = 0; + m_bSynchro = false; +} + +CBotFunction* CBotFunction::m_listPublic = NULL; + +CBotFunction::~CBotFunction() +{ + delete m_Param; // empty parameter list + delete m_Block; // the instruction block + delete m_next; + + // remove public list if there is + if ( m_bPublic ) + { + if ( m_nextpublic != NULL ) + { + m_nextpublic->m_prevpublic = m_prevpublic; + } + if ( m_prevpublic != NULL) + { + m_prevpublic->m_nextpublic = m_nextpublic; + } + else + { + // if prev = next = null may not be in the list! + if ( m_listPublic == this ) m_listPublic = m_nextpublic; + } + } +} + +bool CBotFunction::IsPublic() +{ + return m_bPublic; +} + +bool CBotFunction::IsExtern() +{ + return m_bExtern; +} + +bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop) +{ + start = m_extern.GivStart(); + stop = m_closeblk.GivEnd(); + + if (modestart == GetPosExtern) + { + start = m_extern.GivStart(); + } + if (modestop == GetPosExtern) + { + stop = m_extern.GivEnd(); + } + if (modestart == GetPosNom) + { + start = m_token.GivStart(); + } + if (modestop == GetPosNom) + { + stop = m_token.GivEnd(); + } + if (modestart == GetPosParam) + { + start = m_openpar.GivStart(); + } + if (modestop == GetPosParam) + { + stop = m_closepar.GivEnd(); + } + if (modestart == GetPosBloc) + { + start = m_openblk.GivStart(); + } + if (modestop == GetPosBloc) + { + stop = m_closeblk.GivEnd(); + } + + return true; +} + + +CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type) +{ + while ( IsOfType( p, ID_OPBRK ) ) + { + if ( !IsOfType( p, ID_CLBRK ) ) + { + pile->SetError(TX_CLBRK, p->GivStart()); + return CBotTypResult( -1 ); + } + type = CBotTypResult( CBotTypArrayPointer, type ); + } + return type; +} + +CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile) +{ + CBotClass* pClass = NULL; + + switch (p->GivType()) + { + case ID_INT: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypInt )); + case ID_FLOAT: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypFloat )); + case ID_BOOLEAN: + case ID_BOOL: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypBoolean )); + case ID_STRING: + p = p->GivNext(); + return ArrayType(p, pile, CBotTypResult( CBotTypString )); + case ID_VOID: + p = p->GivNext(); + return CBotTypResult( 0 ); + + case TokenTypVar: + pClass = CBotClass::Find(p); + if ( pClass != NULL) + { + p = p->GivNext(); + return ArrayType(p, pile, + pClass->IsIntrinsic() ? + CBotTypResult( CBotTypIntrinsic, pClass ) : + CBotTypResult( CBotTypPointer, pClass ) ); + } + } + return CBotTypResult( -1 ); +} + +// compiles a new function +// bLocal allows of the declaration of parameters on the same level +// as the elements belonging to the class for methods +CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal) +{ + CBotToken* pp; + CBotFunction* func = finput; + if ( func == NULL ) func = new CBotFunction(); + + CBotCStack* pStk = pStack->TokenStack(p, bLocal); + +// func->m_nFuncIdent = CBotVar::NextUniqNum(); + + while (true) + { + if ( IsOfType(p, ID_PUBLIC) ) + { + func->m_bPublic = true; + continue; + } + pp = p; + if ( IsOfType(p, ID_EXTERN) ) + { + func->m_extern = pp; // for the position of the word "extern" + func->m_bExtern = true; +// func->m_bPublic = true; // therefore also public! + continue; + } + break; + } + + func->m_retToken = *p; +// CBotClass* pClass; + func->m_retTyp = TypeParam(p, pStk); // type of the result + + if (func->m_retTyp.GivType() >= 0) + { + CBotToken* pp = p; + func->m_token = *p; + + if ( IsOfType(p, ID_NOT) ) + { + CBotToken d("~" + p->GivString()); + func->m_token = d; + } + + // un nom de fonction est-il là ? + if (IsOfType(p, TokenTypVar)) + { + if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class + { + func->m_MasterClass = pp->GivString(); + CBotClass* pClass = CBotClass::Find(pp); + if ( pClass == NULL ) goto bad; + +// pp = p; + func->m_token = *p; + if (!IsOfType(p, TokenTypVar)) goto bad; + + } + func->m_openpar = p; + func->m_Param = CBotDefParam::Compile( p, pStk ); + func->m_closepar = p->GivPrev(); + if (pStk->IsOk()) + { + pStk->SetRetType(func->m_retTyp); // for knowledge what type returns + + if (!func->m_MasterClass.IsEmpty()) + { + // return "this" known + CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass )); + pThis->SetInit(2); +// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() will not + pThis->SetUniqNum(-2); + pStk->AddVar(pThis); + + // initialize variables acording to This + // only saves the pointer to the first, + // the rest is chained + CBotVar* pv = pThis->GivItemList(); +// int num = 1; + while (pv != NULL) + { + CBotVar* pcopy = CBotVar::Create(pv); +// pcopy->SetInit(2); + pcopy->Copy(pv); + pcopy->SetPrivate(pv->GivPrivate()); +// pcopy->SetUniqNum(pv->GivUniqNum()); //num++); + pStk->AddVar(pcopy); + pv = pv->GivNext(); + } + } + + // and compiles the following instruction block + func->m_openblk = p; + func->m_Block = CBotBlock::Compile(p, pStk, false); + func->m_closeblk = p->GivPrev(); + if ( pStk->IsOk() ) + { + if ( func->m_bPublic ) // public function, return known for all + { + CBotFunction::AddPublic(func); + } + return pStack->ReturnFunc(func, pStk); + } + } + } +bad: + pStk->SetError(TX_NOFONC, p); + } + pStk->SetError(TX_NOTYP, p); + if ( finput == NULL ) delete func; + return pStack->ReturnFunc(NULL, pStk); +} + +// pre-compile a new function +CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) +{ + CBotFunction* func = new CBotFunction(); + func->m_nFuncIdent = CBotVar::NextUniqNum(); + + CBotCStack* pStk = pStack->TokenStack(p, true); + + while (true) + { + if ( IsOfType(p, ID_PUBLIC) ) + { + // func->m_bPublic = true; // will be done in two passes + continue; + } + if ( IsOfType(p, ID_EXTERN) ) + { + func->m_bExtern = true; + continue; + } + break; + } + + func->m_retToken = *p; + func->m_retTyp = TypeParam(p, pStack); // type of the result + + if (func->m_retTyp.GivType() >= 0) + { + CBotToken* pp = p; + func->m_token = *p; + // un nom de fonction est-il là ? + if (IsOfType(p, TokenTypVar)) + { + if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class + { + func->m_MasterClass = pp->GivString(); + CBotClass* pClass = CBotClass::Find(pp); + if ( pClass == NULL ) + { + pStk->SetError(TX_NOCLASS, pp); + goto bad; + } + + pp = p; + func->m_token = *p; + if (!IsOfType(p, TokenTypVar)) goto bad; + + } + func->m_Param = CBotDefParam::Compile( p, pStk ); + if (pStk->IsOk()) + { + // looks if the function exists elsewhere + if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) && + ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) ) + { + if (IsOfType(p, ID_OPBLK)) + { + int level = 1; + // and skips the following instruction block + do + { + int type = p->GivType(); + p = p->GivNext(); + if (type == ID_OPBLK) level++; + if (type == ID_CLBLK) level--; + } + while (level > 0 && p != NULL); + + return pStack->ReturnFunc(func, pStk); + } + pStk->SetError(TX_OPENBLK, p); + } + } + pStk->SetError(TX_REDEF, pp); + } +bad: + pStk->SetError(TX_NOFONC, p); + } + pStk->SetError(TX_NOTYP, p); + delete func; + return pStack->ReturnFunc(NULL, pStk); +} + +#ifdef _DEBUG +static int xx = 0; +#endif + +bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) +{ + CBotStack* pile = pj->AddStack(this, 2); // one end of stack local to this function +// if ( pile == EOX ) return true; + + pile->SetBotCall(m_pProg); // bases for routines + + if ( pile->GivState() == 0 ) + { + if ( !m_Param->Execute(ppVars, pile) ) return false; // define parameters + pile->IncState(); + } + + if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() ) + { + // makes "this" known + CBotVar* pThis ; + if ( pInstance == NULL ) + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass )); + pThis->SetInit(2); + } + else + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass )); + pThis->SetPointer(pInstance); + pThis->SetInit(2); + } + +// pThis->SetUniqNum(m_nThisIdent); + pThis->SetUniqNum(-2); + pile->AddVar(pThis); + + pile->IncState(); + } + + if ( pile->IfStep() ) return false; + + if ( !m_Block->Execute(pile) ) + { + if ( pile->GivError() < 0 ) + pile->SetError( 0 ); + else + return false; + } + + return pj->Return(pile); +} + + +void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) +{ + CBotStack* pile = pj->RestoreStack(this); // one end of stack local to this function + if ( pile == NULL ) return; + CBotStack* pile2 = pile; + + pile->SetBotCall(m_pProg); // bases for routines + + if ( pile->GivBlock() < 2 ) + { + CBotStack* pile2 = pile->RestoreStack(NULL); // one end of stack local to this function + if ( pile2 == NULL ) return; + pile->SetState(pile->GivState() + pile2->GivState()); + pile2->Delete(); + } + + m_Param->RestoreState(pile2, true); // parameters + + if ( !m_MasterClass.IsEmpty() ) + { + CBotVar* pThis = pile->FindVar("this"); + pThis->SetInit(2); + pThis->SetUniqNum(-2); + } + + m_Block->RestoreState(pile2, true); +} + +void CBotFunction::AddNext(CBotFunction* p) +{ + CBotFunction* pp = this; + while (pp->m_next != NULL) pp = pp->m_next; + + pp->m_next = p; +} + + +CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent) +{ + nIdent = 0; + CBotTypResult type; + + CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); + return type; +} + + +// is a function according to its unique identifier +// if the identifier is not found, looking by name and parameters + +CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic) +{ + TypeOrError.SetType(TX_UNDEFCALL); // no routine of the name + CBotFunction* pt; + + if ( nIdent ) + { + if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next ) + { + if ( pt->m_nFuncIdent == nIdent ) + { + TypeOrError = pt->m_retTyp; + return pt; + } + } + + // search the list of public functions + + for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) + { + if ( pt->m_nFuncIdent == nIdent ) + { + TypeOrError = pt->m_retTyp; + return pt; + } + } + } + + if ( name == NULL ) return NULL; + + int delta = 99999; // seeks the lowest signature + CBotFunction* pFunc = NULL; // the best function found + + if ( this != NULL ) + { + for ( pt = this ; pt != NULL ; pt = pt->m_next ) + { + if ( pt->m_token.GivString() == name ) + { + int i = 0; + int alpha = 0; // signature of parameters + // parameters are compatible? + CBotDefParam* pv = pt->m_Param; // expected list of parameters + CBotVar* pw = ppVars[i++]; // provided list parameter + while ( pv != NULL && pw != NULL) + { + if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult())) + { + if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; + break; + } + int d = pv->GivType() - pw->GivType(2); + alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! + + pv = pv->GivNext(); + pw = ppVars[i++]; + } + if ( pw != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); + continue; // too many parameters + } + if ( pv != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); + continue; // not enough parameters + } + + if (alpha == 0) // perfect signature + { + nIdent = pt->m_nFuncIdent; + TypeOrError = pt->m_retTyp; + return pt; + } + + if ( alpha < delta ) // a better signature? + { + pFunc = pt; + delta = alpha; + } + } + } + } + + if ( bPublic ) + { + for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) + { + if ( pt->m_token.GivString() == name ) + { + int i = 0; + int alpha = 0; // signature of parameters + // parameters sont-ils compatibles ? + CBotDefParam* pv = pt->m_Param; // list of expected parameters + CBotVar* pw = ppVars[i++]; // list of provided parameters + while ( pv != NULL && pw != NULL) + { + if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult())) + { + if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; + break; + } + int d = pv->GivType() - pw->GivType(2); + alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! + + pv = pv->GivNext(); + pw = ppVars[i++]; + } + if ( pw != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); + continue; // to many parameters + } + if ( pv != NULL ) + { + if ( pFunc != NULL ) continue; + if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); + if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); + continue; // not enough parameters + } + + if (alpha == 0) // perfect signature + { + nIdent = pt->m_nFuncIdent; + TypeOrError = pt->m_retTyp; + return pt; + } + + if ( alpha < delta ) // a better signature? + { + pFunc = pt; + delta = alpha; + } + } + } + } + + if ( pFunc != NULL ) + { + nIdent = pFunc->m_nFuncIdent; + TypeOrError = pFunc->m_retTyp; + return pFunc; + } + return NULL; +} + + +// fait un appel à une fonction + +int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) +{ + CBotTypResult type; + CBotFunction* pt = NULL; + + pt = FindLocalOrPublic(nIdent, name, ppVars, type); + + if ( pt != NULL ) + { + CBotStack* pStk1 = pStack->AddStack(pt, 2); // to put "this" +// if ( pStk1 == EOX ) return true; + + pStk1->SetBotCall(pt->m_pProg); // it may have changed module + + if ( pStk1->IfStep() ) return false; + + CBotStack* pStk3 = pStk1->AddStack(NULL, true); // parameters + + // preparing parameters on the stack + + if ( pStk1->GivState() == 0 ) + { + if ( !pt->m_MasterClass.IsEmpty() ) + { + CBotVar* pInstance = m_pProg->m_pInstance; + // make "this" known + CBotVar* pThis ; + if ( pInstance == NULL ) + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass )); + pThis->SetInit(2); + } + else + { + pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass )); + pThis->SetPointer(pInstance); + pThis->SetInit(2); + } + + pThis->SetUniqNum(-2); + pStk1->AddVar(pThis); + + } + + // initializes the variables as parameters + pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted + + pStk1->IncState(); + } + + // finally execution of the found function + + if ( !pStk3->GivRetVar( // puts the result on the stack + pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted + { + if ( !pStk3->IsOk() && pt->m_pProg != m_pProg ) + { +#ifdef _DEBUG + if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return false; +#endif + pStk3->SetPosError(pToken); // indicates the error on the procedure call + } + return false; // interrupt ! + } + + return pStack->Return( pStk3 ); + } + return -1; +} + +void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack) +{ + CBotTypResult type; + CBotFunction* pt = NULL; + CBotStack* pStk1; + CBotStack* pStk3; + + // search function to return the ok identifier + + pt = FindLocalOrPublic(nIdent, name, ppVars, type); + + if ( pt != NULL ) + { + pStk1 = pStack->RestoreStack(pt); + if ( pStk1 == NULL ) return; + + pStk1->SetBotCall(pt->m_pProg); // it may have changed module + + if ( pStk1->GivBlock() < 2 ) + { + CBotStack* pStk2 = pStk1->RestoreStack(NULL); // used more + if ( pStk2 == NULL ) return; + pStk3 = pStk2->RestoreStack(NULL); + if ( pStk3 == NULL ) return; + } + else + { + pStk3 = pStk1->RestoreStack(NULL); + if ( pStk3 == NULL ) return; + } + + // preparing parameters on the stack + + { + if ( !pt->m_MasterClass.IsEmpty() ) + { + CBotVar* pInstance = m_pProg->m_pInstance; + // make "this" known + CBotVar* pThis = pStk1->FindVar("this"); + pThis->SetInit(2); + pThis->SetUniqNum(-2); + } + } + + if ( pStk1->GivState() == 0 ) + { + pt->m_Param->RestoreState(pStk3, true); + return; + } + + // initializes the variables as parameters + pt->m_Param->RestoreState(pStk3, false); + pt->m_Block->RestoreState(pStk3, true); + } +} + + + +// makes call of a method +// note: this is already on the stack, the pointer pThis is just to simplify + +int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass) +{ + CBotTypResult type; + CBotProgram* pProgCurrent = pStack->GivBotCall(); + + CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false); + + if ( pt != NULL ) + { +// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack); + + CBotStack* pStk = pStack->AddStack(pt, 2); +// if ( pStk == EOX ) return true; + + pStk->SetBotCall(pt->m_pProg); // it may have changed module + CBotStack* pStk3 = pStk->AddStack(NULL, true); // to set parameters passed + + // preparing parameters on the stack + + if ( pStk->GivState() == 0 ) + { + // sets the variable "this" on the stack + CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); + pthis->Copy(pThis, false); + pthis->SetUniqNum(-2); // special value + pStk->AddVar(pthis); + + CBotClass* pClass = pThis->GivClass()->GivParent(); + if ( pClass ) + { + // sets the variable "super" on the stack + CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); + psuper->Copy(pThis, false); // in fact identical to "this" + psuper->SetUniqNum(-3); // special value + pStk->AddVar(psuper); + } + // initializes the variables as parameters + pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted + pStk->IncState(); + } + + if ( pStk->GivState() == 1 ) + { + if ( pt->m_bSynchro ) + { + CBotProgram* pProgBase = pStk->GivBotCall(true); + if ( !pClass->Lock(pProgBase) ) return false; // expected to power \TODO attend de pouvoir + } + pStk->IncState(); + } + // finally calls the found function + + if ( !pStk3->GivRetVar( // puts the result on the stack + pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted + { + if ( !pStk3->IsOk() ) + { + if ( pt->m_bSynchro ) + { + pClass->Unlock(); // release function + } + + if ( pt->m_pProg != pProgCurrent ) + { + pStk3->SetPosError(pToken); // indicates the error on the procedure call + } + } + return false; // interrupt ! + } + + if ( pt->m_bSynchro ) + { + pClass->Unlock(); // release function + } + + return pStack->Return( pStk3 ); + } + return -1; +} + +void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass) +{ + CBotTypResult type; + CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type); + + if ( pt != NULL ) + { + CBotStack* pStk = pStack->RestoreStack(pt); + if ( pStk == NULL ) return; + pStk->SetBotCall(pt->m_pProg); // it may have changed module + + CBotVar* pthis = pStk->FindVar("this"); + pthis->SetUniqNum(-2); + + CBotStack* pStk3 = pStk->RestoreStack(NULL); // to set parameters passed + if ( pStk3 == NULL ) return; + + pt->m_Param->RestoreState(pStk3, true); // parameters + + if ( pStk->GivState() > 1 && // latching is effective? + pt->m_bSynchro ) + { + CBotProgram* pProgBase = pStk->GivBotCall(true); + pClass->Lock(pProgBase); // locks the class + } + + // finally calls the found function + + pt->m_Block->RestoreState(pStk3, true); // interrupt ! + } +} + +// see if the "signature" of parameters is identical +bool CBotFunction::CheckParam(CBotDefParam* pParam) +{ + CBotDefParam* pp = m_Param; + while ( pp != NULL && pParam != NULL ) + { + CBotTypResult type1 = pp->GivType(); + CBotTypResult type2 = pParam->GivType(); + if ( !type1.Compare(type2) ) return false; + pp = pp->GivNext(); + pParam = pParam->GivNext(); + } + return ( pp == NULL && pParam == NULL ); +} + +CBotString CBotFunction::GivName() +{ + return m_token.GivString(); +} + +CBotString CBotFunction::GivParams() +{ + if ( m_Param == NULL ) return CBotString("()"); + + CBotString params = "( "; + CBotDefParam* p = m_Param; // list of parameters + + while (p != NULL) + { + params += p->GivParamString(); + p = p->GivNext(); + if ( p != NULL ) params += ", "; + } + + params += " )"; + return params; +} + +CBotFunction* CBotFunction::Next() +{ + return m_next; +} + +void CBotFunction::AddPublic(CBotFunction* func) +{ + if ( m_listPublic != NULL ) + { + func->m_nextpublic = m_listPublic; + m_listPublic->m_prevpublic = func; + } + m_listPublic = func; +} + + + +///////////////////////////////////////////////////////////////////////// +// management of parameters + + +CBotDefParam::CBotDefParam() +{ + m_next = NULL; + m_nIdent = 0; +} + +CBotDefParam::~CBotDefParam() +{ + delete m_next; +} + + +// compiles a list of parameters +CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) +{ + // mainly not pStack->TokenStack here + // declared variables must remain visible thereafter + + pStack->SetStartError(p->GivStart()); + + if (IsOfType(p, ID_OPENPAR)) + { + CBotDefParam* list = NULL; + + while (!IsOfType(p, ID_CLOSEPAR)) + { + CBotDefParam* param = new CBotDefParam(); + if (list == NULL) list = param; + else list->AddNext(param); // added to the list + + CBotClass* pClass = NULL;//= CBotClass::Find(p); + param->m_typename = p->GivString(); + CBotTypResult type = param->m_type = TypeParam(p, pStack); +// if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object + + if (param->m_type.GivType() > 0) + { + CBotToken* pp = p; + param->m_token = *p; + if (pStack->IsOk() && IsOfType(p, TokenTypVar) ) + { + + // variable already declared? + if (pStack->CheckVarLocal(pp)) + { + pStack->SetError(TX_REDEFVAR, pp); + break; + } + + if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); + CBotVar* var = CBotVar::Create(pp->GivString(), type); // creates the variable +// if ( pClass ) var->SetClass(pClass); + var->SetInit(2); // mark initialized + param->m_nIdent = CBotVar::NextUniqNum(); + var->SetUniqNum(param->m_nIdent); + pStack->AddVar(var); // place on the stack + + if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR) + continue; + } + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + } + pStack->SetError(TX_NOTYP, p); + delete list; + return NULL; + } + return list; + } + pStack->SetError(TX_OPENPAR, p->GivStart()); + return NULL; +} + +void CBotDefParam::AddNext(CBotDefParam* p) +{ + CBotDefParam* pp = this; + while (pp->m_next != NULL) pp = pp->m_next; + + pp->m_next = p; +} + + +bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) +{ + int i = 0; + CBotDefParam* p = this; + + while ( p != NULL ) + { + // creates a local variable on the stack + CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type); + + // serves to make the transformation of types: + if ( ppVars != NULL && ppVars[i] != NULL ) + { + switch (p->m_type.GivType()) + { + case CBotTypInt: + newvar->SetValInt(ppVars[i]->GivValInt()); + break; + case CBotTypFloat: + newvar->SetValFloat(ppVars[i]->GivValFloat()); + break; + case CBotTypString: + newvar->SetValString(ppVars[i]->GivValString()); + break; + case CBotTypBoolean: + newvar->SetValInt(ppVars[i]->GivValInt()); + break; + case CBotTypIntrinsic: + ((CBotVarClass*)newvar)->Copy(ppVars[i], false); + break; + case CBotTypPointer: + case CBotTypArrayPointer: + { + newvar->SetPointer(ppVars[i]->GivPointer()); + } + break; + default: + ASM_TRAP(); + } + } + newvar->SetUniqNum(p->m_nIdent); + pj->AddVar(newvar); // add a variable + p = p->m_next; + i++; + } + + return true; +} + +void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) +{ + int i = 0; + CBotDefParam* p = this; + + while ( p != NULL ) + { + // creates a local variable on the stack + CBotVar* var = pj->FindVar(p->m_token.GivString()); + var->SetUniqNum(p->m_nIdent); + p = p->m_next; + } +} + +int CBotDefParam::GivType() +{ + return m_type.GivType(); +} + +CBotTypResult CBotDefParam::GivTypResult() +{ + return m_type; +} + +CBotDefParam* CBotDefParam::GivNext() +{ + return m_next; +} + +CBotString CBotDefParam::GivParamString() +{ + CBotString param; + + param = m_typename; + param += ' '; + + param += m_token.GivString(); + return param; +} + + + +////////////////////////////////////////////////////////////////////////// +// return parameters + +CBotReturn::CBotReturn() +{ + m_Instr = NULL; + name = "CBotReturn"; // debug +} + +CBotReturn::~CBotReturn() +{ + delete m_Instr; +} + +CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; + + if (!IsOfType(p, ID_RETURN)) return NULL; // should never happen + + CBotReturn* inst = new CBotReturn(); // creates the object + inst->SetToken( pp ); + + CBotTypResult type = pStack->GivRetType(); + + if ( type.GivType() == 0 ) // returned void ? + { + if ( IsOfType( p, ID_SEP ) ) return inst; + pStack->SetError( TX_BADTYPE, pp ); + return NULL; + } + + inst->m_Instr = CBotExpression::Compile(p, pStack); + if ( pStack->IsOk() ) + { + CBotTypResult retType = pStack->GivTypResult(2); + if (TypeCompatible(retType, type, ID_ASS)) + { + if ( IsOfType( p, ID_SEP ) ) + return inst; + + pStack->SetError(TX_ENDOF, p->GivStart()); + } + pStack->SetError(TX_BADTYPE, p->GivStart()); + } + + delete inst; + return NULL; // no object, the error is on the stack +} + +bool CBotReturn::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); +// if ( pile == EOX ) return true; + + if ( pile->GivState() == 0 ) + { + if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // evaluate the result + // the result is on the stack + pile->IncState(); + } + + if ( pile->IfStep() ) return false; + + pile->SetBreak(3, CBotString()); + return pj->Return(pile); +} + +void CBotReturn::RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + CBotStack* pile = pj->RestoreStack(this); + if ( pile == NULL ) return; + + if ( pile->GivState() == 0 ) + { + if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // evaluate the result + return; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Calls of these functions + +CBotInstrCall::CBotInstrCall() +{ + m_Parameters = NULL; + m_nFuncIdent = 0; + name = "CBotInstrCall"; +} + +CBotInstrCall::~CBotInstrCall() +{ + delete m_Parameters; +} + +CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotVar* ppVars[1000]; + + int i = 0; + + CBotToken* pp = p; + p = p->GivNext(); + + pStack->SetStartError(p->GivStart()); + CBotCStack* pile = pStack; + + if ( IsOfType(p, ID_OPENPAR) ) + { + int start, end; + CBotInstrCall* inst = new CBotInstrCall(); + inst->SetToken(pp); + + // compile la list of parameters + if (!IsOfType(p, ID_CLOSEPAR)) while (true) + { + start = p->GivStart(); + pile = pile->TokenStack(); // keeps the results on the stack + + CBotInstr* param = CBotExpression::Compile(p, pile); + end = p->GivStart(); + if ( inst->m_Parameters == NULL ) inst->m_Parameters = param; + else inst->m_Parameters->AddNext(param); // constructs the list + + if ( !pile->IsOk() ) + { + delete inst; + return pStack->Return(NULL, pile); + } + + if ( param != NULL ) + { + if ( pile->GivTypResult().Eq(99) ) + { + delete pStack->TokenStack(); + pStack->SetError(TX_VOID, p->GivStart()); + delete inst; + return NULL; + } + ppVars[i] = pile->GivVar(); + ppVars[i]->GivToken()->SetPos(start, end); + i++; + + if (IsOfType(p, ID_COMMA)) continue; // skips the comma + if (IsOfType(p, ID_CLOSEPAR)) break; + } + + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + delete pStack->TokenStack(); + delete inst; + return NULL; + } + ppVars[i] = NULL; + + // the routine is known? +// CBotClass* pClass = NULL; + inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent); + if ( inst->m_typRes.GivType() >= 20 ) + { +// if (pVar2!=NULL) pp = pVar2->RetToken(); + pStack->SetError( inst->m_typRes.GivType(), pp ); + delete pStack->TokenStack(); + delete inst; + return NULL; + } + + delete pStack->TokenStack(); + if ( inst->m_typRes.GivType() > 0 ) + { + CBotVar* pRes = CBotVar::Create("", inst->m_typRes); + pStack->SetVar(pRes); // for knowing the type of the result + } + else pStack->SetVar(NULL); // routine returns void + + return inst; + } + p = pp; + delete pStack->TokenStack(); + return NULL; +} + +bool CBotInstrCall::Execute(CBotStack* &pj) +{ + CBotVar* ppVars[1000]; + CBotStack* pile = pj->AddStack(this); + if ( pile->StackOver() ) return pj->Return( pile ); + + CBotStack* pile1 = pile; + + int i = 0; + + CBotInstr* p = m_Parameters; + // evaluates parameters + // and places the values ​​on the stack + // for allow of interruption at any time + if ( p != NULL) while ( true ) + { + pile = pile->AddStack(); // place on the stack for the results + if ( pile->GivState() == 0 ) + { + if (!p->Execute(pile)) return false; // interrupted here? + pile->SetState(1); // mark as special for reknowed parameters \TODO marque spéciale pour reconnaîre parameters + } + ppVars[i++] = pile->GivVar(); + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotStack* pile2 = pile->AddStack(); + if ( pile2->IfStep() ) return false; + + if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return false; // interrupt + + return pj->Return(pile2); // release the entire stack +} + +void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pile = pj->RestoreStack(this); + if ( pile == NULL ) return; + + CBotStack* pile1 = pile; + + int i = 0; + CBotVar* ppVars[1000]; + CBotInstr* p = m_Parameters; + // evaluate parameters + // and place the values on the stack + // for allow of interruption at any time + if ( p != NULL) while ( true ) + { + pile = pile->RestoreStack(); // place on the stack for the results + if ( pile == NULL ) return; + if ( pile->GivState() == 0 ) + { + p->RestoreState(pile, bMain); // interrupt here! + return; + } + ppVars[i++] = pile->GivVar(); // constructs the list of parameters + p = p->GivNext(); + if ( p == NULL) break; + } + ppVars[i] = NULL; + + CBotStack* pile2 = pile->RestoreStack(); + if ( pile2 == NULL ) return; + + pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars); +} + +////////////////////////////////////////////////////////////////////////////// +// statement of user classes + +// pre-compile a new class +// analysis is complete except the body of routines + +CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack) +{ + if ( !IsOfType(p, ID_PUBLIC) ) + { + pStack->SetError(TX_NOPUBLIC, p); + return NULL; + } + + if ( !IsOfType(p, ID_CLASS) ) return NULL; + + CBotString name = p->GivString(); + + CBotClass* pOld = CBotClass::Find(name); + if ( pOld != NULL && pOld->m_IsDef ) + { + pStack->SetError( TX_REDEFCLASS, p ); + return NULL; + } + + // a name of the class is there? + if (IsOfType(p, TokenTypVar)) + { + CBotClass* pPapa = NULL; + if ( IsOfType( p, ID_EXTENDS ) ) + { + CBotString name = p->GivString(); + pPapa = CBotClass::Find(name); + + if (!IsOfType(p, TokenTypVar) || pPapa == NULL ) + { + pStack->SetError( TX_NOCLASS, p ); + return NULL; + } + } + CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld; + classe->Purge(); // emptythe old definitions + classe->m_IsDef = false; // current definition + + if ( !IsOfType( p, ID_OPBLK) ) + { + pStack->SetError(TX_OPENBLK, p); + return NULL; + } + + while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) ) + { + classe->CompileDefItem(p, pStack, false); + } + + if (pStack->IsOk()) return classe; + } + pStack->SetError(TX_ENDOF, p); + return NULL; +} + +bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) +{ + bool bStatic = false; + int mProtect = PR_PUBLIC; + bool bSynchro = false; + + while (IsOfType(p, ID_SEP)) ; + + CBotTypResult type( -1 ); + + if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true; + CBotToken* pBase = p; + + if ( IsOfType(p, ID_STATIC) ) bStatic = true; + if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC; + if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE; + if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT; + if ( IsOfType(p, ID_STATIC) ) bStatic = true; + +// CBotClass* pClass = NULL; + type = TypeParam(p, pStack); // type of the result + + if ( type.Eq(-1) ) + { + pStack->SetError(TX_NOTYP, p); + return false; + } + + while (pStack->IsOk()) + { + CBotToken* pp = p; + IsOfType(p, ID_NOT); // skips ~ eventual (destructor) + + if (IsOfType(p, TokenTypVar)) + { + CBotInstr* limites = NULL; + while ( IsOfType( p, ID_OPBRK ) ) // a table? + { + CBotInstr* i = NULL; + + if ( p->GivType() != ID_CLBRK ) + i = CBotExpression::Compile( p, pStack ); // expression for the value + else + i = new CBotEmpty(); // special if not a formula + + type = CBotTypResult(CBotTypArrayPointer, type); + + if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) ) + { + pStack->SetError(TX_CLBRK, p->GivStart()); + return false; + } + +/* CBotVar* pv = pStack->GivVar(); + if ( pv->GivType()>= CBotTypBoolean ) + { + pStack->SetError(TX_BADTYPE, p->GivStart()); + return false; + }*/ + + if (limites == NULL) limites = i; + else limites->AddNext3(i); + } + + if ( p->GivType() == ID_OPENPAR ) + { + if ( !bSecond ) + { + p = pBase; + CBotFunction* f = + CBotFunction::Compile1(p, pStack, this); + + if ( f == NULL ) return false; + + if (m_pMethod == NULL) m_pMethod = f; + else m_pMethod->AddNext(f); + } + else + { + // return a method precompiled in pass 1 + CBotFunction* pf = m_pMethod; + CBotFunction* prev = NULL; + while ( pf != NULL ) + { + if (pf->GivName() == pp->GivString()) break; + prev = pf; + pf = pf->Next(); + } + + bool bConstructor = (pp->GivString() == GivName()); + CBotCStack* pile = pStack->TokenStack(NULL, true); + + // make "this" known + CBotToken TokenThis(CBotString("this"), CBotString()); + CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) ); + pThis->SetUniqNum(-2); + pile->AddVar(pThis); + + if ( m_pParent ) + { + // makes "super" known + CBotToken TokenSuper(CBotString("super"), CBotString()); + CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) ); + pThis->SetUniqNum(-3); + pile->AddVar(pThis); + } + +// int num = 1; + CBotClass* my = this; + while (my != NULL) + { + // places a copy of variables of a class (this) on a stack + CBotVar* pv = my->m_pVar; + while (pv != NULL) + { + CBotVar* pcopy = CBotVar::Create(pv); + pcopy->SetInit(!bConstructor || pv->IsStatic()); + pcopy->SetUniqNum(pv->GivUniqNum()); + pile->AddVar(pcopy); + pv = pv->GivNext(); + } + my = my->m_pParent; + } + + // compiles a method + p = pBase; + CBotFunction* f = + CBotFunction::Compile(p, pile, NULL/*, false*/); + + if ( f != NULL ) + { + f->m_pProg = pStack->GivBotCall(); + f->m_bSynchro = bSynchro; + // replaces the element in the chain + f->m_next = pf->m_next; + pf->m_next = NULL; + delete pf; + if (prev == NULL) m_pMethod = f; + else prev->m_next = f; + } + pStack->Return(NULL, pile); + } + + return pStack->IsOk(); + } + + // definition of an element + if (type.Eq(0)) + { + pStack->SetError(TX_ENDOF, p); + return false; + } + + CBotInstr* i = NULL; + if ( IsOfType(p, ID_ASS ) ) + { + if ( type.Eq(CBotTypArrayPointer) ) + { + i = CBotListArray::Compile(p, pStack, type.GivTypElem()); + } + else + { + // it has an assignmet to calculate + i = CBotTwoOpExpr::Compile(p, pStack); + } + if ( !pStack->IsOk() ) return false; + } + + + if ( !bSecond ) + { + CBotVar* pv = CBotVar::Create(pp->GivString(), type); + pv -> SetStatic( bStatic ); + pv -> SetPrivate( mProtect ); + + AddItem( pv ); + + pv->m_InitExpr = i; + pv->m_LimExpr = limites; + + + if ( pv->IsStatic() && pv->m_InitExpr != NULL ) + { + CBotStack* pile = CBotStack::FirstStack(); // independent stack + while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer + pv->SetVal( pile->GivVar() ) ; + pile->Delete(); + } + } + else + delete i; + + if ( IsOfType(p, ID_COMMA) ) continue; + if ( IsOfType(p, ID_SEP) ) break; + } + pStack->SetError(TX_ENDOF, p); + } + return pStack->IsOk(); +} + + +CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack) +{ + if ( !IsOfType(p, ID_PUBLIC) ) return NULL; + if ( !IsOfType(p, ID_CLASS) ) return NULL; + + CBotString name = p->GivString(); + + // a name for the class is there? + if (IsOfType(p, TokenTypVar)) + { + // the class was created by Compile1 + CBotClass* pOld = CBotClass::Find(name); + + if ( IsOfType( p, ID_EXTENDS ) ) + { + IsOfType(p, TokenTypVar); // necessarily + } + IsOfType( p, ID_OPBLK); // necessarily + + while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) ) + { + pOld->CompileDefItem(p, pStack, true); + } + + pOld->m_IsDef = true; // complete definition + if (pStack->IsOk()) return pOld; + } + pStack->SetError(TX_ENDOF, p); + return NULL; +} diff --git a/src/CBot/CBotIf.cpp b/src/CBot/CBotIf.cpp index 178992e..c1dc833 100644 --- a/src/CBot/CBotIf.cpp +++ b/src/CBot/CBotIf.cpp @@ -1,159 +1,161 @@ -// * 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/.///////////////////////////////////////////////////////////////////////
-// instruction if (condition) opération1 else opération2;
-
-#include "CBot.h"
-
-// les divers constructeurs / destructeurs
-CBotIf::CBotIf()
-{
- m_Condition =
- m_Block =
- m_BlockElse = NULL; // NULL pour pouvoir faire delete directement
- name = "CBotIf"; // debug
-}
-
-CBotIf::~CBotIf()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction1
- delete m_BlockElse; // libère le bloc d'instruction2
-}
-
-// compilation (routine statique)
-// appelé lorsque le token "if" a été trouvé
-
-CBotInstr* CBotIf::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p; // conserve le ^au token (début instruction)
-
- if (!IsOfType(p, ID_IF)) return NULL; // ne doit jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- CBotIf* inst = new CBotIf(); // crée l'object
- inst->SetToken( pp );
-
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe bel et bien
-
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (peut être vide)
-
- // regarde si l'instruction suivante est le token "else"
- if (IsOfType(p, ID_ELSE))
- {
- // si oui, compile le bloc d'instruction qui suit
- inst->m_BlockElse = CBotBlock::CompileBlkOrInst( p, pStk, true );
- if (!pStk->IsOk())
- {
- // il n'y a pas de bloc correct après le else
- // libère l'objet, et transmet l'erreur qui est sur la pile
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- }
-
- // rend l'object correct à qui le demande.
- return pStack->Return(inst, pStk);
- }
- }
-
- // erreur, libère l'objet
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile.
- return pStack->Return(NULL, pStk);
-}
-
-
-// exécution de l'instruction
-
-bool CBotIf :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- // selon la reprise, on peut être dans l'un des 2 états
- if( pile->GivState() == 0 )
- {
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ?
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // passe dans le second état
- if (!pile->SetState(1)) return false; // prêt pour la suite
- }
-
- // second état, évalue les instructions associées
- // le résultat de la condition est sur la pile
-
- if ( pile->GivVal() == true ) // condition était vraie ?
- {
- if ( m_Block != NULL && // bloc peut être absent
- !m_Block->Execute(pile) ) return false; // interrompu ici ?
- }
- else
- {
- if ( m_BlockElse != NULL && // s'il existe un bloc alternatif
- !m_BlockElse->Execute(pile) ) return false; // interrompu ici
- }
-
- // transmet le résultat et libère la pile
- return pj->Return(pile);
-}
-
-
-void CBotIf :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- // selon la reprise, on peut être dans l'un des 2 états
- if( pile->GivState() == 0 )
- {
- // évalue la condition
- m_Condition->RestoreState(pile, bMain); // interrompu ici !
- return;
- }
-
- // second état, évalue les instructions associées
- // le résultat de la condition est sur la pile
-
- if ( pile->GivVal() == true ) // condition était vraie ?
- {
- if ( m_Block != NULL ) // bloc peut être absent
- m_Block->RestoreState(pile, bMain); // interrompu ici !
- }
- else
- {
- if ( m_BlockElse != NULL ) // s'il existe un bloc alternatif
- m_BlockElse->RestoreState(pile, bMain); // interrompu ici !
- }
-}
-
+// * 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/. + +/////////////////////////////////////////////////////////////////////// +// instruction if (condition) operation1 else operation2; + +#include "CBot.h" + +// various constructors / destructors +CBotIf::CBotIf() +{ + m_Condition = + m_Block = + m_BlockElse = NULL; // NULL so that delete is not possible further + name = "CBotIf"; // debug +} + +CBotIf::~CBotIf() +{ + delete m_Condition; // frees the condition + delete m_Block; // frees the block of instruction1 + delete m_BlockElse; // frees the block of instruction2 +} + +// compilation (static routine) +// called when the token "if" has been found + +CBotInstr* CBotIf::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; // preserves at the ^ token (starting instruction) + + if (!IsOfType(p, ID_IF)) return NULL; // should never happen + + CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + + CBotIf* inst = new CBotIf(); // create the object + inst->SetToken( pp ); + + if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) ) + { + // the condition does exist + + inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); + if ( pStk->IsOk() ) + { + // the statement block is ok (can be empty) + + // see if the next instruction is the token "else" + if (IsOfType(p, ID_ELSE)) + { + // if so, compiles the following statement block + inst->m_BlockElse = CBotBlock::CompileBlkOrInst( p, pStk, true ); + if (!pStk->IsOk()) + { + // there is no correct block after the else + // frees the object, and transmits the error that is on the stack + delete inst; + return pStack->Return(NULL, pStk); + } + } + + // return the corrent object to the application + return pStack->Return(inst, pStk); + } + } + + // error, frees the object + delete inst; + // and transmits the error that is on the stack. + return pStack->Return(NULL, pStk); +} + + +// execution of the instruction + +bool CBotIf :: Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); // adds an item to the stack + // or found in case of recovery +// if ( pile == EOX ) return true; + + if ( pile->IfStep() ) return false; + + // according to recovery, it may be in one of two states + if( pile->GivState() == 0 ) + { + // evaluates the condition + if ( !m_Condition->Execute(pile) ) return false; // interrupted here? + + // terminates if there is an error + if ( !pile->IsOk() ) + { + return pj->Return(pile); // returns the results and releases the stack + } + + // passes into the second state + if (!pile->SetState(1)) return false; // ready for further + } + + // second state, evaluates the associated instructions + // the result of the condition is on the stack + + if ( pile->GivVal() == true ) // condition was true? + { + if ( m_Block != NULL && // block may be absent + !m_Block->Execute(pile) ) return false; // interrupted here? + } + else + { + if ( m_BlockElse != NULL && // if there is an alternate block + !m_BlockElse->Execute(pile) ) return false; // interrupted here + } + + // sends the results and releases the stack + return pj->Return(pile); +} + + +void CBotIf :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack + if ( pile == NULL ) return; + + // according to recovery, it may be in one of two states + if( pile->GivState() == 0 ) + { + // evaluates the condition + m_Condition->RestoreState(pile, bMain); // interrupted here! + return; + } + + // second state, evaluates the associated instructions + // the result of the condition is on the stack + + if ( pile->GivVal() == true ) // condition was true? + { + if ( m_Block != NULL ) // block may be absent + m_Block->RestoreState(pile, bMain); // interrupted here! + } + else + { + if ( m_BlockElse != NULL ) // if there is an alternate block + m_BlockElse->RestoreState(pile, bMain); // interrupted here! + } +} + diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index bbdc350..5f1c021 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -1,1117 +1,1113 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.//////////////////////////////////////////////////////////////////////
-// gestion de base d'un programme CBot
-
-#include "CBot.h"
-#include <stdio.h>
-
-CBotProgram::CBotProgram()
-{
- m_Prog = NULL;
- m_pRun = NULL;
- m_pClass = NULL;
- m_pStack = NULL;
- m_pInstance = NULL;
-
- m_ErrorCode = 0;
- m_Ident = 0;
- m_bDebugDD = 0;
-}
-
-CBotProgram::CBotProgram(CBotVar* pInstance)
-{
- m_Prog = NULL;
- m_pRun = NULL;
- m_pClass = NULL;
- m_pStack = NULL;
- m_pInstance = pInstance;
-
- m_ErrorCode = 0;
- m_Ident = 0;
- m_bDebugDD = 0;
-}
-
-
-CBotProgram::~CBotProgram()
-{
-// delete m_pClass;
- m_pClass->Purge();
- m_pClass = NULL;
-
- CBotClass::FreeLock(this);
-
- delete m_Prog;
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
-}
-
-
-bool CBotProgram::Compile( const char* program, CBotStringArray& ListFonctions, void* pUser )
-{
- int error = 0;
- Stop();
-
-// delete m_pClass;
- m_pClass->Purge(); // purge les anciennes définitions des classes
- // mais sans détruire l'object
- m_pClass = NULL;
- delete m_Prog; m_Prog= NULL;
-
- ListFonctions.SetSize(0);
- m_ErrorCode = 0;
-
- if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
- pUser = m_pInstance->m_pUserPtr;
-
- // transforme le programme en Tokens
- CBotToken* pBaseToken = CBotToken::CompileTokens(program, error);
- if ( pBaseToken == NULL ) return false;
-
-
- CBotCStack* pStack = new CBotCStack(NULL);
- CBotToken* p = pBaseToken->GivNext(); // saute le 1er token (séparateur)
-
- pStack->SetBotCall(this); // défini les routines utilisables
- CBotCall::SetPUser(pUser);
-
- // fait une première passe rapide juste pour prendre les entêtes de routines et de classes
- while ( pStack->IsOk() && p != NULL && p->GivType() != 0)
- {
- if ( IsOfType(p, ID_SEP) ) continue; // des point-virgules qui trainent
-
- if ( p->GivType() == ID_CLASS ||
- ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
- {
- CBotClass* nxt = CBotClass::Compile1(p, pStack);
- if (m_pClass == NULL ) m_pClass = nxt;
- else m_pClass->AddNext(nxt);
- }
- else
- {
- CBotFunction* next = CBotFunction::Compile1(p, pStack, NULL);
- if (m_Prog == NULL ) m_Prog = next;
- else m_Prog->AddNext(next);
- }
- }
- if ( !pStack->IsOk() )
- {
- m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
- delete m_Prog;
- m_Prog = NULL;
- delete pBaseToken;
- return false;
- }
-
-// CBotFunction* temp = NULL;
- CBotFunction* next = m_Prog; // reprend la liste
-
- p = pBaseToken->GivNext(); // revient au début
-
- while ( pStack->IsOk() && p != NULL && p->GivType() != 0 )
- {
- if ( IsOfType(p, ID_SEP) ) continue; // des point-virgules qui trainent
-
- if ( p->GivType() == ID_CLASS ||
- ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
- {
- m_bCompileClass = true;
- CBotClass::Compile(p, pStack); // complète la définition de la classe
- }
- else
- {
- m_bCompileClass = false;
- CBotFunction::Compile(p, pStack, next);
- if (next->IsExtern()) ListFonctions.Add(next->GivName()/* + next->GivParams()*/);
- next->m_pProg = this; // garde le pointeur au module
- next = next->Next();
- }
- }
-
-// delete m_Prog; // la liste de la 1ère passe
-// m_Prog = temp; // la liste de la seconde passe
-
- if ( !pStack->IsOk() )
- {
- m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
- delete m_Prog;
- m_Prog = NULL;
- }
-
- delete pBaseToken;
- delete pStack;
-
- return (m_Prog != NULL);
-}
-
-
-bool CBotProgram::Start(const char* name)
-{
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
-
- m_pRun = m_Prog;
- while (m_pRun != NULL)
- {
- if ( m_pRun->GivName() == name ) break;
- m_pRun = m_pRun->m_next;
- }
-
- if ( m_pRun == NULL )
- {
- m_ErrorCode = TX_NORUN;
- return false;
- }
-
-#if STACKMEM
- m_pStack = CBotStack::FirstStack();
-#else
- m_pStack = new CBotStack(NULL); // crée une pile d'exécution
-#endif
-
- m_pStack->SetBotCall(this); // bases pour les routines
-
- return true; // on est prêt pour un Run()
-}
-
-bool CBotProgram::GetPosition(const char* name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
-{
- CBotFunction* p = m_Prog;
- while (p != NULL)
- {
- if ( p->GivName() == name ) break;
- p = p->m_next;
- }
-
- if ( p == NULL ) return false;
-
- p->GetPosition(start, stop, modestart, modestop);
- return true;
-}
-
-bool CBotProgram::Run(void* pUser, int timer)
-{
- bool ok;
-
- if (m_pStack == NULL || m_pRun == NULL) goto error;
-
- m_ErrorCode = 0;
- if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
- pUser = m_pInstance->m_pUserPtr;
-
- m_pStack->Reset(pUser); // vide l'éventuelle erreur précédente, et remet le timer
- if ( timer >= 0 ) m_pStack->SetTimer(timer);
-
- m_pStack->SetBotCall(this); // bases pour les routines
-
-#if STACKRUN
- // reprend l'exécution sur le haut de la pile
- ok = m_pStack->Execute();
- if ( ok )
- {
-#ifdef _DEBUG
- CBotVar* ppVar[3];
- ppVar[0] = CBotVar::Create("aa", CBotTypInt);
- ppVar[1] = CBotVar::Create("bb", CBotTypInt);
- ppVar[2] = NULL;
- ok = m_pRun->Execute(ppVar, m_pStack, m_pInstance);
-#else
- // revient sur l'exécution normale
- ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
-#endif
- }
-#else
- ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
-#endif
-
- // terminé sur une erreur ?
- if (!ok && !m_pStack->IsOk())
- {
- m_ErrorCode = m_pStack->GivError(m_ErrorStart, m_ErrorEnd);
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
- return true; // exécution terminée !!
- }
-
- if ( ok ) m_pRun = NULL; // plus de fonction en exécution
- return ok;
-
-error:
- m_ErrorCode = TX_NORUN;
- return true;
-}
-
-void CBotProgram::Stop()
-{
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
- m_pRun = NULL;
-}
-
-
-
-bool CBotProgram::GetRunPos(const char* &FunctionName, int &start, int &end)
-{
- FunctionName = NULL;
- start = end = 0;
- if (m_pStack == NULL) return false;
-
- m_pStack->GetRunPos(FunctionName, start, end);
- return true;
-}
-
-CBotVar* CBotProgram::GivStackVars(const char* &FunctionName, int level)
-{
- FunctionName = NULL;
- if (m_pStack == NULL) return NULL;
-
- return m_pStack->GivStackVars(FunctionName, level);
-}
-
-
-
-
-
-
-
-void CBotProgram::SetTimer(int n)
-{
- CBotStack::SetTimer( n );
-}
-
-int CBotProgram::GivError()
-{
- return m_ErrorCode;
-}
-
-void CBotProgram::SetIdent(long n)
-{
- m_Ident = n;
-}
-
-long CBotProgram::GivIdent()
-{
- return m_Ident;
-}
-
-bool CBotProgram::GetError(int& code, int& start, int& end)
-{
- code = m_ErrorCode;
- start = m_ErrorStart;
- end = m_ErrorEnd;
- return code > 0;
-}
-
-bool CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg)
-{
- code = m_ErrorCode;
- start = m_ErrorStart;
- end = m_ErrorEnd;
- pProg = this;
- return code > 0;
-}
-
-CBotString CBotProgram::GivErrorText(int code)
-{
- CBotString TextError;
-
- TextError.LoadString( code );
- if (TextError.IsEmpty())
- {
- char buf[100];
- sprintf(buf, "Exception numéro %d.", code);
- TextError = buf;
- }
- return TextError;
-}
-
-
-CBotFunction* CBotProgram::GivFunctions()
-{
- return m_Prog;
-}
-
-bool CBotProgram::AddFunction(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- // mémorise les pointeurs aux deux fonctions
- return CBotCall::AddFunction(name, rExec, rCompile);
-}
-
-
-bool WriteWord(FILE* pf, unsigned short w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( unsigned short ), 1, pf );
-
- return (lg == 1);
-}
-
-bool ReadWord(FILE* pf, unsigned short& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( unsigned short ), 1, pf );
-
- return (lg == 1);
-}
-
-bool WriteFloat(FILE* pf, float w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( float ), 1, pf );
-
- return (lg == 1);
-}
-
-bool ReadFloat(FILE* pf, float& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( float ), 1, pf );
-
- return (lg == 1);
-}
-
-bool WriteLong(FILE* pf, long w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( long ), 1, pf );
-
- return (lg == 1);
-}
-
-bool ReadLong(FILE* pf, long& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( long ), 1, pf );
-
- return (lg == 1);
-}
-
-bool WriteString(FILE* pf, CBotString s)
-{
- size_t lg1, lg2;
-
- lg1 = s.GivLength();
- if (!WriteWord(pf, lg1)) return false;
-
- lg2 = fwrite(s, 1, lg1, pf );
- return (lg1 == lg2);
-}
-
-bool ReadString(FILE* pf, CBotString& s)
-{
- unsigned short w;
- char buf[1000];
- size_t lg1, lg2;
-
- if (!ReadWord(pf, w)) return false;
- lg1 = w;
- lg2 = fread(buf, 1, lg1, pf );
- buf[lg2] = 0;
-
- s = buf;
- return (lg1 == lg2);
-}
-
-bool WriteType(FILE* pf, CBotTypResult type)
-{
- int typ = type.GivType();
- if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
- if ( !WriteWord(pf, typ) ) return false;
- if ( typ == CBotTypClass )
- {
- CBotClass* p = type.GivClass();
- if ( !WriteString(pf, p->GivName()) ) return false;
- }
- if ( type.Eq( CBotTypArrayBody ) ||
- type.Eq( CBotTypArrayPointer ) )
- {
- if ( !WriteWord(pf, type.GivLimite()) ) return false;
- if ( !WriteType(pf, type.GivTypElem()) ) return false;
- }
- return true;
-}
-
-bool ReadType(FILE* pf, CBotTypResult& type)
-{
- unsigned short w, ww;
- if ( !ReadWord(pf, w) ) return false;
- type.SetType(w);
-
- if ( type.Eq( CBotTypIntrinsic ) )
- {
- type = CBotTypResult( w, "point" );
- }
-
- if ( type.Eq( CBotTypClass ) )
- {
- CBotString s;
- if ( !ReadString(pf, s) ) return false;
- type = CBotTypResult( w, s );
- }
-
- if ( type.Eq( CBotTypArrayPointer ) ||
- type.Eq( CBotTypArrayBody ) )
- {
- CBotTypResult r;
- if ( !ReadWord(pf, ww) ) return false;
- if ( !ReadType(pf, r) ) return false;
- type = CBotTypResult( w, r );
- type.SetLimite((short)ww);
- }
- return true;
-}
-
-
-bool CBotProgram::DefineNum(const char* name, long val)
-{
- return CBotToken::DefineNum(name, val);
-}
-
-
-bool CBotProgram::SaveState(FILE* pf)
-{
- if (!WriteWord( pf, CBOTVERSION)) return false;
-
-
- if ( m_pStack != NULL )
- {
- if (!WriteWord( pf, 1)) return false;
- if (!WriteString( pf, m_pRun->GivName() )) return false;
- if (!m_pStack->SaveState(pf)) return false;
- }
- else
- {
- if (!WriteWord( pf, 0)) return false;
- }
- return true;
-}
-
-
-bool CBotProgram::RestoreState(FILE* pf)
-{
- unsigned short w;
- CBotString s;
-
- Stop();
-
- if (!ReadWord( pf, w )) return false;
- if ( w != CBOTVERSION ) return false;
-
- if (!ReadWord( pf, w )) return false;
- if ( w == 0 ) return true;
-
- if (!ReadString( pf, s )) return false;
- Start(s); // point de reprise
-
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
-
- // récupère la pile depuis l'enregistrement
- // utilise un pointeur NULL (m_pStack) mais c'est ok comme ça
- if (!m_pStack->RestoreState(pf, m_pStack)) return false;
- m_pStack->SetBotCall(this); // bases pour les routines
-
- // rétabli certains états dans la pile selon la structure
- m_pRun->RestoreState(NULL, m_pStack, m_pInstance);
- return true;
-}
-
-int CBotProgram::GivVersion()
-{
- return CBOTVERSION;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CBotCall* CBotCall::m_ListCalls = NULL;
-
-CBotCall::CBotCall(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- m_name = name;
- m_rExec = rExec;
- m_rComp = rCompile;
- m_next = NULL;
- m_nFuncIdent = CBotVar::NextUniqNum();
-}
-
-CBotCall::~CBotCall()
-{
- if (m_next) delete m_next;
- m_next = NULL;
-}
-
-void CBotCall::Free()
-{
- delete CBotCall::m_ListCalls;
-}
-
-bool CBotCall::AddFunction(const char* name,
- bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- CBotCall* p = m_ListCalls;
- CBotCall* pp = NULL;
-
- if ( p != NULL ) while ( p->m_next != NULL )
- {
- if ( p->GivName() == name )
- {
- // libère une fonction qu'on redéfini
- if ( pp ) pp->m_next = p->m_next;
- else m_ListCalls = p->m_next;
- pp = p;
- p = p->m_next;
- pp->m_next = NULL; // ne pas détruire la suite de la liste
- delete pp;
- continue;
- }
- pp = p; // pointeur précédent
- p = p->m_next;
- }
-
- pp = new CBotCall(name, rExec, rCompile);
-
- if (p) p->m_next = pp;
- else m_ListCalls = pp;
-
- return true;
-}
-
-
-// transforme le tableau de pointeurs aux variables
-// en une liste de variables chaînées
-CBotVar* MakeListVars(CBotVar** ppVars, bool bSetVal=false)
-{
- int i = 0;
- CBotVar* pVar = NULL;
-
- while( true )
- {
- ppVars[i];
- if ( ppVars[i] == NULL ) break;
-
- CBotVar* pp = CBotVar::Create(ppVars[i]);
- if (bSetVal) pp->Copy(ppVars[i]);
- else
- if ( ppVars[i]->GivType() == CBotTypPointer )
- pp->SetClass( ppVars[i]->GivClass());
-// copier le pointeur selon indirection
- if (pVar == NULL) pVar = pp;
- else pVar->AddNext(pp);
- i++;
- }
- return pVar;
-}
-
-// trouve un appel acceptable selon le nom de la procédure
-// et les paramètres donnés
-
-CBotTypResult CBotCall::CompileCall(CBotToken* &p, CBotVar** ppVar, CBotCStack* pStack, long& nIdent)
-{
- nIdent = 0;
- CBotCall* pt = m_ListCalls;
- CBotString name = p->GivString();
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- CBotVar* pVar = MakeListVars(ppVar);
- CBotVar* pVar2 = pVar;
- CBotTypResult r = pt->m_rComp(pVar2, m_pUser);
- int ret = r.GivType();
-
- // si une classe est retournée, c'est en fait un pointeur
- if ( ret == CBotTypClass ) r.SetType( ret = CBotTypPointer );
-
- if ( ret > 20 )
- {
- if (pVar2) pStack->SetError(ret, p /*pVar2->GivToken()*/ );
- }
- delete pVar;
- nIdent = pt->m_nFuncIdent;
- return r;
- }
- pt = pt->m_next;
- }
- return -1;
-}
-
-void* CBotCall::m_pUser = NULL;
-
-void CBotCall::SetPUser(void* pUser)
-{
- m_pUser = pUser;
-}
-
-bool CBotCall::CheckCall(const char* name)
-{
- CBotCall* p = m_ListCalls;
-
- while ( p != NULL )
- {
- if ( name == p->GivName() ) return true;
- p = p->m_next;
- }
- return false;
-}
-
-
-
-CBotString CBotCall::GivName()
-{
- return m_name;
-}
-
-CBotCall* CBotCall::Next()
-{
- return m_next;
-}
-
-
-int CBotCall::DoCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack, CBotTypResult& rettype)
-{
- CBotCall* pt = m_ListCalls;
-
- if ( nIdent ) while ( pt != NULL )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- goto fund;
- }
- pt = pt->m_next;
- }
-
- pt = m_ListCalls;
-
- if ( token != NULL )
- {
- CBotString name = token->GivString();
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- nIdent = pt->m_nFuncIdent;
- goto fund;
- }
- pt = pt->m_next;
- }
- }
-
- return -1;
-
-fund:
-#if !STACKRUN
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVar, true);
- CBotVar* pVarToDelete = pVar;
-
- // crée une variable pour le résultat
- CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
-
- CBotVar* pRes = pResult;
- int Exception = 0;
- int res = pt->m_rExec(pVar, pResult, Exception, pStack->GivPUser());
-
- if ( pResult != pRes ) delete pRes; // si résultat différent rendu
- delete pVarToDelete;
-
- if (res == false)
- {
- if (Exception!=0)
- {
- pStack->SetError(Exception, token);
- }
- delete pResult;
- return false;
- }
- pStack->SetVar(pResult);
-
- if ( rettype.GivType() > 0 && pResult == NULL )
- {
- pStack->SetError(TX_NORETVAL, token);
- }
- nIdent = pt->m_nFuncIdent;
- return true;
-
-#else
-
- CBotStack* pile = pStack->AddStackEOX(pt);
- if ( pile == EOX ) return true;
-
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVar, true);
- CBotVar* pVarToDelete = pVar;
-
- // crée une variable pour le résultat
- CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
-
- pile->SetVar( pVar );
-
- CBotStack* pile2 = pile->AddStack();
- pile2->SetVar( pResult );
-
- pile->SetError(0, token); // pour la position en cas d'erreur + loin
- return pt->Run( pStack );
-
-#endif
-
-}
-
-#if STACKRUN
-
-bool CBotCall::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack)
-{
- CBotCall* pt = m_ListCalls;
-
- {
- CBotString name = token->GivString();
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- nIdent = pt->m_nFuncIdent;
-
- CBotStack* pile = pStack->RestoreStackEOX(pt);
- if ( pile == NULL ) return true;
-
- CBotStack* pile2 = pile->RestoreStack();
- return true;
- }
- pt = pt->m_next;
- }
- }
-
- return false;
-}
-
-bool CBotCall::Run(CBotStack* pStack)
-{
- CBotStack* pile = pStack->AddStackEOX(this);
- if ( pile == EOX ) return true;
- CBotVar* pVar = pile->GivVar();
-
- CBotStack* pile2 = pile->AddStack();
- CBotVar* pResult = pile2->GivVar();
- CBotVar* pRes = pResult;
-
- int Exception = 0;
- int res = m_rExec(pVar, pResult, Exception, pStack->GivPUser());
-
- if (res == false)
- {
- if (Exception!=0)
- {
- pStack->SetError(Exception);
- }
- if ( pResult != pRes ) delete pResult; // si résultat différent rendu
- return false;
- }
-
- if ( pResult != NULL ) pStack->SetCopyVar( pResult );
- if ( pResult != pRes ) delete pResult; // si résultat différent rendu
-
- return true;
-}
-
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////
-
-CBotCallMethode::CBotCallMethode(const char* name,
- bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
-{
- m_name = name;
- m_rExec = rExec;
- m_rComp = rCompile;
- m_next = NULL;
- m_nFuncIdent = CBotVar::NextUniqNum();
-}
-
-CBotCallMethode::~CBotCallMethode()
-{
- delete m_next;
- m_next = NULL;
-}
-
-// trouve un appel acceptable selon le nom de la procédure
-// et les paramètres donnés
-
-CBotTypResult CBotCallMethode::CompileCall(const char* name, CBotVar* pThis,
- CBotVar** ppVar, CBotCStack* pStack,
- long& nIdent)
-{
- CBotCallMethode* pt = this;
- nIdent = 0;
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- CBotVar* pVar = MakeListVars(ppVar, true);
- CBotVar* pVar2 = pVar;
- CBotTypResult r = pt->m_rComp(pThis, pVar2);
- int ret = r.GivType();
- if ( ret > 20 )
- {
- if (pVar2) pStack->SetError(ret, pVar2->GivToken());
- }
- delete pVar;
- nIdent = pt->m_nFuncIdent;
- return r;
- }
- pt = pt->m_next;
- }
- return CBotTypResult(-1);
-}
-
-
-CBotString CBotCallMethode::GivName()
-{
- return m_name;
-}
-
-CBotCallMethode* CBotCallMethode::Next()
-{
- return m_next;
-}
-
-void CBotCallMethode::AddNext(CBotCallMethode* pt)
-{
- CBotCallMethode* p = this;
- while ( p->m_next != NULL ) p = p->m_next;
-
- p->m_next = pt;
-}
-
-
-int CBotCallMethode::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pToken)
-{
- CBotCallMethode* pt = this;
-
- // recherche selon l'identificateur
-
- if ( nIdent ) while ( pt != NULL )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVars, true);
- CBotVar* pVarToDelete = pVar;
-
- // puis appelle la routine externe au module
-
- int Exception = 0;
- int res = pt->m_rExec(pThis, pVar, pResult, Exception);
- pStack->SetVar(pResult);
-
- if (res == false)
- {
- if (Exception!=0)
- {
-// pStack->SetError(Exception, pVar->GivToken());
- pStack->SetError(Exception, pToken);
- }
- delete pVarToDelete;
- return false;
- }
- delete pVarToDelete;
- return true;
- }
- pt = pt->m_next;
- }
-
- // recherche selon le nom
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVars, true);
- CBotVar* pVarToDelete = pVar;
-
- int Exception = 0;
- int res = pt->m_rExec(pThis, pVar, pResult, Exception);
- pStack->SetVar(pResult);
-
- if (res == false)
- {
- if (Exception!=0)
- {
-// pStack->SetError(Exception, pVar->GivToken());
- pStack->SetError(Exception, pToken);
- }
- delete pVarToDelete;
- return false;
- }
- delete pVarToDelete;
- nIdent = pt->m_nFuncIdent;
- return true;
- }
- pt = pt->m_next;
- }
-
- return -1;
-}
-
-bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- if ( pVar == NULL ) return TX_LOWPARAM;
-
- int i = 0;
- pVar = pVar->GivItemList();
-
- while ( pVar != NULL )
- {
- i++;
- pVar = pVar->GivNext();
- }
-
- pResult->SetValInt(i);
- return true;
-}
-
-CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
-{
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
- if ( pVar->GivType() != CBotTypArrayPointer )
- return CBotTypResult( TX_BADPARAM );
- return CBotTypResult( CBotTypInt );
-}
-
-
-CBotString CBotProgram::m_DebugVarStr = "";
-
-bool rCBotDebug( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- pResult->SetValString( CBotProgram::m_DebugVarStr );
-
- return true;
-}
-
-CBotTypResult cCBotDebug( CBotVar* &pVar, void* pUser )
-{
- // pas de paramètre
- if ( pVar != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // la fonction retourne un résultat "string"
- return CBotTypResult( CBotTypString );
-}
-
-
-#include "StringFunctions.cpp"
-
-void CBotProgram::Init()
-{
- CBotToken::DefineNum( "CBotErrOpenPar", 5000) ; // manque la parenthèse ouvrante
- CBotToken::DefineNum( "CBotErrClosePar", 5001) ; // manque la parenthèse fermante
- CBotToken::DefineNum( "CBotErrNotBoolean", 5002) ; // l'expression doit être un boolean
- CBotToken::DefineNum( "CBotErrUndefVar", 5003) ; // variable non déclarée
- CBotToken::DefineNum( "CBotErrBadLeft", 5004) ; // assignation impossible ( 5 = ... )
- CBotToken::DefineNum( "CBotErrNoTerminator", 5005) ;// point-virgule attendu
- CBotToken::DefineNum( "CBotErrCaseOut", 5006) ; // case en dehors d'un switch
- CBotToken::DefineNum( "CBotErrCloseBlock", 5008) ; // manque " } "
- CBotToken::DefineNum( "CBotErrElseWhitoutIf", 5009) ;// else sans if correspondant
- CBotToken::DefineNum( "CBotErrOpenBlock", 5010) ; // manque " { "
- CBotToken::DefineNum( "CBotErrBadType1", 5011) ; // mauvais type pour l'assignation
- CBotToken::DefineNum( "CBotErrRedefVar", 5012) ; // redéfinition de la variable
- CBotToken::DefineNum( "CBotErrBadType2", 5013) ; // 2 opérandes de type incompatibles
- CBotToken::DefineNum( "CBotErrUndefCall", 5014) ; // routine inconnue
- CBotToken::DefineNum( "CBotErrNoDoubleDots", 5015) ;// " : " attendu
- CBotToken::DefineNum( "CBotErrBreakOutside", 5017) ;// break en dehors d'une boucle
- CBotToken::DefineNum( "CBotErrUndefLabel", 5019) ; // label inconnu
- CBotToken::DefineNum( "CBotErrLabel", 5018) ; // label ne peut se mettre ici
- CBotToken::DefineNum( "CBotErrNoCase", 5020) ; // manque " case "
- CBotToken::DefineNum( "CBotErrBadNum", 5021) ; // nombre attendu
- CBotToken::DefineNum( "CBotErrVoid", 5022) ; // " void " pas possible ici
- CBotToken::DefineNum( "CBotErrNoType", 5023) ; // déclaration de type attendue
- CBotToken::DefineNum( "CBotErrNoVar", 5024) ; // nom de variable attendu
- CBotToken::DefineNum( "CBotErrNoFunc", 5025) ; // nom de fonction attendu
- CBotToken::DefineNum( "CBotErrOverParam", 5026) ; // trop de paramètres
- CBotToken::DefineNum( "CBotErrRedefFunc", 5027) ; // cette fonction existe déjà
- CBotToken::DefineNum( "CBotErrLowParam", 5028) ; // pas assez de paramètres
- CBotToken::DefineNum( "CBotErrBadParam", 5029) ; // mauvais types de paramètres
- CBotToken::DefineNum( "CBotErrNbParam", 5030) ; // mauvais nombre de paramètres
- CBotToken::DefineNum( "CBotErrUndefItem", 5031) ; // élément n'existe pas dans la classe
- CBotToken::DefineNum( "CBotErrUndefClass", 5032) ; // variable n'est pas une classe
- CBotToken::DefineNum( "CBotErrNoConstruct", 5033) ; // pas de constructeur approprié
- CBotToken::DefineNum( "CBotErrRedefClass", 5034) ; // classe existe déjà
- CBotToken::DefineNum( "CBotErrCloseIndex", 5035) ; // " ] " attendu
- CBotToken::DefineNum( "CBotErrReserved", 5036) ; // mot réservé (par un DefineNum)
-
-// voici la liste des erreurs pouvant être retournées par le module
-// pour l'exécution
-
- CBotToken::DefineNum( "CBotErrZeroDiv", 6000) ; // division par zéro
- CBotToken::DefineNum( "CBotErrNotInit", 6001) ; // variable non initialisée
- CBotToken::DefineNum( "CBotErrBadThrow", 6002) ; // throw d'une valeur négative
- CBotToken::DefineNum( "CBotErrNoRetVal", 6003) ; // fonction n'a pas retourné de résultat
- CBotToken::DefineNum( "CBotErrNoRun", 6004) ; // Run() sans fonction active
- CBotToken::DefineNum( "CBotErrUndefFunc", 6005) ; // appel d'une fonction qui n'existe plus
-
- CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf );
-
- InitStringFunctions();
-
- // une fonction juste pour les debug divers
- CBotProgram::AddFunction("CBOTDEBUGDD", rCBotDebug, cCBotDebug);
- //TODO implement this deletion
- // DeleteFile("CbotDebug.txt");
-
-}
-
-void CBotProgram::Free()
-{
- CBotToken::Free() ;
- CBotCall ::Free() ;
- CBotClass::Free() ;
-}
-
+// * 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/. + +////////////////////////////////////////////////////////////////////// +// database management of CBoT program + +#include "CBot.h" +#include <stdio.h> + +CBotProgram::CBotProgram() +{ + m_Prog = NULL; + m_pRun = NULL; + m_pClass = NULL; + m_pStack = NULL; + m_pInstance = NULL; + + m_ErrorCode = 0; + m_Ident = 0; + m_bDebugDD = 0; +} + +CBotProgram::CBotProgram(CBotVar* pInstance) +{ + m_Prog = NULL; + m_pRun = NULL; + m_pClass = NULL; + m_pStack = NULL; + m_pInstance = pInstance; + + m_ErrorCode = 0; + m_Ident = 0; + m_bDebugDD = 0; +} + + +CBotProgram::~CBotProgram() +{ +// delete m_pClass; + m_pClass->Purge(); + m_pClass = NULL; + + CBotClass::FreeLock(this); + + delete m_Prog; +#if STACKMEM + m_pStack->Delete(); +#else + delete m_pStack; +#endif +} + + +bool CBotProgram::Compile( const char* program, CBotStringArray& ListFonctions, void* pUser ) +{ + int error = 0; + Stop(); + +// delete m_pClass; + m_pClass->Purge(); // purge the old definitions of classes + // but without destroying the object + m_pClass = NULL; + delete m_Prog; m_Prog= NULL; + + ListFonctions.SetSize(0); + m_ErrorCode = 0; + + if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL) + pUser = m_pInstance->m_pUserPtr; + + // transforms the program in Tokens + CBotToken* pBaseToken = CBotToken::CompileTokens(program, error); + if ( pBaseToken == NULL ) return false; + + + CBotCStack* pStack = new CBotCStack(NULL); + CBotToken* p = pBaseToken->GivNext(); // skips the first token (separator) + + pStack->SetBotCall(this); // defined used routines + CBotCall::SetPUser(pUser); + + // first made a quick pass just to take the headers of routines and classes + while ( pStack->IsOk() && p != NULL && p->GivType() != 0) + { + if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking + + if ( p->GivType() == ID_CLASS || + ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS )) + { + CBotClass* nxt = CBotClass::Compile1(p, pStack); + if (m_pClass == NULL ) m_pClass = nxt; + else m_pClass->AddNext(nxt); + } + else + { + CBotFunction* next = CBotFunction::Compile1(p, pStack, NULL); + if (m_Prog == NULL ) m_Prog = next; + else m_Prog->AddNext(next); + } + } + if ( !pStack->IsOk() ) + { + m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd); + delete m_Prog; + m_Prog = NULL; + delete pBaseToken; + return false; + } + +// CBotFunction* temp = NULL; + CBotFunction* next = m_Prog; // rewind the list + + p = pBaseToken->GivNext(); // returns to the beginning + + while ( pStack->IsOk() && p != NULL && p->GivType() != 0 ) + { + if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking + + if ( p->GivType() == ID_CLASS || + ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS )) + { + m_bCompileClass = true; + CBotClass::Compile(p, pStack); // completes the definition of the class + } + else + { + m_bCompileClass = false; + CBotFunction::Compile(p, pStack, next); + if (next->IsExtern()) ListFonctions.Add(next->GivName()/* + next->GivParams()*/); + next->m_pProg = this; // keeps pointers to the module + next = next->Next(); + } + } + +// delete m_Prog; // the list of first pass +// m_Prog = temp; // list of the second pass + + if ( !pStack->IsOk() ) + { + m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd); + delete m_Prog; + m_Prog = NULL; + } + + delete pBaseToken; + delete pStack; + + return (m_Prog != NULL); +} + + +bool CBotProgram::Start(const char* name) +{ +#if STACKMEM + m_pStack->Delete(); +#else + delete m_pStack; +#endif + m_pStack = NULL; + + m_pRun = m_Prog; + while (m_pRun != NULL) + { + if ( m_pRun->GivName() == name ) break; + m_pRun = m_pRun->m_next; + } + + if ( m_pRun == NULL ) + { + m_ErrorCode = TX_NORUN; + return false; + } + +#if STACKMEM + m_pStack = CBotStack::FirstStack(); +#else + m_pStack = new CBotStack(NULL); // creates an execution stack +#endif + + m_pStack->SetBotCall(this); // bases for routines + + return true; // we are ready for Run () +} + +bool CBotProgram::GetPosition(const char* name, int& start, int& stop, CBotGet modestart, CBotGet modestop) +{ + CBotFunction* p = m_Prog; + while (p != NULL) + { + if ( p->GivName() == name ) break; + p = p->m_next; + } + + if ( p == NULL ) return false; + + p->GetPosition(start, stop, modestart, modestop); + return true; +} + +bool CBotProgram::Run(void* pUser, int timer) +{ + bool ok; + + if (m_pStack == NULL || m_pRun == NULL) goto error; + + m_ErrorCode = 0; + if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL) + pUser = m_pInstance->m_pUserPtr; + + m_pStack->Reset(pUser); // empty the possible previous error, and resets the timer + if ( timer >= 0 ) m_pStack->SetTimer(timer); + + m_pStack->SetBotCall(this); // bases for routines + +#if STACKRUN + // resumes execution on the top of the stack + ok = m_pStack->Execute(); + if ( ok ) + { +#ifdef _DEBUG + CBotVar* ppVar[3]; + ppVar[0] = CBotVar::Create("aa", CBotTypInt); + ppVar[1] = CBotVar::Create("bb", CBotTypInt); + ppVar[2] = NULL; + ok = m_pRun->Execute(ppVar, m_pStack, m_pInstance); +#else + // returns to normal execution + ok = m_pRun->Execute(NULL, m_pStack, m_pInstance); +#endif + } +#else + ok = m_pRun->Execute(NULL, m_pStack, m_pInstance); +#endif + + // completed on a mistake? + if (!ok && !m_pStack->IsOk()) + { + m_ErrorCode = m_pStack->GivError(m_ErrorStart, m_ErrorEnd); +#if STACKMEM + m_pStack->Delete(); +#else + delete m_pStack; +#endif + m_pStack = NULL; + return true; // execution is finished! + } + + if ( ok ) m_pRun = NULL; // more function in execution + return ok; + +error: + m_ErrorCode = TX_NORUN; + return true; +} + +void CBotProgram::Stop() +{ +#if STACKMEM + m_pStack->Delete(); +#else + delete m_pStack; +#endif + m_pStack = NULL; + m_pRun = NULL; +} + + + +bool CBotProgram::GetRunPos(const char* &FunctionName, int &start, int &end) +{ + FunctionName = NULL; + start = end = 0; + if (m_pStack == NULL) return false; + + m_pStack->GetRunPos(FunctionName, start, end); + return true; +} + +CBotVar* CBotProgram::GivStackVars(const char* &FunctionName, int level) +{ + FunctionName = NULL; + if (m_pStack == NULL) return NULL; + + return m_pStack->GivStackVars(FunctionName, level); +} + +void CBotProgram::SetTimer(int n) +{ + CBotStack::SetTimer( n ); +} + +int CBotProgram::GivError() +{ + return m_ErrorCode; +} + +void CBotProgram::SetIdent(long n) +{ + m_Ident = n; +} + +long CBotProgram::GivIdent() +{ + return m_Ident; +} + +bool CBotProgram::GetError(int& code, int& start, int& end) +{ + code = m_ErrorCode; + start = m_ErrorStart; + end = m_ErrorEnd; + return code > 0; +} + +bool CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg) +{ + code = m_ErrorCode; + start = m_ErrorStart; + end = m_ErrorEnd; + pProg = this; + return code > 0; +} + +CBotString CBotProgram::GivErrorText(int code) +{ + CBotString TextError; + + TextError.LoadString( code ); + if (TextError.IsEmpty()) + { + char buf[100]; + sprintf(buf, "Exception numéro %d.", code); + TextError = buf; + } + return TextError; +} + + +CBotFunction* CBotProgram::GivFunctions() +{ + return m_Prog; +} + +bool CBotProgram::AddFunction(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)) +{ + // stores pointers to the two functions + return CBotCall::AddFunction(name, rExec, rCompile); +} + + +bool WriteWord(FILE* pf, unsigned short w) +{ + size_t lg; + + lg = fwrite(&w, sizeof( unsigned short ), 1, pf ); + + return (lg == 1); +} + +bool ReadWord(FILE* pf, unsigned short& w) +{ + size_t lg; + + lg = fread(&w, sizeof( unsigned short ), 1, pf ); + + return (lg == 1); +} + +bool WriteFloat(FILE* pf, float w) +{ + size_t lg; + + lg = fwrite(&w, sizeof( float ), 1, pf ); + + return (lg == 1); +} + +bool ReadFloat(FILE* pf, float& w) +{ + size_t lg; + + lg = fread(&w, sizeof( float ), 1, pf ); + + return (lg == 1); +} + +bool WriteLong(FILE* pf, long w) +{ + size_t lg; + + lg = fwrite(&w, sizeof( long ), 1, pf ); + + return (lg == 1); +} + +bool ReadLong(FILE* pf, long& w) +{ + size_t lg; + + lg = fread(&w, sizeof( long ), 1, pf ); + + return (lg == 1); +} + +bool WriteString(FILE* pf, CBotString s) +{ + size_t lg1, lg2; + + lg1 = s.GivLength(); + if (!WriteWord(pf, lg1)) return false; + + lg2 = fwrite(s, 1, lg1, pf ); + return (lg1 == lg2); +} + +bool ReadString(FILE* pf, CBotString& s) +{ + unsigned short w; + char buf[1000]; + size_t lg1, lg2; + + if (!ReadWord(pf, w)) return false; + lg1 = w; + lg2 = fread(buf, 1, lg1, pf ); + buf[lg2] = 0; + + s = buf; + return (lg1 == lg2); +} + +bool WriteType(FILE* pf, CBotTypResult type) +{ + int typ = type.GivType(); + if ( typ == CBotTypIntrinsic ) typ = CBotTypClass; + if ( !WriteWord(pf, typ) ) return false; + if ( typ == CBotTypClass ) + { + CBotClass* p = type.GivClass(); + if ( !WriteString(pf, p->GivName()) ) return false; + } + if ( type.Eq( CBotTypArrayBody ) || + type.Eq( CBotTypArrayPointer ) ) + { + if ( !WriteWord(pf, type.GivLimite()) ) return false; + if ( !WriteType(pf, type.GivTypElem()) ) return false; + } + return true; +} + +bool ReadType(FILE* pf, CBotTypResult& type) +{ + unsigned short w, ww; + if ( !ReadWord(pf, w) ) return false; + type.SetType(w); + + if ( type.Eq( CBotTypIntrinsic ) ) + { + type = CBotTypResult( w, "point" ); + } + + if ( type.Eq( CBotTypClass ) ) + { + CBotString s; + if ( !ReadString(pf, s) ) return false; + type = CBotTypResult( w, s ); + } + + if ( type.Eq( CBotTypArrayPointer ) || + type.Eq( CBotTypArrayBody ) ) + { + CBotTypResult r; + if ( !ReadWord(pf, ww) ) return false; + if ( !ReadType(pf, r) ) return false; + type = CBotTypResult( w, r ); + type.SetLimite((short)ww); + } + return true; +} + + +bool CBotProgram::DefineNum(const char* name, long val) +{ + return CBotToken::DefineNum(name, val); +} + + +bool CBotProgram::SaveState(FILE* pf) +{ + if (!WriteWord( pf, CBOTVERSION)) return false; + + + if ( m_pStack != NULL ) + { + if (!WriteWord( pf, 1)) return false; + if (!WriteString( pf, m_pRun->GivName() )) return false; + if (!m_pStack->SaveState(pf)) return false; + } + else + { + if (!WriteWord( pf, 0)) return false; + } + return true; +} + + +bool CBotProgram::RestoreState(FILE* pf) +{ + unsigned short w; + CBotString s; + + Stop(); + + if (!ReadWord( pf, w )) return false; + if ( w != CBOTVERSION ) return false; + + if (!ReadWord( pf, w )) return false; + if ( w == 0 ) return true; + + if (!ReadString( pf, s )) return false; + Start(s); // point de reprise + +#if STACKMEM + m_pStack->Delete(); +#else + delete m_pStack; +#endif + m_pStack = NULL; + + // retrieves the stack from the memory + // uses a NULL pointer (m_pStack) but it's ok like that + if (!m_pStack->RestoreState(pf, m_pStack)) return false; + m_pStack->SetBotCall(this); // bases for routines + + // restored some states in the stack according to the structure + m_pRun->RestoreState(NULL, m_pStack, m_pInstance); + return true; +} + +int CBotProgram::GivVersion() +{ + return CBOTVERSION; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////// + +CBotCall* CBotCall::m_ListCalls = NULL; + +CBotCall::CBotCall(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)) +{ + m_name = name; + m_rExec = rExec; + m_rComp = rCompile; + m_next = NULL; + m_nFuncIdent = CBotVar::NextUniqNum(); +} + +CBotCall::~CBotCall() +{ + if (m_next) delete m_next; + m_next = NULL; +} + +void CBotCall::Free() +{ + delete CBotCall::m_ListCalls; +} + +bool CBotCall::AddFunction(const char* name, + bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), + CBotTypResult rCompile (CBotVar* &pVar, void* pUser)) +{ + CBotCall* p = m_ListCalls; + CBotCall* pp = NULL; + + if ( p != NULL ) while ( p->m_next != NULL ) + { + if ( p->GivName() == name ) + { + // frees redefined function + if ( pp ) pp->m_next = p->m_next; + else m_ListCalls = p->m_next; + pp = p; + p = p->m_next; + pp->m_next = NULL; // not to destroy the following list + delete pp; + continue; + } + pp = p; // previous pointer + p = p->m_next; + } + + pp = new CBotCall(name, rExec, rCompile); + + if (p) p->m_next = pp; + else m_ListCalls = pp; + + return true; +} + + +// transforms the array of pointers to variables +// in a chained list of variables +CBotVar* MakeListVars(CBotVar** ppVars, bool bSetVal=false) +{ + int i = 0; + CBotVar* pVar = NULL; + + while( true ) + { + ppVars[i]; + if ( ppVars[i] == NULL ) break; + + CBotVar* pp = CBotVar::Create(ppVars[i]); + if (bSetVal) pp->Copy(ppVars[i]); + else + if ( ppVars[i]->GivType() == CBotTypPointer ) + pp->SetClass( ppVars[i]->GivClass()); +// copy the pointer according to indirections + if (pVar == NULL) pVar = pp; + else pVar->AddNext(pp); + i++; + } + return pVar; +} + +// is acceptable by a call procedure name +// and given parameters + +CBotTypResult CBotCall::CompileCall(CBotToken* &p, CBotVar** ppVar, CBotCStack* pStack, long& nIdent) +{ + nIdent = 0; + CBotCall* pt = m_ListCalls; + CBotString name = p->GivString(); + + while ( pt != NULL ) + { + if ( pt->m_name == name ) + { + CBotVar* pVar = MakeListVars(ppVar); + CBotVar* pVar2 = pVar; + CBotTypResult r = pt->m_rComp(pVar2, m_pUser); + int ret = r.GivType(); + + // if a class is returned, it is actually a pointer + if ( ret == CBotTypClass ) r.SetType( ret = CBotTypPointer ); + + if ( ret > 20 ) + { + if (pVar2) pStack->SetError(ret, p /*pVar2->GivToken()*/ ); + } + delete pVar; + nIdent = pt->m_nFuncIdent; + return r; + } + pt = pt->m_next; + } + return -1; +} + +void* CBotCall::m_pUser = NULL; + +void CBotCall::SetPUser(void* pUser) +{ + m_pUser = pUser; +} + +bool CBotCall::CheckCall(const char* name) +{ + CBotCall* p = m_ListCalls; + + while ( p != NULL ) + { + if ( name == p->GivName() ) return true; + p = p->m_next; + } + return false; +} + + + +CBotString CBotCall::GivName() +{ + return m_name; +} + +CBotCall* CBotCall::Next() +{ + return m_next; +} + + +int CBotCall::DoCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack, CBotTypResult& rettype) +{ + CBotCall* pt = m_ListCalls; + + if ( nIdent ) while ( pt != NULL ) + { + if ( pt->m_nFuncIdent == nIdent ) + { + goto fund; + } + pt = pt->m_next; + } + + pt = m_ListCalls; + + if ( token != NULL ) + { + CBotString name = token->GivString(); + while ( pt != NULL ) + { + if ( pt->m_name == name ) + { + nIdent = pt->m_nFuncIdent; + goto fund; + } + pt = pt->m_next; + } + } + + return -1; + +fund: +#if !STACKRUN + // lists the parameters depending on the contents of the stack (pStackVar) + + CBotVar* pVar = MakeListVars(ppVar, true); + CBotVar* pVarToDelete = pVar; + + // creates a variable to the result + CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype); + + CBotVar* pRes = pResult; + int Exception = 0; + int res = pt->m_rExec(pVar, pResult, Exception, pStack->GivPUser()); + + if ( pResult != pRes ) delete pRes; // different result if made + delete pVarToDelete; + + if (res == false) + { + if (Exception!=0) + { + pStack->SetError(Exception, token); + } + delete pResult; + return false; + } + pStack->SetVar(pResult); + + if ( rettype.GivType() > 0 && pResult == NULL ) + { + pStack->SetError(TX_NORETVAL, token); + } + nIdent = pt->m_nFuncIdent; + return true; + +#else + + CBotStack* pile = pStack->AddStackEOX(pt); + if ( pile == EOX ) return true; + + // lists the parameters depending on the contents of the stack (pStackVar) + + CBotVar* pVar = MakeListVars(ppVar, true); + CBotVar* pVarToDelete = pVar; + + // creates a variable to the result + CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype); + + pile->SetVar( pVar ); + + CBotStack* pile2 = pile->AddStack(); + pile2->SetVar( pResult ); + + pile->SetError(0, token); // for the position on error + away + return pt->Run( pStack ); + +#endif + +} + +#if STACKRUN + +bool CBotCall::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack) +{ + CBotCall* pt = m_ListCalls; + + { + CBotString name = token->GivString(); + while ( pt != NULL ) + { + if ( pt->m_name == name ) + { + nIdent = pt->m_nFuncIdent; + + CBotStack* pile = pStack->RestoreStackEOX(pt); + if ( pile == NULL ) return true; + + CBotStack* pile2 = pile->RestoreStack(); + return true; + } + pt = pt->m_next; + } + } + + return false; +} + +bool CBotCall::Run(CBotStack* pStack) +{ + CBotStack* pile = pStack->AddStackEOX(this); + if ( pile == EOX ) return true; + CBotVar* pVar = pile->GivVar(); + + CBotStack* pile2 = pile->AddStack(); + CBotVar* pResult = pile2->GivVar(); + CBotVar* pRes = pResult; + + int Exception = 0; + int res = m_rExec(pVar, pResult, Exception, pStack->GivPUser()); + + if (res == false) + { + if (Exception!=0) + { + pStack->SetError(Exception); + } + if ( pResult != pRes ) delete pResult; // different result if made + return false; + } + + if ( pResult != NULL ) pStack->SetCopyVar( pResult ); + if ( pResult != pRes ) delete pResult; // different result if made + + return true; +} + +#endif + +/////////////////////////////////////////////////////////////////////////////////////// + +CBotCallMethode::CBotCallMethode(const char* name, + bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception), + CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar)) +{ + m_name = name; + m_rExec = rExec; + m_rComp = rCompile; + m_next = NULL; + m_nFuncIdent = CBotVar::NextUniqNum(); +} + +CBotCallMethode::~CBotCallMethode() +{ + delete m_next; + m_next = NULL; +} + +// is acceptable by a call procedure name +// and given parameters + +CBotTypResult CBotCallMethode::CompileCall(const char* name, CBotVar* pThis, + CBotVar** ppVar, CBotCStack* pStack, + long& nIdent) +{ + CBotCallMethode* pt = this; + nIdent = 0; + + while ( pt != NULL ) + { + if ( pt->m_name == name ) + { + CBotVar* pVar = MakeListVars(ppVar, true); + CBotVar* pVar2 = pVar; + CBotTypResult r = pt->m_rComp(pThis, pVar2); + int ret = r.GivType(); + if ( ret > 20 ) + { + if (pVar2) pStack->SetError(ret, pVar2->GivToken()); + } + delete pVar; + nIdent = pt->m_nFuncIdent; + return r; + } + pt = pt->m_next; + } + return CBotTypResult(-1); +} + + +CBotString CBotCallMethode::GivName() +{ + return m_name; +} + +CBotCallMethode* CBotCallMethode::Next() +{ + return m_next; +} + +void CBotCallMethode::AddNext(CBotCallMethode* pt) +{ + CBotCallMethode* p = this; + while ( p->m_next != NULL ) p = p->m_next; + + p->m_next = pt; +} + + +int CBotCallMethode::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pToken) +{ + CBotCallMethode* pt = this; + + // search by the identifier + + if ( nIdent ) while ( pt != NULL ) + { + if ( pt->m_nFuncIdent == nIdent ) + { + // lists the parameters depending on the contents of the stack (pStackVar) + + CBotVar* pVar = MakeListVars(ppVars, true); + CBotVar* pVarToDelete = pVar; + + // then calls the routine external to the module + + int Exception = 0; + int res = pt->m_rExec(pThis, pVar, pResult, Exception); + pStack->SetVar(pResult); + + if (res == false) + { + if (Exception!=0) + { +// pStack->SetError(Exception, pVar->GivToken()); + pStack->SetError(Exception, pToken); + } + delete pVarToDelete; + return false; + } + delete pVarToDelete; + return true; + } + pt = pt->m_next; + } + + // search by name + + while ( pt != NULL ) + { + if ( pt->m_name == name ) + { + // lists the parameters depending on the contents of the stack (pStackVar) + + CBotVar* pVar = MakeListVars(ppVars, true); + CBotVar* pVarToDelete = pVar; + + int Exception = 0; + int res = pt->m_rExec(pThis, pVar, pResult, Exception); + pStack->SetVar(pResult); + + if (res == false) + { + if (Exception!=0) + { +// pStack->SetError(Exception, pVar->GivToken()); + pStack->SetError(Exception, pToken); + } + delete pVarToDelete; + return false; + } + delete pVarToDelete; + nIdent = pt->m_nFuncIdent; + return true; + } + pt = pt->m_next; + } + + return -1; +} + +bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + if ( pVar == NULL ) return TX_LOWPARAM; + + int i = 0; + pVar = pVar->GivItemList(); + + while ( pVar != NULL ) + { + i++; + pVar = pVar->GivNext(); + } + + pResult->SetValInt(i); + return true; +} + +CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser ) +{ + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + if ( pVar->GivType() != CBotTypArrayPointer ) + return CBotTypResult( TX_BADPARAM ); + return CBotTypResult( CBotTypInt ); +} + + +CBotString CBotProgram::m_DebugVarStr = ""; + +bool rCBotDebug( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + pResult->SetValString( CBotProgram::m_DebugVarStr ); + + return true; +} + +CBotTypResult cCBotDebug( CBotVar* &pVar, void* pUser ) +{ + // no parameter + if ( pVar != NULL ) return CBotTypResult( TX_OVERPARAM ); + + // function returns a result "string" + return CBotTypResult( CBotTypString ); +} + + +#include "StringFunctions.cpp" + +void CBotProgram::Init() +{ + CBotToken::DefineNum( "CBotErrOpenPar", 5000) ; // missing the opening parenthesis + CBotToken::DefineNum( "CBotErrClosePar", 5001) ; // missing the closing parenthesis + CBotToken::DefineNum( "CBotErrNotBoolean", 5002) ; // expression must be a boolean + CBotToken::DefineNum( "CBotErrUndefVar", 5003) ; // undeclared variable + CBotToken::DefineNum( "CBotErrBadLeft", 5004) ; // impossible assignment (5 = ...) + CBotToken::DefineNum( "CBotErrNoTerminator", 5005) ;// semicolon expected + CBotToken::DefineNum( "CBotErrCaseOut", 5006) ; // case outside a switch + CBotToken::DefineNum( "CBotErrCloseBlock", 5008) ; // missing " } " + CBotToken::DefineNum( "CBotErrElseWhitoutIf", 5009) ;// else without matching if + CBotToken::DefineNum( "CBotErrOpenBlock", 5010) ; // missing " { " + CBotToken::DefineNum( "CBotErrBadType1", 5011) ; // wrong type for the assignment + CBotToken::DefineNum( "CBotErrRedefVar", 5012) ; // redefinition of the variable + CBotToken::DefineNum( "CBotErrBadType2", 5013) ; // two operands are incompatible + CBotToken::DefineNum( "CBotErrUndefCall", 5014) ; // routine unknown + CBotToken::DefineNum( "CBotErrNoDoubleDots", 5015) ;// " : " expected + CBotToken::DefineNum( "CBotErrBreakOutside", 5017) ;// break outside of a loop + CBotToken::DefineNum( "CBotErrUndefLabel", 5019) ; // unknown label + CBotToken::DefineNum( "CBotErrLabel", 5018) ; // label can not get here + CBotToken::DefineNum( "CBotErrNoCase", 5020) ; // missing " case " + CBotToken::DefineNum( "CBotErrBadNum", 5021) ; // expected number + CBotToken::DefineNum( "CBotErrVoid", 5022) ; // " void " not possble here + CBotToken::DefineNum( "CBotErrNoType", 5023) ; // type declaration expected + CBotToken::DefineNum( "CBotErrNoVar", 5024) ; // variable name expected + CBotToken::DefineNum( "CBotErrNoFunc", 5025) ; // expected function name + CBotToken::DefineNum( "CBotErrOverParam", 5026) ; // too many parameters + CBotToken::DefineNum( "CBotErrRedefFunc", 5027) ; // this function already exists + CBotToken::DefineNum( "CBotErrLowParam", 5028) ; // not enough parameters + CBotToken::DefineNum( "CBotErrBadParam", 5029) ; // mauvais types de paramètres + CBotToken::DefineNum( "CBotErrNbParam", 5030) ; // wrong number of parameters + CBotToken::DefineNum( "CBotErrUndefItem", 5031) ; // element does not exist in the class + CBotToken::DefineNum( "CBotErrUndefClass", 5032) ; // variable is not a class + CBotToken::DefineNum( "CBotErrNoConstruct", 5033) ; // no appropriate constructor + CBotToken::DefineNum( "CBotErrRedefClass", 5034) ; // Class already exists + CBotToken::DefineNum( "CBotErrCloseIndex", 5035) ; // " ] " expected + CBotToken::DefineNum( "CBotErrReserved", 5036) ; // reserved word (for a DefineNum) + +// Here are the list of errors that can be returned by the module +// for the execution + + CBotToken::DefineNum( "CBotErrZeroDiv", 6000) ; // division by zero + CBotToken::DefineNum( "CBotErrNotInit", 6001) ; // uninitialized variable + CBotToken::DefineNum( "CBotErrBadThrow", 6002) ; // throw a negative value + CBotToken::DefineNum( "CBotErrNoRetVal", 6003) ; // function did not return results + CBotToken::DefineNum( "CBotErrNoRun", 6004) ; // active Run () without a function + CBotToken::DefineNum( "CBotErrUndefFunc", 6005) ; // Calling a function that no longer exists + + CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf ); + + InitStringFunctions(); + + // just a function for various debug + CBotProgram::AddFunction("CBOTDEBUGDD", rCBotDebug, cCBotDebug); + //TODO implement this deletion + // DeleteFile("CbotDebug.txt"); + +} + +void CBotProgram::Free() +{ + CBotToken::Free() ; + CBotCall ::Free() ; + CBotClass::Free() ; +} + diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 419798f..ddb26c6 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -1,1471 +1,1471 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.//////////////////////////////////////////////////////////////////////
-
-//Management of the stack
-
-
-#include "CBot.h"
-#include <cstdlib>
-#include <cstring>
-
-
-#define ITIMER 100
-
-////////////////////////////////////////////////////////////////////////////
-// gestion de la pile d'exécution
-////////////////////////////////////////////////////////////////////////////
-
-int CBotStack::m_initimer = ITIMER;
-int CBotStack::m_timer = 0;
-CBotVar* CBotStack::m_retvar = NULL;
-int CBotStack::m_error = 0;
-int CBotStack::m_start = 0;
-int CBotStack::m_end = 0;
-CBotString CBotStack::m_labelBreak="";
-void* CBotStack::m_pUser = NULL;
-
-#if STACKMEM
-
-CBotStack* CBotStack::FirstStack()
-{
- CBotStack* p;
-
- long size = sizeof(CBotStack);
- size *= (MAXSTACK+10);
-
- // demande une tranche mémoire pour la pile
- p = (CBotStack*)malloc(size);
-
- // la vide totalement
- memset(p, 0, size);
-
- p-> m_bBlock = true;
- m_timer = m_initimer; // met le timer au début
-
- CBotStack* pp = p;
- pp += MAXSTACK;
- int i;
- for ( i = 0 ; i< 10 ; i++ )
- {
- pp->m_bOver = true;
- pp ++;
- }
-#ifdef _DEBUG
- int n = 1;
- pp = p;
- for ( i = 0 ; i< MAXSTACK+10 ; i++ )
- {
- pp->m_index = n++;
- pp ++;
- }
-#endif
-
- m_error = 0; // évite des blocages car m_error est static
- return p;
-}
-
-CBotStack::CBotStack(CBotStack* ppapa)
-{
- // constructor must exist or the destructor is never called!
- ASM_TRAP();
-}
-
-CBotStack::~CBotStack()
-{
- ASM_TRAP(); // utiliser Delete() à la place
-}
-
-void CBotStack::Delete()
-{
- if ( this == NULL || this == EOX ) return;
-
- m_next->Delete();
- m_next2->Delete();
-
- if (m_prev != NULL)
- {
- if ( m_prev->m_next == this )
- m_prev->m_next = NULL; // enlève de la chaîne
-
- if ( m_prev->m_next2 == this )
- m_prev->m_next2 = NULL; // enlève de la chaîne
- }
-
- delete m_var;
- delete m_listVar;
-
- CBotStack* p = m_prev;
- bool bOver = m_bOver;
-#ifdef _DEBUG
- int n = m_index;
-#endif
-
- // efface le bloc libéré
- memset(this, 0, sizeof(CBotStack));
- m_bOver = bOver;
-#ifdef _DEBUG
- m_index = n;
-#endif
-
- if ( p == NULL )
- free( this );
-}
-
-
-// routine optimisée
-CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- return m_next; // reprise dans une pile existante
- }
-
-#ifdef _DEBUG
- int n = 0;
-#endif
- CBotStack* p = this;
- do
- {
- p ++;
-#ifdef _DEBUG
- n ++;
-#endif
- }
- while ( p->m_prev != NULL );
-
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_instr = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- p->m_prev = this;
- p->m_state = 0;
- p->m_call = NULL;
- p->m_bFunc = false;
- return p;
-}
-
-CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- if ( m_next == EOX )
- {
- m_next = NULL;
- return EOX;
- }
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = AddStack(NULL, bBlock);
- p->m_call = instr;
- p->m_bFunc = 2; // spécial
- return p;
-}
-
-CBotStack* CBotStack::AddStack2(bool bBlock)
-{
- if (m_next2 != NULL)
- {
- m_next2->m_prog = m_prog; // spécial évite un RestoreStack2
- return m_next2; // reprise dans une pile existante
- }
-
- CBotStack* p = this;
- do
- {
- p ++;
- }
- while ( p->m_prev != NULL );
-
- m_next2 = p; // chaîne l'élément
- p->m_prev = this;
- p->m_bBlock = bBlock;
- p->m_prog = m_prog;
- p->m_step = 0;
- return p;
-}
-
-bool CBotStack::GivBlock()
-{
- return m_bBlock;
-}
-
-bool CBotStack::Return(CBotStack* pfils)
-{
- if ( pfils == this ) return true; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- m_next->Delete();m_next = NULL; // libère la pile au dessus
- m_next2->Delete();m_next2 = NULL; // aussi la seconde pile (catch)
-
- return (m_error == 0); // interrompu si erreur
-}
-
-bool CBotStack::ReturnKeep(CBotStack* pfils)
-{
- if ( pfils == this ) return true; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- return (m_error == 0); // interrompu si erreur
-}
-
-bool CBotStack::StackOver()
-{
- if (!m_bOver) return false;
- m_error = TX_STACKOVER;
- return true;
-}
-
-#else
-
-CBotStack::CBotStack(CBotStack* ppapa)
-{
- m_next = NULL;
- m_next2 = NULL;
- m_prev = ppapa;
-
- m_bBlock = (ppapa == NULL) ? true : false;
-
- m_state = 0;
- m_step = 1;
-
- if (ppapa == NULL) m_timer = m_initimer; // met le timer au début
-
- m_listVar = NULL;
- m_bDontDelete = false;
-
- m_var = NULL;
- m_prog = NULL;
- m_instr = NULL;
- m_call = NULL;
- m_bFunc = false;
-}
-
-// destructeur
-CBotStack::~CBotStack()
-{
- if ( m_next != EOX) delete m_next;
- delete m_next2;
- if (m_prev != NULL && m_prev->m_next == this )
- m_prev->m_next = NULL; // enlève de la chaîne
-
- delete m_var;
- if ( !m_bDontDelete ) delete m_listVar;
-}
-
-// routine à optimiser
-CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = new CBotStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_instr = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- return p;
-}
-
-CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
-{
- if (m_next != NULL)
- {
- if ( m_next == EOX )
- {
- m_next = NULL;
- return EOX;
- }
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = new CBotStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_call = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- p->m_bFunc = 2; // spécial
- return p;
-}
-
-CBotStack* CBotStack::AddStack2(bool bBlock)
-{
- if (m_next2 != NULL)
- {
- m_next2->m_prog = m_prog; // spécial évite un RestoreStack2
- return m_next2; // reprise dans une pile existante
- }
-
- CBotStack* p = new CBotStack(this);
- m_next2 = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_prog = m_prog;
- p->m_step = 0;
-
- return p;
-}
-
-bool CBotStack::Return(CBotStack* pfils)
-{
- if ( pfils == this ) return true; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruite la variable
-
- if ( m_next != EOX ) delete m_next; // libère la pile au dessus
- delete m_next2;m_next2 = NULL; // aussi la seconde pile (catch)
-
- return (m_error == 0); // interrompu si erreur
-}
-
-bool CBotStack::StackOver()
-{
- return false; // pas de test de débordement dans cette version
-}
-
-#endif
-
-void CBotStack::Reset(void* pUser)
-{
- m_timer = m_initimer; // remet le timer
- m_error = 0;
-// m_start = 0;
-// m_end = 0;
- m_labelBreak.Empty();
- m_pUser = pUser;
-}
-
-
-
-
-CBotStack* CBotStack::RestoreStack(CBotInstr* instr)
-{
- if (m_next != NULL)
- {
- m_next->m_instr = instr; // réinit (si reprise après restitution)
- m_next->m_prog = m_prog;
- return m_next; // reprise dans une pile existante
- }
- return NULL;
-}
-
-CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr)
-{
- CBotStack* p = RestoreStack();
- p->m_call = instr;
- return p;
-}
-
-
-
-// routine pour l'exécution pas à pas
-bool CBotStack::IfStep()
-{
- if ( m_initimer > 0 || m_step++ > 0 ) return false;
- return true;
-}
-
-
-bool CBotStack::BreakReturn(CBotStack* pfils, const char* name)
-{
- if ( m_error>=0 ) return false; // sortie normale
- if ( m_error==-3 ) return false; // sortie normale (return en cours)
-
- if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name))
- return false; // c'est pas pour moi
-
- m_error = 0;
- m_labelBreak.Empty();
- return Return(pfils);
-}
-
-bool CBotStack::IfContinue(int state, const char* name)
-{
- if ( m_error != -2 ) return false;
-
- if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name))
- return false; // c'est pas pour moi
-
- m_state = state; // où reprendre ?
- m_error = 0;
- m_labelBreak.Empty();
- if ( m_next != EOX ) m_next->Delete(); // purge la pile au dessus
- return true;
-}
-
-void CBotStack::SetBreak(int val, const char* name)
-{
- m_error = -val; // réagit comme une Exception
- m_labelBreak = name;
- if (val == 3) // pour un return
- {
- m_retvar = m_var;
- m_var = NULL;
- }
-}
-
-// remet sur la pile la valeur calculée par le dernier CBotReturn
-
-bool CBotStack::GivRetVar(bool bRet)
-{
- if (m_error == -3)
- {
- if ( m_var ) delete m_var;
- m_var = m_retvar;
- m_retvar = NULL;
- m_error = 0;
- return true;
- }
- return bRet; // interrompu par autre chose que return
-}
-
-int CBotStack::GivError(int& start, int& end)
-{
- start = m_start;
- end = m_end;
- return m_error;
-}
-
-
-int CBotStack::GivType(int mode)
-{
- if (m_var == NULL) return -1;
- return m_var->GivType(mode);
-}
-
-CBotTypResult CBotStack::GivTypResult(int mode)
-{
- if (m_var == NULL) return -1;
- return m_var->GivTypResult(mode);
-}
-
-void CBotStack::SetType(CBotTypResult& type)
-{
- if (m_var == NULL) return;
- m_var->SetType( type );
-}
-
-
-CBotVar* CBotStack::FindVar(CBotToken* &pToken, bool bUpdate, bool bModif)
-{
- CBotStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivName() == name)
- {
- if ( bUpdate )
- pp->Maj(m_pUser, false);
-
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotStack::FindVar(const char* name)
-{
- CBotStack* p = this;
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivName() == name)
- {
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotStack::FindVar(long ident, bool bUpdate, bool bModif)
-{
- CBotStack* p = this;
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivUniqNum() == ident)
- {
- if ( bUpdate )
- pp->Maj(m_pUser, false);
-
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-
-CBotVar* CBotStack::FindVar(CBotToken& Token, bool bUpdate, bool bModif)
-{
- CBotToken* pt = &Token;
- return FindVar(pt, bUpdate, bModif);
-}
-
-
-CBotVar* CBotStack::CopyVar(CBotToken& Token, bool bUpdate)
-{
- CBotVar* pVar = FindVar( Token, bUpdate );
-
- if ( pVar == NULL) return NULL;
-
- CBotVar* pCopy = CBotVar::Create(pVar);
- pCopy->Copy(pVar);
- return pCopy;
-}
-
-
-bool CBotStack::SetState(int n, int limite)
-{
- m_state = n;
-
- m_timer--; // décompte les opérations
- return ( m_timer > limite ); // interrompu si timer passé
-}
-
-bool CBotStack::IncState(int limite)
-{
- m_state++;
-
- m_timer--; // décompte les opérations
- return ( m_timer > limite ); // interrompu si timer passé
-}
-
-
-void CBotStack::SetError(int n, CBotToken* token)
-{
- if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante
- m_error = n;
- if (token != NULL)
- {
- m_start = token->GivStart();
- m_end = token->GivEnd();
- }
-}
-
-void CBotStack::ResetError(int n, int start, int end)
-{
- m_error = n;
- m_start = start;
- m_end = end;
-}
-
-void CBotStack::SetPosError(CBotToken* token)
-{
- m_start = token->GivStart();
- m_end = token->GivEnd();
-}
-
-void CBotStack::SetTimer(int n)
-{
- m_initimer = n;
-}
-
-bool CBotStack::Execute()
-{
- CBotCall* instr = NULL; // instruction la plus élevée
- CBotStack* pile;
-
- CBotStack* p = this;
-
- while (p != NULL)
- {
- if ( p->m_next2 != NULL ) break;
- if ( p->m_call != NULL )
- {
- instr = p->m_call;
- pile = p->m_prev ;
- }
- p = p->m_next;
- }
-
- if ( instr == NULL ) return true; // exécution normale demandée
-
- if (!instr->Run(pile)) return false; // exécution à partir de là
-
-#if STACKMEM
- pile->m_next->Delete();
-#else
- delete pile->m_next;
-#endif
-
- pile->m_next = EOX; // spécial pour reprise
- return true;
-}
-
-// met sur le stack le pointeur à une variable
-void CBotStack::SetVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
- m_var = var;
-}
-
-// met sur le stack une copie d'une variable
-void CBotStack::SetCopyVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
-
- m_var = CBotVar::Create("", var->GivTypResult(2));
- m_var->Copy( var );
-}
-
-CBotVar* CBotStack::GivVar()
-{
- return m_var;
-}
-
-CBotVar* CBotStack::GivPtVar()
-{
- CBotVar* p = m_var;
- m_var = NULL; // ne sera pas détruit donc
- return p;
-}
-
-CBotVar* CBotStack::GivCopyVar()
-{
- if (m_var == NULL) return NULL;
- CBotVar* v = CBotVar::Create("", m_var->GivType());
- v->Copy( m_var );
- return v;
-}
-
-long CBotStack::GivVal()
-{
- if (m_var == NULL) return 0;
- return m_var->GivValInt();
-}
-
-
-
-
-void CBotStack::AddVar(CBotVar* pVar)
-{
- CBotStack* p = this;
-
- // revient sur l'élement père
- while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
-
- if ( p == NULL ) return;
-
-/// p->m_bDontDelete = bDontDelete;
-
- CBotVar** pp = &p->m_listVar;
- while ( *pp != NULL ) pp = &(*pp)->m_next;
-
- *pp = pVar; // ajoute à la suite
-
-#ifdef _DEBUG
- if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
-#endif
-}
-
-/*void CBotStack::RestoreVar(CBotVar* pVar)
-{
- if ( !m_bDontDelete ) __asm int 3;
- delete m_listVar;
- m_listVar = pVar; // remplace directement
-}*/
-
-void CBotStack::SetBotCall(CBotProgram* p)
-{
- m_prog = p;
- m_bFunc = true;
-}
-
-CBotProgram* CBotStack::GivBotCall(bool bFirst)
-{
- if ( ! bFirst ) return m_prog;
- CBotStack* p = this;
- while ( p->m_prev != NULL ) p = p->m_prev;
- return p->m_prog;
-}
-
-void* CBotStack::GivPUser()
-{
- return m_pUser;
-}
-
-
-bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype)
-{
- CBotTypResult res;
-
- // cherche d'abord selon l'identificateur
-
- res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype );
- if (res.GivType() >= 0) return res.GivType();
-
- res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token );
- if (res.GivType() >= 0) return res.GivType();
-
- // si pas trouvé (recompilé ?) cherche selon le nom
-
- nIdent = 0;
- res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype );
- if (res.GivType() >= 0) return res.GivType();
-
- res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token );
- if (res.GivType() >= 0) return res.GivType();
-
- SetError(TX_NOCALL, token);
- return true;
-}
-
-void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
-{
- if ( m_next == NULL ) return;
-
- if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) )
- m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this );
-}
-
-
-bool SaveVar(FILE* pf, CBotVar* pVar)
-{
- while ( true )
- {
- if ( pVar == NULL )
- {
- return WriteWord(pf, 0); // met un terminateur
- }
-
- if ( !pVar->Save0State(pf)) return false; // entête commune
- if ( !pVar->Save1State(pf) ) return false; // sauve selon la classe fille
-
- pVar = pVar->GivNext();
- }
-}
-
-void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end)
-{
- CBotProgram* prog = m_prog; // programme courrant
-
- CBotInstr* funct = NULL; // fonction trouvée
- CBotInstr* instr = NULL; // instruction la plus élevée
-
- CBotStack* p = this;
-
- while (p->m_next != NULL)
- {
- if ( p->m_instr != NULL ) instr = p->m_instr;
- if ( p->m_bFunc == 1 ) funct = p->m_instr;
- if ( p->m_next->m_prog != prog ) break ;
-
- if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
- else p = p->m_next;
- }
-
- if ( p->m_instr != NULL ) instr = p->m_instr;
- if ( p->m_bFunc == 1 ) funct = p->m_instr;
-
- if ( funct == NULL ) return;
-
- CBotToken* t = funct->GivToken();
- FunctionName = t->GivString();
-
-// if ( p->m_instr != NULL ) instr = p->m_instr;
-
- t = instr->GivToken();
- start = t->GivStart();
- end = t->GivEnd();
-}
-
-CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level)
-{
- CBotProgram* prog = m_prog; // programme courrant
- FunctionName = NULL;
-
- // remonte la pile dans le module courant
- CBotStack* p = this;
-
- while (p->m_next != NULL)
- {
- if ( p->m_next->m_prog != prog ) break ;
-
- if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
- else p = p->m_next;
- }
-
-
- // descend sur les éléments de block
- while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
-
- while ( p != NULL && level++ < 0 )
- {
- p = p->m_prev;
- while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
- }
-
- if ( p == NULL ) return NULL;
-
- // recherche le nom de la fonction courante
- CBotStack* pp = p;
- while ( pp != NULL )
- {
- if ( pp->m_bFunc == 1 ) break;
- pp = pp->m_prev;
- }
-
- if ( pp == NULL || pp->m_instr == NULL ) return NULL;
-
- CBotToken* t = pp->m_instr->GivToken();
- FunctionName = t->GivString();
-
- return p->m_listVar;
-}
-
-bool CBotStack::SaveState(FILE* pf)
-{
- if ( this == NULL ) // fin de l'arbre ?
- {
- return WriteWord(pf, 0); // met un terminateur
- }
-
- if ( m_next2 != NULL )
- {
- if (!WriteWord(pf, 2)) return false; // une marque de poursuite
- if (!m_next2->SaveState(pf)) return false;
- }
- else
- {
- if (!WriteWord(pf, 1)) return false; // une marque de poursuite
- }
- if (!WriteWord(pf, m_bBlock)) return false; // est-ce un bloc local
- if (!WriteWord(pf, m_state)) return false; // dans quel état
- if (!WriteWord(pf, 0)) return false; // par compatibilité m_bDontDelete
- if (!WriteWord(pf, m_step)) return false; // dans quel état
-
-
- if (!SaveVar(pf, m_var)) return false; // le résultat courant
- if (!SaveVar(pf, m_listVar)) return false; // les variables locales
-
- return m_next->SaveState(pf); // enregistre la suite
-}
-
-
-bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
-{
- unsigned short w;
-
- pStack = NULL;
- if (!ReadWord(pf, w)) return false;
- if ( w == 0 ) return true;
-
-#if STACKMEM
- if ( this == NULL ) pStack = FirstStack();
- else pStack = AddStack();
-#else
- pStack = new CBotStack(this);
-#endif
-
- if ( w == 2 )
- {
- if (!pStack->RestoreState(pf, pStack->m_next2)) return false;
- }
-
- if (!ReadWord(pf, w)) return false; // est-ce un bloc local
- pStack->m_bBlock = w;
-
- if (!ReadWord(pf, w)) return false; // dans quel état j'ère ?
- pStack->SetState((short)w); // dans le bon état
-
- if (!ReadWord(pf, w)) return false; // dont delete ?
- // plus utilisé
-
- if (!ReadWord(pf, w)) return false; // pas à pas
- pStack->m_step = w;
-
- if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // la variable temp
- if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// les variables locales
-
- return pStack->RestoreState(pf, pStack->m_next);
-}
-
-
-bool CBotVar::Save0State(FILE* pf)
-{
- if (!WriteWord(pf, 100+m_mPrivate))return false; // variable privée ?
- if (!WriteWord(pf, m_bStatic))return false; // variable static ?
- if (!WriteWord(pf, m_type.GivType()))return false; // enregiste le type (toujours non nul)
- if (!WriteWord(pf, m_binit))return false; // variable définie ?
- return WriteString(pf, m_token->GivString()); // et le nom de la variable
-}
-
-bool CBotVarInt::Save0State(FILE* pf)
-{
- if ( !m_defnum.IsEmpty() )
- {
- if(!WriteWord(pf, 200 )) return false; // marqueur spécial
- if(!WriteString(pf, m_defnum)) return false; // nom de la valeur
- }
-
- return CBotVar::Save0State(pf);
-}
-
-bool CBotVarInt::Save1State(FILE* pf)
-{
- return WriteWord(pf, m_val); // la valeur de la variable
-}
-
-bool CBotVarBoolean::Save1State(FILE* pf)
-{
- return WriteWord(pf, m_val); // la valeur de la variable
-}
-
-bool CBotVarFloat::Save1State(FILE* pf)
-{
- return WriteFloat(pf, m_val); // la valeur de la variable
-}
-
-bool CBotVarString::Save1State(FILE* pf)
-{
- return WriteString(pf, m_val); // la valeur de la variable
-}
-
-
-
-bool CBotVarClass::Save1State(FILE* pf)
-{
- if ( !WriteType(pf, m_type) ) return false;
- if ( !WriteLong(pf, m_ItemIdent) ) return false;
-
- return SaveVar(pf, m_pVar); // contenu de l'objet
-}
-
-bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
-{
- unsigned short w, wi, prv, st;
- float ww;
- CBotString name, s;
-
- delete pVar;
-
- pVar = NULL;
- CBotVar* pNew = NULL;
- CBotVar* pPrev = NULL;
-
- while ( true ) // recupère toute une liste
- {
- if (!ReadWord(pf, w)) return false; // privé ou type ?
- if ( w == 0 ) return true;
-
- CBotString defnum;
- if ( w == 200 )
- {
- if (!ReadString(pf, defnum)) return false; // nombre avec un identifiant
- if (!ReadWord(pf, w)) return false; // type
- }
-
- prv = 100; st = 0;
- if ( w >= 100 )
- {
- prv = w;
- if (!ReadWord(pf, st)) return false; // statique
- if (!ReadWord(pf, w)) return false; // type
- }
-
- if ( w == CBotTypClass ) w = CBotTypIntrinsic; // forcément intrinsèque
-
- if (!ReadWord(pf, wi)) return false; // init ?
-
- if (!ReadString(pf, name)) return false; // nom de la variable
-
- CBotToken token(name, CBotString());
-
- switch (w)
- {
- case CBotTypInt:
- case CBotTypBoolean:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadWord(pf, w)) return false;
- pNew->SetValInt((short)w, defnum);
- break;
- case CBotTypFloat:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadFloat(pf, ww)) return false;
- pNew->SetValFloat(ww);
- break;
- case CBotTypString:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadString(pf, s)) return false;
- pNew->SetValString(s);
- break;
-
- // restitue un objet intrinsic ou un élément d'un array
- case CBotTypIntrinsic:
- case CBotTypArrayBody:
- {
- CBotTypResult r;
- long id;
- if (!ReadType(pf, r)) return false; // type complet
- if (!ReadLong(pf, id) ) return false;
-
-// if (!ReadString(pf, s)) return false;
- {
- CBotVar* p = NULL;
- if ( id ) p = CBotVarClass::Find(id) ;
-
- pNew = new CBotVarClass(&token, r); // crée directement une instance
- // attention cptuse = 0
- if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return false;
- pNew->SetIdent(id);
-
- if ( p != NULL )
- {
- delete pNew;
- pNew = p; // reprend l'élément connu
- }
- }
- }
- break;
-
- case CBotTypPointer:
- case CBotTypNullPointer:
- if (!ReadString(pf, s)) return false;
- {
- pNew = CBotVar::Create(&token, CBotTypResult(w, s));// crée une variable
- CBotVarClass* p = NULL;
- long id;
- ReadLong(pf, id);
-// if ( id ) p = CBotVarClass::Find(id); // retrouve l'instance ( fait par RestoreInstance )
-
- // restitue une copie de l'instance d'origine
- CBotVar* pInstance = NULL;
- if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
- ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus
-
-// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // plutôt celui-ci !
-
- }
- break;
-
- case CBotTypArrayPointer:
- {
- CBotTypResult r;
- if (!ReadType(pf, r)) return false;
-
- pNew = CBotVar::Create(&token, r); // crée une variable
-
- // restitue une copie de l'instance d'origine
- CBotVar* pInstance = NULL;
- if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
- ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus
- }
- break;
- default:
- ASM_TRAP();
- }
-
- if ( pPrev != NULL ) pPrev->m_next = pNew;
- if ( pVar == NULL ) pVar = pNew;
-
- pNew->m_binit = wi; // pNew->SetInit(wi);
- pNew->SetStatic(st);
- pNew->SetPrivate(prv-100);
- pPrev = pNew;
- }
- return true;
-}
-
-
-
-
-////////////////////////////////////////////////////////////////////////////
-// gestion de la pile à la compilation
-////////////////////////////////////////////////////////////////////////////
-
-CBotProgram* CBotCStack::m_prog = NULL; // init la variable statique
-int CBotCStack::m_error = 0;
-int CBotCStack::m_end = 0;
-CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0);
-//CBotToken* CBotCStack::m_retClass= NULL;
-
-
-CBotCStack::CBotCStack(CBotCStack* ppapa)
-{
- m_next = NULL;
- m_prev = ppapa;
-
- if (ppapa == NULL)
- {
- m_error = 0;
- m_start = 0;
- m_end = 0;
- m_bBlock = true;
- }
- else
- {
- m_start = ppapa->m_start;
- m_bBlock = false;
- }
-
- m_listVar = NULL;
- m_var = NULL;
-}
-
-// destructeur
-CBotCStack::~CBotCStack()
-{
- if (m_next != NULL) delete m_next;
- if (m_prev != NULL) m_prev->m_next = NULL; // enlève de la chaîne
-
- delete m_var;
- delete m_listVar;
-}
-
-// utilisé uniquement à la compilation
-CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock)
-{
- if (m_next != NULL) return m_next; // reprise dans une pile existante
-
- CBotCStack* p = new CBotCStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
-
- if (pToken != NULL) p->SetStartError(pToken->GivStart());
-
- return p;
-}
-
-
-CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils)
-{
- if ( pfils == this ) return inst;
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- if (m_error)
- {
- m_start = pfils->m_start; // récupère la position de l'erreur
- m_end = pfils->m_end;
- }
-
- delete pfils;
- return inst;
-}
-
-CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils)
-{
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- if (m_error)
- {
- m_start = pfils->m_start; // récupère la position de l'erreur
- m_end = pfils->m_end;
- }
-
- delete pfils;
- return inst;
-}
-
-int CBotCStack::GivError(int& start, int& end)
-{
- start = m_start;
- end = m_end;
- return m_error;
-}
-
-int CBotCStack::GivError()
-{
- return m_error;
-}
-
-// type d'instruction sur la pile
-CBotTypResult CBotCStack::GivTypResult(int mode)
-{
- if (m_var == NULL)
- return CBotTypResult(99);
- return m_var->GivTypResult(mode);
-}
-
-// type d'instruction sur la pile
-int CBotCStack::GivType(int mode)
-{
- if (m_var == NULL)
- return 99;
- return m_var->GivType(mode);
-}
-
-// pointeur sur la pile est de quelle classe ?
-CBotClass* CBotCStack::GivClass()
-{
- if ( m_var == NULL )
- return NULL;
- if ( m_var->GivType(1) != CBotTypPointer ) return NULL;
-
- return m_var->GivClass();
-}
-
-// type d'instruction sur la pile
-void CBotCStack::SetType(CBotTypResult& type)
-{
- if (m_var == NULL) return;
- m_var->SetType( type );
-}
-
-// cherche une variable sur la pile
-// le token peut être une suite de TokenTypVar (objet d'une classe)
-// ou un pointeur dans le source
-
-CBotVar* CBotCStack::FindVar(CBotToken* &pToken)
-{
- CBotCStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (name == pp->GivName())
- {
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotCStack::FindVar(CBotToken& Token)
-{
- CBotToken* pt = &Token;
- return FindVar(pt);
-}
-
-CBotVar* CBotCStack::CopyVar(CBotToken& Token)
-{
- CBotVar* pVar = FindVar( Token );
-
- if ( pVar == NULL) return NULL;
-
- CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() );
- pCopy->Copy(pVar);
- return pCopy;
-}
-
-bool CBotCStack::IsOk()
-{
- return (m_error == 0);
-}
-
-
-void CBotCStack::SetStartError( int pos )
-{
- if ( m_error != 0) return; // ne change pas une erreur déjà existante
- m_start = pos;
-}
-
-void CBotCStack::SetError(int n, int pos)
-{
- if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante
- m_error = n;
- m_end = pos;
-}
-
-void CBotCStack::SetError(int n, CBotToken* p)
-{
- if (m_error) return; // ne change pas une erreur déjà existante
- m_error = n;
- m_start = p->GivStart();
- m_end = p->GivEnd();
-}
-
-void CBotCStack::ResetError(int n, int start, int end)
-{
- m_error = n;
- m_start = start;
- m_end = end;
-}
-
-bool CBotCStack::NextToken(CBotToken* &p)
-{
- CBotToken* pp = p;
-
- p = p->GivNext();
- if (p!=NULL) return true;
-
- SetError(TX_ENDOF, pp->GivEnd());
- return false;
-}
-
-void CBotCStack::SetBotCall(CBotProgram* p)
-{
- m_prog = p;
-}
-
-CBotProgram* CBotCStack::GivBotCall()
-{
- return m_prog;
-}
-
-void CBotCStack::SetRetType(CBotTypResult& type)
-{
- m_retTyp = type;
-}
-
-CBotTypResult CBotCStack::GivRetType()
-{
- return m_retTyp;
-}
-
-void CBotCStack::SetVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
- m_var = var;
-}
-
-// met sur le stack une copie d'une variable
-void CBotCStack::SetCopyVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
-
- if ( var == NULL ) return;
- m_var = CBotVar::Create("", var->GivTypResult(2));
- m_var->Copy( var );
-}
-
-CBotVar* CBotCStack::GivVar()
-{
- return m_var;
-}
-
-void CBotCStack::AddVar(CBotVar* pVar)
-{
- CBotCStack* p = this;
-
- // revient sur l'élement père
- while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
-
- if ( p == NULL ) return;
-
- CBotVar** pp = &p->m_listVar;
- while ( *pp != NULL ) pp = &(*pp)->m_next;
-
- *pp = pVar; // ajoute à la suite
-
-#ifdef _DEBUG
- if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
-#endif
-}
-
-// test si une variable est déjà définie localement
-
-bool CBotCStack::CheckVarLocal(CBotToken* &pToken)
-{
- CBotCStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (name == pp->GivName())
- return true;
- pp = pp->m_next;
- }
- if ( p->m_bBlock ) return false;
- p = p->m_prev;
- }
- return false;
-}
-
-CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent)
-{
- nIdent = 0;
- CBotTypResult val(-1);
-
- val = CBotCall::CompileCall(p, ppVars, this, nIdent);
- if (val.GivType() < 0)
- {
- val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent);
- if ( val.GivType() < 0 )
- {
- // pVar = NULL; // l'erreur n'est pas sur un paramètre en particulier
- SetError( -val.GivType(), p );
- val.SetType(-val.GivType());
- return val;
- }
- }
- return val;
-}
-
-// test si un nom de procédure est déjà défini quelque part
-
-bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
-{
- CBotString name = pToken->GivString();
-
- if ( CBotCall::CheckCall(name) ) return true;
-
- CBotFunction* pp = m_prog->GivFunctions();
- while ( pp != NULL )
- {
- if ( pToken->GivString() == pp->GivName() )
- {
- // les paramètres sont-ils exactement les mêmes ?
- if ( pp->CheckParam( pParam ) )
- return true;
- }
- pp = pp->Next();
- }
-
- pp = CBotFunction::m_listPublic;
- while ( pp != NULL )
- {
- if ( pToken->GivString() == pp->GivName() )
- {
- // les paramètres sont-ils exactement les mêmes ?
- if ( pp->CheckParam( pParam ) )
- return true;
- }
- pp = pp->m_nextpublic;
- }
-
- return false;
-}
-
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//Management of the stack + + +#include "CBot.h" +#include <cstdlib> +#include <cstring> + + +#define ITIMER 100 + +//////////////////////////////////////////////////////////////////////////// +// management of a execution of a stack +//////////////////////////////////////////////////////////////////////////// + +int CBotStack::m_initimer = ITIMER; +int CBotStack::m_timer = 0; +CBotVar* CBotStack::m_retvar = NULL; +int CBotStack::m_error = 0; +int CBotStack::m_start = 0; +int CBotStack::m_end = 0; +CBotString CBotStack::m_labelBreak=""; +void* CBotStack::m_pUser = NULL; + +#if STACKMEM + +CBotStack* CBotStack::FirstStack() +{ + CBotStack* p; + + long size = sizeof(CBotStack); + size *= (MAXSTACK+10); + + // request a slice of memory for the stack + p = (CBotStack*)malloc(size); + + // completely empty + memset(p, 0, size); + + p-> m_bBlock = true; + m_timer = m_initimer; // sets the timer at the beginning + + CBotStack* pp = p; + pp += MAXSTACK; + int i; + for ( i = 0 ; i< 10 ; i++ ) + { + pp->m_bOver = true; + pp ++; + } +#ifdef _DEBUG + int n = 1; + pp = p; + for ( i = 0 ; i< MAXSTACK+10 ; i++ ) + { + pp->m_index = n++; + pp ++; + } +#endif + + m_error = 0; // avoids deadlocks because m_error is static + return p; +} + +CBotStack::CBotStack(CBotStack* ppapa) +{ + // constructor must exist or the destructor is never called! + ASM_TRAP(); +} + +CBotStack::~CBotStack() +{ + ASM_TRAP(); // use Delete () instead +} + +void CBotStack::Delete() +{ + if ( this == NULL || this == EOX ) return; + + m_next->Delete(); + m_next2->Delete(); + + if (m_prev != NULL) + { + if ( m_prev->m_next == this ) + m_prev->m_next = NULL; // removes chain + + if ( m_prev->m_next2 == this ) + m_prev->m_next2 = NULL; // removes chain + } + + delete m_var; + delete m_listVar; + + CBotStack* p = m_prev; + bool bOver = m_bOver; +#ifdef _DEBUG + int n = m_index; +#endif + + // clears the freed block + memset(this, 0, sizeof(CBotStack)); + m_bOver = bOver; +#ifdef _DEBUG + m_index = n; +#endif + + if ( p == NULL ) + free( this ); +} + + +// routine improved +CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock) +{ + if (m_next != NULL) + { + return m_next; // included in an existing stack + } + +#ifdef _DEBUG + int n = 0; +#endif + CBotStack* p = this; + do + { + p ++; +#ifdef _DEBUG + n ++; +#endif + } + while ( p->m_prev != NULL ); + + m_next = p; // chain an element + p->m_bBlock = bBlock; + p->m_instr = instr; + p->m_prog = m_prog; + p->m_step = 0; + p->m_prev = this; + p->m_state = 0; + p->m_call = NULL; + p->m_bFunc = false; + return p; +} + +CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock) +{ + if (m_next != NULL) + { + if ( m_next == EOX ) + { + m_next = NULL; + return EOX; + } + return m_next; // included in an existing stack + } + CBotStack* p = AddStack(NULL, bBlock); + p->m_call = instr; + p->m_bFunc = 2; // special + return p; +} + +CBotStack* CBotStack::AddStack2(bool bBlock) +{ + if (m_next2 != NULL) + { + m_next2->m_prog = m_prog; // special avoids RestoreStack2 + return m_next2; // included in an existing stack + } + + CBotStack* p = this; + do + { + p ++; + } + while ( p->m_prev != NULL ); + + m_next2 = p; // chain an element + p->m_prev = this; + p->m_bBlock = bBlock; + p->m_prog = m_prog; + p->m_step = 0; + return p; +} + +bool CBotStack::GivBlock() +{ + return m_bBlock; +} + +bool CBotStack::Return(CBotStack* pfils) +{ + if ( pfils == this ) return true; // special + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + m_next->Delete();m_next = NULL; // releases the stack above + m_next2->Delete();m_next2 = NULL; // also the second stack (catch) + + return (m_error == 0); // interrupted if error +} + +bool CBotStack::ReturnKeep(CBotStack* pfils) +{ + if ( pfils == this ) return true; // special + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + return (m_error == 0); // interrupted if error +} + +bool CBotStack::StackOver() +{ + if (!m_bOver) return false; + m_error = TX_STACKOVER; + return true; +} + +#else + +CBotStack::CBotStack(CBotStack* ppapa) +{ + m_next = NULL; + m_next2 = NULL; + m_prev = ppapa; + + m_bBlock = (ppapa == NULL) ? true : false; + + m_state = 0; + m_step = 1; + + if (ppapa == NULL) m_timer = m_initimer; // sets the timer at the beginning + + m_listVar = NULL; + m_bDontDelete = false; + + m_var = NULL; + m_prog = NULL; + m_instr = NULL; + m_call = NULL; + m_bFunc = false; +} + +// destructor +CBotStack::~CBotStack() +{ + if ( m_next != EOX) delete m_next; + delete m_next2; + if (m_prev != NULL && m_prev->m_next == this ) + m_prev->m_next = NULL; // removes chain + + delete m_var; + if ( !m_bDontDelete ) delete m_listVar; +} + +// \TODO routine has/to optimize +CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock) +{ + if (m_next != NULL) + { + return m_next; // included in an existing stack + } + CBotStack* p = new CBotStack(this); + m_next = p; // chain an element + p->m_bBlock = bBlock; + p->m_instr = instr; + p->m_prog = m_prog; + p->m_step = 0; + return p; +} + +CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock) +{ + if (m_next != NULL) + { + if ( m_next == EOX ) + { + m_next = NULL; + return EOX; + } + return m_next; // included in an existing stack + } + CBotStack* p = new CBotStack(this); + m_next = p; // chain an element + p->m_bBlock = bBlock; + p->m_call = instr; + p->m_prog = m_prog; + p->m_step = 0; + p->m_bFunc = 2; // special + return p; +} + +CBotStack* CBotStack::AddStack2(bool bBlock) +{ + if (m_next2 != NULL) + { + m_next2->m_prog = m_prog; // special avoids RestoreStack2 + return m_next2; // included in an existing stack + } + + CBotStack* p = new CBotStack(this); + m_next2 = p; // chain an element + p->m_bBlock = bBlock; + p->m_prog = m_prog; + p->m_step = 0; + + return p; +} + +bool CBotStack::Return(CBotStack* pfils) +{ + if ( pfils == this ) return true; // special + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // do not destroy the variable + + if ( m_next != EOX ) delete m_next; // releases the stack above + delete m_next2;m_next2 = NULL; // also the second stack (catch) + + return (m_error == 0); // interrupted if error +} + +bool CBotStack::StackOver() +{ + return false; // no overflow check in this version +} + +#endif + +void CBotStack::Reset(void* pUser) +{ + m_timer = m_initimer; // resets the timer + m_error = 0; +// m_start = 0; +// m_end = 0; + m_labelBreak.Empty(); + m_pUser = pUser; +} + + + + +CBotStack* CBotStack::RestoreStack(CBotInstr* instr) +{ + if (m_next != NULL) + { + m_next->m_instr = instr; // reset (if recovery after ) + m_next->m_prog = m_prog; + return m_next; // included in an existing stack + } + return NULL; +} + +CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr) +{ + CBotStack* p = RestoreStack(); + p->m_call = instr; + return p; +} + + + +// routine for execution step by step +bool CBotStack::IfStep() +{ + if ( m_initimer > 0 || m_step++ > 0 ) return false; + return true; +} + + +bool CBotStack::BreakReturn(CBotStack* pfils, const char* name) +{ + if ( m_error>=0 ) return false; // normal output + if ( m_error==-3 ) return false; // normal output (return current) + + if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name)) + return false; // it's not for me + + m_error = 0; + m_labelBreak.Empty(); + return Return(pfils); +} + +bool CBotStack::IfContinue(int state, const char* name) +{ + if ( m_error != -2 ) return false; + + if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name)) + return false; // it's not for me + + m_state = state; // where again? + m_error = 0; + m_labelBreak.Empty(); + if ( m_next != EOX ) m_next->Delete(); // purge above stack + return true; +} + +void CBotStack::SetBreak(int val, const char* name) +{ + m_error = -val; // reacts as an Exception + m_labelBreak = name; + if (val == 3) // for a return + { + m_retvar = m_var; + m_var = NULL; + } +} + +// gives on the stack value calculated by the last CBotReturn + +bool CBotStack::GivRetVar(bool bRet) +{ + if (m_error == -3) + { + if ( m_var ) delete m_var; + m_var = m_retvar; + m_retvar = NULL; + m_error = 0; + return true; + } + return bRet; // interrupted by something other than return +} + +int CBotStack::GivError(int& start, int& end) +{ + start = m_start; + end = m_end; + return m_error; +} + + +int CBotStack::GivType(int mode) +{ + if (m_var == NULL) return -1; + return m_var->GivType(mode); +} + +CBotTypResult CBotStack::GivTypResult(int mode) +{ + if (m_var == NULL) return -1; + return m_var->GivTypResult(mode); +} + +void CBotStack::SetType(CBotTypResult& type) +{ + if (m_var == NULL) return; + m_var->SetType( type ); +} + + +CBotVar* CBotStack::FindVar(CBotToken* &pToken, bool bUpdate, bool bModif) +{ + CBotStack* p = this; + CBotString name = pToken->GivString(); + + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (pp->GivName() == name) + { + if ( bUpdate ) + pp->Maj(m_pUser, false); + + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + +CBotVar* CBotStack::FindVar(const char* name) +{ + CBotStack* p = this; + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (pp->GivName() == name) + { + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + +CBotVar* CBotStack::FindVar(long ident, bool bUpdate, bool bModif) +{ + CBotStack* p = this; + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (pp->GivUniqNum() == ident) + { + if ( bUpdate ) + pp->Maj(m_pUser, false); + + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + + +CBotVar* CBotStack::FindVar(CBotToken& Token, bool bUpdate, bool bModif) +{ + CBotToken* pt = &Token; + return FindVar(pt, bUpdate, bModif); +} + + +CBotVar* CBotStack::CopyVar(CBotToken& Token, bool bUpdate) +{ + CBotVar* pVar = FindVar( Token, bUpdate ); + + if ( pVar == NULL) return NULL; + + CBotVar* pCopy = CBotVar::Create(pVar); + pCopy->Copy(pVar); + return pCopy; +} + + +bool CBotStack::SetState(int n, int limite) +{ + m_state = n; + + m_timer--; // decrement the operations \TODO decrement the operations + return ( m_timer > limite ); // interrupted if timer pass +} + +bool CBotStack::IncState(int limite) +{ + m_state++; + + m_timer--; // decrement the operations \TODO decompte les operations + return ( m_timer > limite ); // interrupted if timer pass +} + + +void CBotStack::SetError(int n, CBotToken* token) +{ + if ( n!= 0 && m_error != 0) return; // does not change existing error + m_error = n; + if (token != NULL) + { + m_start = token->GivStart(); + m_end = token->GivEnd(); + } +} + +void CBotStack::ResetError(int n, int start, int end) +{ + m_error = n; + m_start = start; + m_end = end; +} + +void CBotStack::SetPosError(CBotToken* token) +{ + m_start = token->GivStart(); + m_end = token->GivEnd(); +} + +void CBotStack::SetTimer(int n) +{ + m_initimer = n; +} + +bool CBotStack::Execute() +{ + CBotCall* instr = NULL; // the most highest instruction + CBotStack* pile; + + CBotStack* p = this; + + while (p != NULL) + { + if ( p->m_next2 != NULL ) break; + if ( p->m_call != NULL ) + { + instr = p->m_call; + pile = p->m_prev ; + } + p = p->m_next; + } + + if ( instr == NULL ) return true; // normal execution request + + if (!instr->Run(pile)) return false; // \TODO exécution à partir de là + +#if STACKMEM + pile->m_next->Delete(); +#else + delete pile->m_next; +#endif + + pile->m_next = EOX; // special for recovery + return true; +} + +// puts on the stack pointer to a variable +void CBotStack::SetVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + m_var = var; +} + +// puts on the stack a copy of a variable +void CBotStack::SetCopyVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + + m_var = CBotVar::Create("", var->GivTypResult(2)); + m_var->Copy( var ); +} + +CBotVar* CBotStack::GivVar() +{ + return m_var; +} + +CBotVar* CBotStack::GivPtVar() +{ + CBotVar* p = m_var; + m_var = NULL; // therefore will not be destroyed + return p; +} + +CBotVar* CBotStack::GivCopyVar() +{ + if (m_var == NULL) return NULL; + CBotVar* v = CBotVar::Create("", m_var->GivType()); + v->Copy( m_var ); + return v; +} + +long CBotStack::GivVal() +{ + if (m_var == NULL) return 0; + return m_var->GivValInt(); +} + + + + +void CBotStack::AddVar(CBotVar* pVar) +{ + CBotStack* p = this; + + // returns to the father element + while (p != NULL && p->m_bBlock == 0) p = p->m_prev; + + if ( p == NULL ) return; + +/// p->m_bDontDelete = bDontDelete; + + CBotVar** pp = &p->m_listVar; + while ( *pp != NULL ) pp = &(*pp)->m_next; + + *pp = pVar; // added after + +#ifdef _DEBUG + if ( pVar->GivUniqNum() == 0 ) ASM_TRAP(); +#endif +} + +/*void CBotStack::RestoreVar(CBotVar* pVar) +{ + if ( !m_bDontDelete ) __asm int 3; + delete m_listVar; + m_listVar = pVar; // direct replacement +}*/ + +void CBotStack::SetBotCall(CBotProgram* p) +{ + m_prog = p; + m_bFunc = true; +} + +CBotProgram* CBotStack::GivBotCall(bool bFirst) +{ + if ( ! bFirst ) return m_prog; + CBotStack* p = this; + while ( p->m_prev != NULL ) p = p->m_prev; + return p->m_prog; +} + +void* CBotStack::GivPUser() +{ + return m_pUser; +} + + +bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype) +{ + CBotTypResult res; + + // first looks by the identifier + + res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype ); + if (res.GivType() >= 0) return res.GivType(); + + res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token ); + if (res.GivType() >= 0) return res.GivType(); + + // if not found (recompile?) seeks by name + + nIdent = 0; + res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype ); + if (res.GivType() >= 0) return res.GivType(); + + res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token ); + if (res.GivType() >= 0) return res.GivType(); + + SetError(TX_NOCALL, token); + return true; +} + +void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar) +{ + if ( m_next == NULL ) return; + + if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) ) + m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this ); +} + + +bool SaveVar(FILE* pf, CBotVar* pVar) +{ + while ( true ) + { + if ( pVar == NULL ) + { + return WriteWord(pf, 0); // is a terminator + } + + if ( !pVar->Save0State(pf)) return false; // common header + if ( !pVar->Save1State(pf) ) return false; // saves as the child class + + pVar = pVar->GivNext(); + } +} + +void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end) +{ + CBotProgram* prog = m_prog; // Current program + + CBotInstr* funct = NULL; // function found + CBotInstr* instr = NULL; // the highest intruction + + CBotStack* p = this; + + while (p->m_next != NULL) + { + if ( p->m_instr != NULL ) instr = p->m_instr; + if ( p->m_bFunc == 1 ) funct = p->m_instr; + if ( p->m_next->m_prog != prog ) break ; + + if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; + else p = p->m_next; + } + + if ( p->m_instr != NULL ) instr = p->m_instr; + if ( p->m_bFunc == 1 ) funct = p->m_instr; + + if ( funct == NULL ) return; + + CBotToken* t = funct->GivToken(); + FunctionName = t->GivString(); + +// if ( p->m_instr != NULL ) instr = p->m_instr; + + t = instr->GivToken(); + start = t->GivStart(); + end = t->GivEnd(); +} + +CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level) +{ + CBotProgram* prog = m_prog; // current program + FunctionName = NULL; + + // back the stack in the current module + CBotStack* p = this; + + while (p->m_next != NULL) + { + if ( p->m_next->m_prog != prog ) break ; + + if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ; + else p = p->m_next; + } + + + // descends upon the elements of block + while ( p != NULL && !p->m_bBlock ) p = p->m_prev; + + while ( p != NULL && level++ < 0 ) + { + p = p->m_prev; + while ( p != NULL && !p->m_bBlock ) p = p->m_prev; + } + + if ( p == NULL ) return NULL; + + // search the name of the current function + CBotStack* pp = p; + while ( pp != NULL ) + { + if ( pp->m_bFunc == 1 ) break; + pp = pp->m_prev; + } + + if ( pp == NULL || pp->m_instr == NULL ) return NULL; + + CBotToken* t = pp->m_instr->GivToken(); + FunctionName = t->GivString(); + + return p->m_listVar; +} + +bool CBotStack::SaveState(FILE* pf) +{ + if ( this == NULL ) // end of the tree? + { + return WriteWord(pf, 0); // is a terminator + } + + if ( m_next2 != NULL ) + { + if (!WriteWord(pf, 2)) return false; // a mark of pursuit + if (!m_next2->SaveState(pf)) return false; + } + else + { + if (!WriteWord(pf, 1)) return false; // a mark of pursuit + } + if (!WriteWord(pf, m_bBlock)) return false; // is a local block + if (!WriteWord(pf, m_state)) return false; // in what state? + if (!WriteWord(pf, 0)) return false; // by compatibility m_bDontDelete + if (!WriteWord(pf, m_step)) return false; // in what state? + + + if (!SaveVar(pf, m_var)) return false; // current result + if (!SaveVar(pf, m_listVar)) return false; // local variables + + return m_next->SaveState(pf); // saves the following +} + + +bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack) +{ + unsigned short w; + + pStack = NULL; + if (!ReadWord(pf, w)) return false; + if ( w == 0 ) return true; + +#if STACKMEM + if ( this == NULL ) pStack = FirstStack(); + else pStack = AddStack(); +#else + pStack = new CBotStack(this); +#endif + + if ( w == 2 ) + { + if (!pStack->RestoreState(pf, pStack->m_next2)) return false; + } + + if (!ReadWord(pf, w)) return false; // is a local block + pStack->m_bBlock = w; + + if (!ReadWord(pf, w)) return false; // in what state ? + pStack->SetState((short)w); // in a good state + + if (!ReadWord(pf, w)) return false; // dont delete? + // uses more + + if (!ReadWord(pf, w)) return false; // step by step + pStack->m_step = w; + + if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // temp variable + if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// local variables + + return pStack->RestoreState(pf, pStack->m_next); +} + + +bool CBotVar::Save0State(FILE* pf) +{ + if (!WriteWord(pf, 100+m_mPrivate))return false; // private variable? + if (!WriteWord(pf, m_bStatic))return false; // static variable? + if (!WriteWord(pf, m_type.GivType()))return false; // saves the type (always non-zero) + if (!WriteWord(pf, m_binit))return false; // variable defined? + return WriteString(pf, m_token->GivString()); // and variable name +} + +bool CBotVarInt::Save0State(FILE* pf) +{ + if ( !m_defnum.IsEmpty() ) + { + if(!WriteWord(pf, 200 )) return false; // special marker + if(!WriteString(pf, m_defnum)) return false; // name of the value + } + + return CBotVar::Save0State(pf); +} + +bool CBotVarInt::Save1State(FILE* pf) +{ + return WriteWord(pf, m_val); // the value of the variable +} + +bool CBotVarBoolean::Save1State(FILE* pf) +{ + return WriteWord(pf, m_val); // the value of the variable +} + +bool CBotVarFloat::Save1State(FILE* pf) +{ + return WriteFloat(pf, m_val); // the value of the variable +} + +bool CBotVarString::Save1State(FILE* pf) +{ + return WriteString(pf, m_val); // the value of the variable +} + + + +bool CBotVarClass::Save1State(FILE* pf) +{ + if ( !WriteType(pf, m_type) ) return false; + if ( !WriteLong(pf, m_ItemIdent) ) return false; + + return SaveVar(pf, m_pVar); // content of the object +} + +bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar) +{ + unsigned short w, wi, prv, st; + float ww; + CBotString name, s; + + delete pVar; + + pVar = NULL; + CBotVar* pNew = NULL; + CBotVar* pPrev = NULL; + + while ( true ) // retrieves a list + { + if (!ReadWord(pf, w)) return false; // private or type? + if ( w == 0 ) return true; + + CBotString defnum; + if ( w == 200 ) + { + if (!ReadString(pf, defnum)) return false; // number with identifier + if (!ReadWord(pf, w)) return false; // type + } + + prv = 100; st = 0; + if ( w >= 100 ) + { + prv = w; + if (!ReadWord(pf, st)) return false; // static + if (!ReadWord(pf, w)) return false; // type + } + + if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic + + if (!ReadWord(pf, wi)) return false; // init ? + + if (!ReadString(pf, name)) return false; // variable name + + CBotToken token(name, CBotString()); + + switch (w) + { + case CBotTypInt: + case CBotTypBoolean: + pNew = CBotVar::Create(&token, w); // creates a variable + if (!ReadWord(pf, w)) return false; + pNew->SetValInt((short)w, defnum); + break; + case CBotTypFloat: + pNew = CBotVar::Create(&token, w); // creates a variable + if (!ReadFloat(pf, ww)) return false; + pNew->SetValFloat(ww); + break; + case CBotTypString: + pNew = CBotVar::Create(&token, w); // creates a variable + if (!ReadString(pf, s)) return false; + pNew->SetValString(s); + break; + + // returns an intrinsic object or element of an array + case CBotTypIntrinsic: + case CBotTypArrayBody: + { + CBotTypResult r; + long id; + if (!ReadType(pf, r)) return false; // complete type + if (!ReadLong(pf, id) ) return false; + +// if (!ReadString(pf, s)) return false; + { + CBotVar* p = NULL; + if ( id ) p = CBotVarClass::Find(id) ; + + pNew = new CBotVarClass(&token, r); // directly creates an instance + // attention cptuse = 0 + if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return false; + pNew->SetIdent(id); + + if ( p != NULL ) + { + delete pNew; + pNew = p; // resume known element + } + } + } + break; + + case CBotTypPointer: + case CBotTypNullPointer: + if (!ReadString(pf, s)) return false; + { + pNew = CBotVar::Create(&token, CBotTypResult(w, s));// creates a variable + CBotVarClass* p = NULL; + long id; + ReadLong(pf, id); +// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance) + + // returns a copy of the original instance + CBotVar* pInstance = NULL; + if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; + ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over + +// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // rather this one + + } + break; + + case CBotTypArrayPointer: + { + CBotTypResult r; + if (!ReadType(pf, r)) return false; + + pNew = CBotVar::Create(&token, r); // creates a variable + + // returns a copy of the original instance + CBotVar* pInstance = NULL; + if ( !CBotVar::RestoreState( pf, pInstance ) ) return false; + ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over + } + break; + default: + ASM_TRAP(); + } + + if ( pPrev != NULL ) pPrev->m_next = pNew; + if ( pVar == NULL ) pVar = pNew; + + pNew->m_binit = wi; // pNew->SetInit(wi); + pNew->SetStatic(st); + pNew->SetPrivate(prv-100); + pPrev = pNew; + } + return true; +} + + + + +//////////////////////////////////////////////////////////////////////////// +// management of the compile stack +//////////////////////////////////////////////////////////////////////////// + +CBotProgram* CBotCStack::m_prog = NULL; // init the static variable +int CBotCStack::m_error = 0; +int CBotCStack::m_end = 0; +CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0); +//CBotToken* CBotCStack::m_retClass= NULL; + + +CBotCStack::CBotCStack(CBotCStack* ppapa) +{ + m_next = NULL; + m_prev = ppapa; + + if (ppapa == NULL) + { + m_error = 0; + m_start = 0; + m_end = 0; + m_bBlock = true; + } + else + { + m_start = ppapa->m_start; + m_bBlock = false; + } + + m_listVar = NULL; + m_var = NULL; +} + +// destructor +CBotCStack::~CBotCStack() +{ + if (m_next != NULL) delete m_next; + if (m_prev != NULL) m_prev->m_next = NULL; // removes chain + + delete m_var; + delete m_listVar; +} + +// used only at compile +CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock) +{ + if (m_next != NULL) return m_next; // include on an existing stack + + CBotCStack* p = new CBotCStack(this); + m_next = p; // channel element + p->m_bBlock = bBlock; + + if (pToken != NULL) p->SetStartError(pToken->GivStart()); + + return p; +} + + +CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils) +{ + if ( pfils == this ) return inst; + + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + if (m_error) + { + m_start = pfils->m_start; // retrieves the position of the error + m_end = pfils->m_end; + } + + delete pfils; + return inst; +} + +CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils) +{ + if (m_var != NULL) delete m_var; // value replaced? + m_var = pfils->m_var; // result transmitted + pfils->m_var = NULL; // not to destroy the variable + + if (m_error) + { + m_start = pfils->m_start; // retrieves the position of the error + m_end = pfils->m_end; + } + + delete pfils; + return inst; +} + +int CBotCStack::GivError(int& start, int& end) +{ + start = m_start; + end = m_end; + return m_error; +} + +int CBotCStack::GivError() +{ + return m_error; +} + +// type of instruction on the stack +CBotTypResult CBotCStack::GivTypResult(int mode) +{ + if (m_var == NULL) + return CBotTypResult(99); + return m_var->GivTypResult(mode); +} + +// type of instruction on the stack +int CBotCStack::GivType(int mode) +{ + if (m_var == NULL) + return 99; + return m_var->GivType(mode); +} + +// pointer on the stack is in what class? +CBotClass* CBotCStack::GivClass() +{ + if ( m_var == NULL ) + return NULL; + if ( m_var->GivType(1) != CBotTypPointer ) return NULL; + + return m_var->GivClass(); +} + +// type of instruction on the stack +void CBotCStack::SetType(CBotTypResult& type) +{ + if (m_var == NULL) return; + m_var->SetType( type ); +} + +// seeks a variable on the stack +// the token may be a result of TokenTypVar (object of a class) +// or a pointer in the source + +CBotVar* CBotCStack::FindVar(CBotToken* &pToken) +{ + CBotCStack* p = this; + CBotString name = pToken->GivString(); + + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (name == pp->GivName()) + { + return pp; + } + pp = pp->m_next; + } + p = p->m_prev; + } + return NULL; +} + +CBotVar* CBotCStack::FindVar(CBotToken& Token) +{ + CBotToken* pt = &Token; + return FindVar(pt); +} + +CBotVar* CBotCStack::CopyVar(CBotToken& Token) +{ + CBotVar* pVar = FindVar( Token ); + + if ( pVar == NULL) return NULL; + + CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() ); + pCopy->Copy(pVar); + return pCopy; +} + +bool CBotCStack::IsOk() +{ + return (m_error == 0); +} + + +void CBotCStack::SetStartError( int pos ) +{ + if ( m_error != 0) return; // does not change existing error + m_start = pos; +} + +void CBotCStack::SetError(int n, int pos) +{ + if ( n!= 0 && m_error != 0) return; // does not change existing error + m_error = n; + m_end = pos; +} + +void CBotCStack::SetError(int n, CBotToken* p) +{ + if (m_error) return; // does not change existing error + m_error = n; + m_start = p->GivStart(); + m_end = p->GivEnd(); +} + +void CBotCStack::ResetError(int n, int start, int end) +{ + m_error = n; + m_start = start; + m_end = end; +} + +bool CBotCStack::NextToken(CBotToken* &p) +{ + CBotToken* pp = p; + + p = p->GivNext(); + if (p!=NULL) return true; + + SetError(TX_ENDOF, pp->GivEnd()); + return false; +} + +void CBotCStack::SetBotCall(CBotProgram* p) +{ + m_prog = p; +} + +CBotProgram* CBotCStack::GivBotCall() +{ + return m_prog; +} + +void CBotCStack::SetRetType(CBotTypResult& type) +{ + m_retTyp = type; +} + +CBotTypResult CBotCStack::GivRetType() +{ + return m_retTyp; +} + +void CBotCStack::SetVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + m_var = var; +} + +// puts on the stack a copy of a variable +void CBotCStack::SetCopyVar( CBotVar* var ) +{ + if (m_var) delete m_var; // replacement of a variable + + if ( var == NULL ) return; + m_var = CBotVar::Create("", var->GivTypResult(2)); + m_var->Copy( var ); +} + +CBotVar* CBotCStack::GivVar() +{ + return m_var; +} + +void CBotCStack::AddVar(CBotVar* pVar) +{ + CBotCStack* p = this; + + // returns to the father element + while (p != NULL && p->m_bBlock == 0) p = p->m_prev; + + if ( p == NULL ) return; + + CBotVar** pp = &p->m_listVar; + while ( *pp != NULL ) pp = &(*pp)->m_next; + + *pp = pVar; // added after + +#ifdef _DEBUG + if ( pVar->GivUniqNum() == 0 ) ASM_TRAP(); +#endif +} + +// test whether a variable is already defined locally + +bool CBotCStack::CheckVarLocal(CBotToken* &pToken) +{ + CBotCStack* p = this; + CBotString name = pToken->GivString(); + + while (p != NULL) + { + CBotVar* pp = p->m_listVar; + while ( pp != NULL) + { + if (name == pp->GivName()) + return true; + pp = pp->m_next; + } + if ( p->m_bBlock ) return false; + p = p->m_prev; + } + return false; +} + +CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent) +{ + nIdent = 0; + CBotTypResult val(-1); + + val = CBotCall::CompileCall(p, ppVars, this, nIdent); + if (val.GivType() < 0) + { + val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent); + if ( val.GivType() < 0 ) + { + // pVar = NULL; // the error is not on a particular parameter + SetError( -val.GivType(), p ); + val.SetType(-val.GivType()); + return val; + } + } + return val; +} + +// test if a procedure name is already defined somewhere + +bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam) +{ + CBotString name = pToken->GivString(); + + if ( CBotCall::CheckCall(name) ) return true; + + CBotFunction* pp = m_prog->GivFunctions(); + while ( pp != NULL ) + { + if ( pToken->GivString() == pp->GivName() ) + { + // are parameters exactly the same? + if ( pp->CheckParam( pParam ) ) + return true; + } + pp = pp->Next(); + } + + pp = CBotFunction::m_listPublic; + while ( pp != NULL ) + { + if ( pToken->GivString() == pp->GivName() ) + { + // are parameters exactly the same? + if ( pp->CheckParam( pParam ) ) + return true; + } + pp = pp->m_nextpublic; + } + + return false; +} + diff --git a/src/CBot/CBotString.cpp b/src/CBot/CBotString.cpp index 9d5d257..6acd96e 100644 --- a/src/CBot/CBotString.cpp +++ b/src/CBot/CBotString.cpp @@ -12,7 +12,8 @@ // * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/./////////////////////////////////////////////////////
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+/////////////////////////////////////////////////////
//strings management
diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp index 03a5337..c76df7f 100644 --- a/src/CBot/CBotToken.cpp +++ b/src/CBot/CBotToken.cpp @@ -12,37 +12,40 @@ // * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.//////////////////////////////////////////////////////////////////
-// Gestion des Tokens
-// le texte d'un programme est d'abord transformé
-// en une suite de tokens pour facilité l'interprétation
+// * along with this program. If not, see http://www.gnu.org/licenses/.
-// il faudra traiter le seul cas d'erreur possible
-// qui est un caractère illégal dans une string
+
+//CBotToken.cpp
+
+//////////////////////////////////////////////////////////////////
+// Managing Tokens
+// the text of a program is first transformed
+// into a sequence of tokens for easy interpretation
+// it will only treat the case as an error
+// where there is an illegal character in a string
#include "CBot.h"
#include <cstdarg>
CBotStringArray CBotToken::m_ListKeyWords;
-int CBotToken::m_ListIdKeyWords[200];
+int CBotToken::m_ListIdKeyWords[200];
CBotStringArray CBotToken::m_ListKeyDefine;
-long CBotToken::m_ListKeyNums[MAXDEFNUM];
+long CBotToken::m_ListKeyNums[MAXDEFNUM];
-// constructeurs
+//! contructors
CBotToken::CBotToken()
{
- m_next = NULL;
- m_prev = NULL;
-
- m_type = TokenTypVar; // à priori un nom d'une variable
- m_IdKeyWord = -1;
+ m_next = NULL;
+ m_prev = NULL;
+ m_type = TokenTypVar; // at the beginning a default variable type
+ m_IdKeyWord = -1;
}
CBotToken::CBotToken(const CBotToken* pSrc)
{
- m_next = NULL;
- m_prev = NULL;
+ m_next = NULL;
+ m_prev = NULL;
m_Text.Empty();
m_Sep.Empty();
@@ -55,12 +58,13 @@ CBotToken::CBotToken(const CBotToken* pSrc) if ( pSrc != NULL )
{
- m_Text = pSrc->m_Text;
- m_Sep = pSrc->m_Sep;
m_type = pSrc->m_type;
m_IdKeyWord = pSrc->m_IdKeyWord;
+ m_Text = pSrc->m_Text;
+ m_Sep = pSrc->m_Sep;
+
m_start = pSrc->m_start;
m_end = pSrc->m_end;
}
@@ -68,14 +72,14 @@ CBotToken::CBotToken(const CBotToken* pSrc) CBotToken::CBotToken(const CBotString& mot, const CBotString& sep, int start, int end)
{
- m_Text = mot; // mot trouvé comme token
- m_Sep = sep; // séparateurs qui suivent
+ m_Text = mot; // word (mot) found as token
+ m_Sep = sep; // separator
m_next = NULL;
m_prev = NULL;
m_start = start;
m_end = end;
- m_type = TokenTypVar; // à priori un nom d'une variable
+ m_type = TokenTypVar; // at the beginning a default variable type
m_IdKeyWord = -1;
}
@@ -86,13 +90,13 @@ CBotToken::CBotToken(const char* mot, const char* sep) m_next = NULL;
m_prev = NULL;
- m_type = TokenTypVar; // à priori un nom d'une variable
+ m_type = TokenTypVar; // at the beginning a default variable type
m_IdKeyWord = -1;
}
CBotToken::~CBotToken()
{
- delete m_next; // récursif
+ delete m_next; // recursive
m_next = NULL;
}
@@ -121,9 +125,9 @@ const CBotToken& CBotToken::operator=(const CBotToken& src) int CBotToken::GivType()
{
- if (this == NULL) return 0;
- if (m_type == TokenTypKeyWord) return m_IdKeyWord;
- return m_type;
+ if (this == NULL) return 0;
+ if (m_type == TokenTypKeyWord) return m_IdKeyWord;
+ return m_type;
}
long CBotToken::GivIdKey()
@@ -214,85 +218,85 @@ bool Char2InList(const char c, const char cc, const char* list) }
static char* sep1 = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
-static char* sep2 = " \r\n\t"; // séparateurs pures
-static char* sep3 = ",:()[]{}-+*/=;<>!~^|&%."; // séparateurs opérationnels
-static char* num = "0123456789"; // le point (unique) est testé séparément
+static char* sep2 = " \r\n\t"; // only separators
+static char* sep3 = ",:()[]{}-+*/=;<>!~^|&%."; // operational separators
+static char* num = "0123456789"; // point (single) is tested separately
static char* hexnum = "0123456789ABCDEFabcdef";
-static char* nch = "\"\r\n\t"; // refusé dans les chaines
+static char* nch = "\"\r\n\t"; // forbidden in chains
-//static char* duo = "+=-=*=/===!=<=>=++--///**/||&&";// les opérateurs doubles
+//static char* duo = "+=-=*=/===!=<=>=++--///**/||&&"; // double operators
-// cherche le prochain token dans une phrase
-// ne doit pas commencer par des séparateurs
-// qui sont pris avec le token précédent
+// looking for the next token in a sentence
+// do not start with separators
+// which are made in the previous token
CBotToken* CBotToken::NextToken(char* &program, int& error, bool first)
{
- CBotString mot; // le mot trouvé
- CBotString sep; // les séparateurs qui le suivent
+ CBotString mot; // the word which is found
+ CBotString sep; // separators that are after
char c;
bool stop = first;
if (*program == 0) return NULL;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
if (!first)
{
- mot = c; // construit le mot
- c = *(program++); // prochain caractère
+ mot = c; // built the word
+ c = *(program++); // next character
- // cas particulier pour les chaînes de caractères
+ // special case for strings
if ( mot[0] == '\"' )
{
while (c != 0 && !CharInList(c, nch))
{
mot += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
if ( c == '\\' )
{
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
if ( c == 'n' ) c = '\n';
if ( c == 'r' ) c = '\r';
if ( c == 't' ) c = '\t';
mot += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
}
}
if ( c == '\"' )
{
- mot += c; // chaîne complète
- c = *(program++); // prochain caractère
+ mot += c; // string is complete
+ c = *(program++); // next character
}
stop = true;
}
- // cas particulier pour les nombres
+ // special case for numbers
if ( CharInList(mot[0], num ))
{
- bool bdot = false; // trouvé un point ?
- bool bexp = false; // trouvé un exposant ?
+ bool bdot = false; // found a point?
+ bool bexp = false; // found an exponent?
char* liste = num;
- if (mot[0] == '0' && c == 'x') // valeur hexadécimale ?
+ if (mot[0] == '0' && c == 'x') // hexadecimal value?
{
mot += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
liste = hexnum;
}
cw:
while (c != 0 && CharInList(c, liste))
{
cc: mot += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
}
- if ( liste == num ) // pas pour les exadécimaux
+ if ( liste == num ) // not for hexadecimal
{
if ( !bdot && c == '.' ) { bdot = true; goto cc; }
if ( !bexp && ( c == 'e' || c == 'E' ) )
{
bexp = true;
mot += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
if ( c == '-' ||
c == '+' ) goto cc;
goto cw;
@@ -302,13 +306,13 @@ cc: mot += c; stop = true;
}
- if (CharInList(mot[0], sep3)) // un séparateur opérationnel ?
+ if (CharInList(mot[0], sep3)) // an operational separator?
{
CBotString motc = mot;
- while (motc += c, c != 0 && GivKeyWords(motc)>0) // cherche l'opérande le plus long possible
+ while (motc += c, c != 0 && GivKeyWords(motc)>0) // operand seeks the longest possible
{
- mot += c; // construit le mot
- c = *(program++); // prochain caractère
+ mot += c; // build the word
+ c = *(program++); // next character
}
stop = true;
@@ -321,36 +325,36 @@ cc: mot += c; {
if (stop || c == 0 || CharInList(c, sep1))
{
- if (!first && mot.IsEmpty()) return NULL; // fin de l'analyse
+ if (!first && mot.IsEmpty()) return NULL; // end of the analysis
bis:
while (CharInList(c, sep2))
{
- sep += c; // tous les séparateurs qui suivent
+ sep += c; // after all the separators
c = *(program++);
}
- if (c == '/' && *program == '/') // un commentaire dans le tas ?
+ if (c == '/' && *program == '/') // comment on the heap?
{
while( c != '\n' && c != 0 )
{
sep += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
}
goto bis;
}
- if (c == '/' && *program == '*') // un commentaire dans le tas ?
+ if (c == '/' && *program == '*') // comment on the heap?
{
while( c != 0 && (c != '*' || *program != '/'))
{
sep += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
}
if ( c != 0 )
{
sep += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
sep += c;
- c = *(program++); // prochain caractère
+ c = *(program++); // next character
}
goto bis;
}
@@ -365,13 +369,13 @@ bis: token->m_IdKeyWord = GivKeyWords(mot);
if (token->m_IdKeyWord > 0) token->m_type = TokenTypKeyWord;
- else GivKeyDefNum(mot, token) ; // traite les DefineNum
+ else GivKeyDefNum(mot, token) ; // treats DefineNum
return token;
}
- mot += c; // construit le mot
- c = *(program++); // prochain caractère
+ mot += c; // built the word
+ c = *(program++); // next character
}
}
@@ -394,24 +398,24 @@ CBotToken* CBotToken::CompileTokens(const char* program, int& error) char* pp = p;
while (NULL != (nxt = NextToken(p, error)))
{
- prv->m_next = nxt; // ajoute à la suite
+ prv->m_next = nxt; // added after
nxt->m_prev = prv;
- prv = nxt; // avance
+ prv = nxt; // advance
nxt->m_start = pos;
-/* pos += nxt->m_Text.GivLength(); // la chaîne peut être plus courte (BOA supprimés)
+/* pos += nxt->m_Text.GivLength(); // chain may be shorter (BOA deleted)
nxt->m_end = pos;
pos += nxt->m_Sep.GivLength();*/
- pos += (p - pp); // taille totale
+ pos += (p - pp); // total size
nxt->m_end = pos - nxt->m_Sep.GivLength();
pp = p;
}
- // ajoute un token comme terminateur
- // ( utile pour avoir le précédent )
+ // adds a token as a terminator
+ // ( useful for the previous )
nxt = new CBotToken();
nxt->m_type = 0;
- prv->m_next = nxt; // ajoute à la suite
+ prv->m_next = nxt; // added after
nxt->m_prev = prv;
return tokenbase;
@@ -423,7 +427,7 @@ void CBotToken::Delete(CBotToken* pToken) }
-// recherche si un mot fait parti des mots clefs
+// search if a word is part of the keywords
int CBotToken::GivKeyWords(const char* w)
{
@@ -432,7 +436,7 @@ int CBotToken::GivKeyWords(const char* w) if (l == 0)
{
- LoadKeyWords(); // prend la liste la première fois
+ LoadKeyWords(); // takes the list for the first time
l = m_ListKeyWords.GivSize();
}
@@ -462,22 +466,25 @@ bool CBotToken::GivKeyDefNum(const char* w, CBotToken* &token) return false;
}
-// reprend la liste des mots clefs dans les ressources
/// \todo Fixme Figure out how this should work.
+
+// recreates the list of keywords and its IDs basing on some resources
+// defines of TokenKey.. are in CBotDll.h
+
void CBotToken::LoadKeyWords()
{
CBotString s;
int i, n = 0;
- i = TokenKeyWord;
+ i = TokenKeyWord; //start with keywords of the language
while (s.LoadString(i))
{
m_ListKeyWords.Add(s);
m_ListIdKeyWords[n++] = i++;
}
- i = TokenKeyDeclare;
+ i = TokenKeyDeclare; //keywords of declarations
while (s.LoadString(i))
{
m_ListKeyWords.Add(s);
@@ -485,14 +492,14 @@ void CBotToken::LoadKeyWords() }
- i = TokenKeyVal;
+ i = TokenKeyVal; //keywords of values
while (s.LoadString(i))
{
m_ListKeyWords.Add(s);
m_ListIdKeyWords[n++] = i++;
}
- i = TokenKeyOp;
+ i = TokenKeyOp; //operators
while (s.LoadString(i))
{
m_ListKeyWords.Add(s);
@@ -526,9 +533,8 @@ bool IsOfType(CBotToken* &p, int type1, int type2) }
return false;
}
-
-// idem avec un nombre indéfini d'arguments
-// il faut mettre un zéro comme dernier argument
+// Same with any number of arguments
+// There must be a zero as the last argument
bool IsOfTypeList(CBotToken* &p, int type1, ...)
{
int i = type1;
diff --git a/src/CBot/CBotToken.h b/src/CBot/CBotToken.h index 62e9bf3..8e9d1e3 100644 --- a/src/CBot/CBotToken.h +++ b/src/CBot/CBotToken.h @@ -12,15 +12,15 @@ // * 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/.////////////////////////////////////////////////////////////////////
-// interpréteur pour le language CBot du jeu COLOBOT
+// * along with this program. If not, see http://www.gnu.org/licenses/.
-// un programme écrit est tout d'abord transformé en une liste de tokens
-// avant d'aborder le compilateur proprement dit
-// par exemple
+// interpreter of the lanuage CBot for game COLOBOT
+// writing a program is first transformed into a list of tokens
+// before tackling the compiler itself
+// for example
// int var = 3 * ( pos.y + x )
-// est décomposé en (chaque ligne est un token)
+// is decomposed into (each line is a token)
// int
// var
// =
@@ -32,6 +32,7 @@ // x
// )
+#pragma once
extern bool IsOfType(CBotToken* &p, int type1, int type2 = -1);
extern bool IsOfTypeList(CBotToken* &p, int type1, ...);
diff --git a/src/CBot/CBotTwoOpExpr.cpp b/src/CBot/CBotTwoOpExpr.cpp index e2523b5..49cfcc8 100644 --- a/src/CBot/CBotTwoOpExpr.cpp +++ b/src/CBot/CBotTwoOpExpr.cpp @@ -1,566 +1,568 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////
-// expression du genre Opérande1 + Opérande2
-// Opérande1 > Opérande2
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotTwoOpExpr::CBotTwoOpExpr()
-{
- m_leftop =
- m_rightop = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotTwoOpExpr"; // debug
-}
-
-CBotTwoOpExpr::~CBotTwoOpExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-CBotLogicExpr::CBotLogicExpr()
-{
- m_condition =
- m_op1 =
- m_op2 = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotLogicExpr"; // debug
-}
-
-CBotLogicExpr::~CBotLogicExpr()
-{
- delete m_condition;
- delete m_op1;
- delete m_op2;
-}
-
-
-// type d'opérandes acceptés par les opérations
-#define ENTIER ((1<<CBotTypByte)|(1<<CBotTypShort)|(1<<CBotTypChar)|(1<<CBotTypInt)|(1<<CBotTypLong))
-#define FLOTANT ((1<<CBotTypFloat)|(1<<CBotTypDouble))
-#define BOOLEEN (1<<CBotTypBoolean)
-#define CHAINE (1<<CBotTypString)
-#define POINTER (1<<CBotTypPointer)
-#define INSTANCE (1<<CBotTypClass)
-
-// liste des opérations (précéance)
-// type acceptable, opérande
-// le zéro termine un niveau de précéance
-
-static int ListOp[] =
-{
- BOOLEEN, ID_LOGIC, 0,
- BOOLEEN, ID_TXT_OR,
- BOOLEEN, ID_LOG_OR, 0,
- BOOLEEN, ID_TXT_AND,
- BOOLEEN, ID_LOG_AND, 0,
- BOOLEEN|ENTIER, ID_OR, 0,
- BOOLEEN|ENTIER, ID_XOR, 0,
- BOOLEEN|ENTIER, ID_AND, 0,
- BOOLEEN|ENTIER|FLOTANT
- |CHAINE
- |POINTER
- |INSTANCE,ID_EQ,
- BOOLEEN|ENTIER|FLOTANT
- |CHAINE
- |POINTER
- |INSTANCE,ID_NE, 0,
- ENTIER|FLOTANT|CHAINE, ID_HI,
- ENTIER|FLOTANT|CHAINE, ID_LO,
- ENTIER|FLOTANT|CHAINE, ID_HS,
- ENTIER|FLOTANT|CHAINE, ID_LS, 0,
- ENTIER, ID_SR,
- ENTIER, ID_SL,
- ENTIER, ID_ASR, 0,
- ENTIER|FLOTANT|CHAINE, ID_ADD,
- ENTIER|FLOTANT, ID_SUB, 0,
- ENTIER|FLOTANT, ID_MUL,
- ENTIER|FLOTANT, ID_DIV,
- ENTIER|FLOTANT, ID_MODULO, 0,
- ENTIER|FLOTANT, ID_POWER, 0,
- 0,
-};
-
-bool IsInList( int val, int* list, int& typemasque )
-{
- while (true)
- {
- if ( *list == 0 ) return false;
- typemasque = *list++;
- if ( *list++ == val ) return true;
- }
-}
-
-bool TypeOk( int type, int test )
-{
- while (true)
- {
- if ( type == 0 ) return (test & 1);
- type--; test /= 2;
- }
-}
-
-// compile une instruction de type A op B
-
-CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations)
-{
- int typemasque;
-
- if ( pOperations == NULL ) pOperations = ListOp;
- int* pOp = pOperations;
- while ( *pOp++ != 0 ); // suite de la table
-
- CBotCStack* pStk = pStack->TokenStack(); // un bout de pile svp
-
- // cherche des instructions qui peuvent convenir à gauche de l'opération
- CBotInstr* left = (*pOp == 0) ?
- CBotParExpr::Compile( p, pStk ) : // expression (...) à gauche
- CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B à gauche
-
- if (left == NULL) return pStack->Return(NULL, pStk); // si erreur, la transmet
-
- // est-ce qu'on a l'opérande prévu ensuite ?
- int TypeOp = p->GivType();
- if ( IsInList( TypeOp, pOperations, typemasque ) )
- {
- CBotTypResult type1, type2;
- type1 = pStk->GivTypResult(); // de quel type le premier opérande ?
-
- if ( TypeOp == ID_LOGIC ) // cas spécial pour condition ? op1 : op2 ;
- {
- if ( !type1.Eq(CBotTypBoolean) )
- {
- pStk->SetError( TX_BADTYPE, p);
- return pStack->Return(NULL, pStk);
- }
- CBotLogicExpr* inst = new CBotLogicExpr();
- inst->m_condition = left;
-
- p = p->GivNext(); // saute le token de l'opération
- inst->m_op1 = CBotExpression::Compile(p, pStk);
- CBotToken* pp = p;
- if ( inst->m_op1 == NULL || !IsOfType( p, ID_DOTS ) )
- {
- pStk->SetError( TX_MISDOTS, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- type1 = pStk->GivTypResult();
-
- inst->m_op2 = CBotExpression::Compile(p, pStk);
- if ( inst->m_op2 == NULL )
- {
- pStk->SetError( TX_ENDOF, p->GivStart() );
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- type2 = pStk->GivTypResult();
- if (!TypeCompatible(type1, type2))
- {
- pStk->SetError( TX_BAD2TYPE, pp );
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- pStk->SetType(type1); // le plus grand des 2 types
-
- return pStack->Return(inst, pStk);
- }
-
- CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
-
- p = p->GivNext(); // saute le token de l'opération
-
- // cherche des instructions qui peuvent convenir à droite
-
- if ( NULL != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) )
- // expression (...) à droite
- {
- // il y a un second opérande acceptable
-
- type2 = pStk->GivTypResult(); // de quel type le résultat ?
-
- // quel est le type du résultat ?
- int TypeRes = MAX( type1.GivType(3), type2.GivType(3) );
- if ( TypeOp == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- type2 = type1; // tout type convertible en chaîne
- }
- else if ( TypeOp == ID_ADD && type2.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- type1 = type2; // tout type convertible en chaîne
- }
- else if (!TypeOk( TypeRes, typemasque )) type1.SetType(99);// erreur de type
-
- switch ( TypeOp )
- {
- case ID_LOG_OR:
- case ID_LOG_AND:
- case ID_TXT_OR:
- case ID_TXT_AND:
- case ID_EQ:
- case ID_NE:
- case ID_HI:
- case ID_LO:
- case ID_HS:
- case ID_LS:
- TypeRes = CBotTypBoolean;
- }
- if ( TypeCompatible (type1, type2, TypeOp ) ) // les résultats sont-ils compatibles
- {
- // si ok, enregistre l'opérande dans l'objet
- inst->m_leftop = left;
-
- // spécial pour évaluer les opérations de même niveau de gauche à droite
- while ( IsInList( p->GivType(), pOperations, typemasque ) ) // même(s) opération(s) suit ?
- {
- TypeOp = p->GivType();
- CBotTwoOpExpr* i = new CBotTwoOpExpr(); // élément pour opération
- i->SetToken(p); // mémorise l'opération
- i->m_leftop = inst; // opérande de gauche
- type1 = TypeRes;
-
- p = p->GivNext(); // avance à la suite
- i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp );
- type2 = pStk->GivTypResult();
-
- if ( !TypeCompatible (type1, type2, TypeOp) ) // les résultats sont-ils compatibles
- {
- pStk->SetError(TX_BAD2TYPE, &i->m_token);
- delete i;
- return pStack->Return(NULL, pStk);
- }
-
- if ( TypeRes != CBotTypString )
- TypeRes = MAX(type1.GivType(), type2.GivType());
- inst = i;
- }
-
- CBotTypResult t(type1);
- t.SetType(TypeRes);
- // met une variable sur la pile pour avoir le type de résultat
- pStk->SetVar(CBotVar::Create((CBotToken*)NULL, t));
-
- // et rend l'object à qui l'a demandé
- return pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_BAD2TYPE, &inst->m_token);
- }
-
- // en cas d'erreur, libère les éléments
- delete left;
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile
- return pStack->Return(NULL, pStk);
- }
-
- // si on n'a pas affaire à une opération + ou -
- // rend à qui l'a demandé, l'opérande (de gauche) trouvé
- // à la place de l'objet "addition"
- return pStack->Return(left, pStk);
-}
-
-
-bool IsNan(CBotVar* left, CBotVar* right, int* err = NULL)
-{
- if ( left ->GivInit() > IS_DEF || right->GivInit() > IS_DEF )
- {
- if ( err != NULL ) *err = TX_OPNAN ;
- return true;
- }
- return false;
-}
-
-
-// fait l'opération sur 2 opérandes
-
-bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pStk1 == EOX ) return true;
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GivState() == 0 ) // 1er état, évalue l'opérande de gauche
- {
- if (!m_leftop->Execute(pStk1) ) return false; // interrompu ici ?
-
- // pour les OU et ET logique, n'évalue pas la seconde expression si pas nécessaire
- if ( (GivTokenType() == ID_LOG_AND || GivTokenType() == ID_TXT_AND ) && pStk1->GivVal() == false )
- {
- CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
- res->SetValInt(false);
- pStk1->SetVar(res);
- return pStack->Return(pStk1); // transmet le résultat
- }
- if ( (GivTokenType() == ID_LOG_OR||GivTokenType() == ID_TXT_OR) && pStk1->GivVal() == true )
- {
- CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
- res->SetValInt(true);
- pStk1->SetVar(res);
- return pStack->Return(pStk1); // transmet le résultat
- }
-
- // passe à l'étape suivante
- pStk1->SetState(1); // prêt pour la suite
- }
-
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- // qui se trouve sur la pile, justement.
-
- CBotStack* pStk2 = pStk1->AddStack(); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-
- // 2e état, évalue l'opérande de droite
- if ( pStk2->GivState() == 0 )
- {
- if ( !m_rightop->Execute(pStk2) ) return false; // interrompu ici ?
- pStk2->IncState();
- }
-
- CBotTypResult type1 = pStk1->GivTypResult(); // de quels types les résultats ?
- CBotTypResult type2 = pStk2->GivTypResult();
-
- CBotStack* pStk3 = pStk2->AddStack(this); // ajoute un élément à la pile
- if ( pStk3->IfStep() ) return false; // montre l'opération si step by step
-
- // crée une variable temporaire pour y mettre le résultat
- // quel est le type du résultat ?
- int TypeRes = MAX(type1.GivType(), type2.GivType());
-
- if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- }
-
- switch ( GivTokenType() )
- {
- case ID_LOG_OR:
- case ID_LOG_AND:
- case ID_TXT_OR:
- case ID_TXT_AND:
- case ID_EQ:
- case ID_NE:
- case ID_HI:
- case ID_LO:
- case ID_HS:
- case ID_LS:
- TypeRes = CBotTypBoolean;
- break;
- case ID_DIV:
- TypeRes = MAX(TypeRes, CBotTypFloat);
- }
-
- // crée une variable pour le résultat
- CBotVar* result = CBotVar::Create( (CBotToken*)NULL, TypeRes);
-
- // crée une variable pour effectuer le calcul dans le type adapté
- TypeRes = MAX(type1.GivType(), type2.GivType());
-
- if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- }
-
- CBotVar* temp;
-
- if ( TypeRes == CBotTypPointer ) TypeRes = CBotTypNullPointer;
- if ( TypeRes == CBotTypClass ) temp = CBotVar::Create( (CBotToken*)NULL, CBotTypResult(CBotTypIntrinsic, type1.GivClass() ) );
- else temp = CBotVar::Create( (CBotToken*)NULL, TypeRes );
-
- int err = 0;
- // fait l'opération selon la demande
- CBotVar* left = pStk1->GivVar();
- CBotVar* right = pStk2->GivVar();
-
- switch (GivTokenType())
- {
- case ID_ADD:
- if ( !IsNan(left, right, &err) ) result->Add(left , right); // additionne
- break;
- case ID_SUB:
- if ( !IsNan(left, right, &err) ) result->Sub(left , right); // soustrait
- break;
- case ID_MUL:
- if ( !IsNan(left, right, &err) ) result->Mul(left , right); // multiplie
- break;
- case ID_POWER:
- if ( !IsNan(left, right, &err) ) result->Power(left , right); // puissance
- break;
- case ID_DIV:
- if ( !IsNan(left, right, &err) ) err = result->Div(left , right);// divise
- break;
- case ID_MODULO:
- if ( !IsNan(left, right, &err) ) err = result->Modulo(left , right);// reste de division
- break;
- case ID_LO:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Lo(left , right)); // inférieur
- break;
- case ID_HI:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Hi(left , right)); // supérieur
- break;
- case ID_LS:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Ls(left , right)); // inférieur ou égal
- break;
- case ID_HS:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Hs(left , right)); // supérieur ou égal
- break;
- case ID_EQ:
- if ( IsNan(left, right) )
- result->SetValInt(left->GivInit() == right->GivInit()) ;
- else
- result->SetValInt(temp->Eq(left , right)); // égal
- break;
- case ID_NE:
- if ( IsNan(left, right) )
- result->SetValInt(left ->GivInit() != right->GivInit()) ;
- else
- result->SetValInt(temp->Ne(left , right)); // différent
- break;
- case ID_TXT_AND:
- case ID_LOG_AND:
- case ID_AND:
- if ( !IsNan(left, right, &err) ) result->And(left , right); // ET
- break;
- case ID_TXT_OR:
- case ID_LOG_OR:
- case ID_OR:
- if ( !IsNan(left, right, &err) ) result->Or(left , right); // OU
- break;
- case ID_XOR:
- if ( !IsNan(left, right, &err) ) result->XOr(left , right); // OU exclusif
- break;
- case ID_ASR:
- if ( !IsNan(left, right, &err) ) result->ASR(left , right);
- break;
- case ID_SR:
- if ( !IsNan(left, right, &err) ) result->SR(left , right);
- break;
- case ID_SL:
- if ( !IsNan(left, right, &err) ) result->SL(left , right);
- break;
- default:
- ASM_TRAP();
- }
- delete temp;
-
- pStk2->SetVar(result); // met le résultat sur la pile
- if ( err ) pStk2->SetError(err, &m_token); // et l'erreur éventuelle (division par zéro)
-
-// pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk2); // transmet le résultat
-}
-
-void CBotTwoOpExpr::RestoreState(CBotStack* &pStack, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pStk1 = pStack->RestoreStack(this); // ajoute un élément à la pile
- if ( pStk1 == NULL ) return;
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GivState() == 0 ) // 1er état, évalue l'opérande de gauche
- {
- m_leftop->RestoreState(pStk1, bMain); // interrompu ici !
- return;
- }
-
- CBotStack* pStk2 = pStk1->RestoreStack(); // ajoute un élément à la pile
- if ( pStk2 == NULL ) return;
-
- // 2e état, évalue l'opérande de droite
- if ( pStk2->GivState() == 0 )
- {
- m_rightop->RestoreState(pStk2, bMain); // interrompu ici !
- return;
- }
-}
-
-
-bool CBotLogicExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pStk1 == EOX ) return true;
-
- if ( pStk1->GivState() == 0 )
- {
- if ( !m_condition->Execute(pStk1) ) return false;
- if (!pStk1->SetState(1)) return false;
- }
-
- if ( pStk1->GivVal() == true )
- {
- if ( !m_op1->Execute(pStk1) ) return false;
- }
- else
- {
- if ( !m_op2->Execute(pStk1) ) return false;
- }
-
- return pStack->Return(pStk1); // transmet le résultat
-}
-
-void CBotLogicExpr::RestoreState(CBotStack* &pStack, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pStk1 = pStack->RestoreStack(this); // ajoute un élément à la pile
- if ( pStk1 == NULL ) return;
-
- if ( pStk1->GivState() == 0 )
- {
- m_condition->RestoreState(pStk1, bMain);
- return;
- }
-
- if ( pStk1->GivVal() == true )
- {
- m_op1->RestoreState(pStk1, bMain);
- }
- else
- {
- m_op2->RestoreState(pStk1, bMain);
- }
-}
-
-#if 0
-void t()
-{
- int x,y;
- 1>0 ? x = 0 : y = 0;
-}
-#endif
-
-#if 01
-void t(bool t)
-{
- int x;
- x = 1 + t ? 1 : 3 + 4 * 2 ;
- t ? 0 : "test";
-}
-#endif
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +/////////////////////////////////////////////////// +// expression of type Opérande1 + Opérande2 +// Opérande1 > Opérande2 + +#include "CBot.h" + +// various constructors + +CBotTwoOpExpr::CBotTwoOpExpr() +{ + m_leftop = + m_rightop = NULL; // NULL to be able to delete without other + name = "CBotTwoOpExpr"; // debug +} + +CBotTwoOpExpr::~CBotTwoOpExpr() +{ + delete m_leftop; + delete m_rightop; +} + +CBotLogicExpr::CBotLogicExpr() +{ + m_condition = + m_op1 = + m_op2 = NULL; // NULL to be able to delete without other + name = "CBotLogicExpr"; // debug +} + +CBotLogicExpr::~CBotLogicExpr() +{ + delete m_condition; + delete m_op1; + delete m_op2; +} + + +// type of operands accepted by operations +#define ENTIER ((1<<CBotTypByte)|(1<<CBotTypShort)|(1<<CBotTypChar)|(1<<CBotTypInt)|(1<<CBotTypLong)) +#define FLOTANT ((1<<CBotTypFloat)|(1<<CBotTypDouble)) +#define BOOLEEN (1<<CBotTypBoolean) +#define CHAINE (1<<CBotTypString) +#define POINTER (1<<CBotTypPointer) +#define INSTANCE (1<<CBotTypClass) + +// list of operations (précéance) +// acceptable type, operand +// zero ends level \TODO précéance + +static int ListOp[] = +{ + BOOLEEN, ID_LOGIC, 0, + BOOLEEN, ID_TXT_OR, + BOOLEEN, ID_LOG_OR, 0, + BOOLEEN, ID_TXT_AND, + BOOLEEN, ID_LOG_AND, 0, + BOOLEEN|ENTIER, ID_OR, 0, + BOOLEEN|ENTIER, ID_XOR, 0, + BOOLEEN|ENTIER, ID_AND, 0, + BOOLEEN|ENTIER|FLOTANT + |CHAINE + |POINTER + |INSTANCE,ID_EQ, + BOOLEEN|ENTIER|FLOTANT + |CHAINE + |POINTER + |INSTANCE,ID_NE, 0, + ENTIER|FLOTANT|CHAINE, ID_HI, + ENTIER|FLOTANT|CHAINE, ID_LO, + ENTIER|FLOTANT|CHAINE, ID_HS, + ENTIER|FLOTANT|CHAINE, ID_LS, 0, + ENTIER, ID_SR, + ENTIER, ID_SL, + ENTIER, ID_ASR, 0, + ENTIER|FLOTANT|CHAINE, ID_ADD, + ENTIER|FLOTANT, ID_SUB, 0, + ENTIER|FLOTANT, ID_MUL, + ENTIER|FLOTANT, ID_DIV, + ENTIER|FLOTANT, ID_MODULO, 0, + ENTIER|FLOTANT, ID_POWER, 0, + 0, +}; + +bool IsInList( int val, int* list, int& typemasque ) +{ + while (true) + { + if ( *list == 0 ) return false; + typemasque = *list++; + if ( *list++ == val ) return true; + } +} + +bool TypeOk( int type, int test ) +{ + while (true) + { + if ( type == 0 ) return (test & 1); + type--; test /= 2; + } +} + +// compiles a instruction of type A op B + +CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations) +{ + int typemasque; + + if ( pOperations == NULL ) pOperations = ListOp; + int* pOp = pOperations; + while ( *pOp++ != 0 ); // follows the table + + CBotCStack* pStk = pStack->TokenStack(); // one end of stack please + + // search the intructions that may be suitable to the left of the operation + CBotInstr* left = (*pOp == 0) ? + CBotParExpr::Compile( p, pStk ) : // expression (...) left + CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B left + + if (left == NULL) return pStack->Return(NULL, pStk); // if error, transmit + + // did we expected the operand? + int TypeOp = p->GivType(); + if ( IsInList( TypeOp, pOperations, typemasque ) ) + { + CBotTypResult type1, type2; + type1 = pStk->GivTypResult(); // what kind of the first operand? + + if ( TypeOp == ID_LOGIC ) // special case provided for: ? op1: op2; + { + if ( !type1.Eq(CBotTypBoolean) ) + { + pStk->SetError( TX_BADTYPE, p); + return pStack->Return(NULL, pStk); + } + CBotLogicExpr* inst = new CBotLogicExpr(); + inst->m_condition = left; + + p = p->GivNext(); // skip the token of the operation + inst->m_op1 = CBotExpression::Compile(p, pStk); + CBotToken* pp = p; + if ( inst->m_op1 == NULL || !IsOfType( p, ID_DOTS ) ) + { + pStk->SetError( TX_MISDOTS, p->GivStart()); + delete inst; + return pStack->Return(NULL, pStk); + } + type1 = pStk->GivTypResult(); + + inst->m_op2 = CBotExpression::Compile(p, pStk); + if ( inst->m_op2 == NULL ) + { + pStk->SetError( TX_ENDOF, p->GivStart() ); + delete inst; + return pStack->Return(NULL, pStk); + } + type2 = pStk->GivTypResult(); + if (!TypeCompatible(type1, type2)) + { + pStk->SetError( TX_BAD2TYPE, pp ); + delete inst; + return pStack->Return(NULL, pStk); + } + + pStk->SetType(type1); // the greatest of 2 types + + return pStack->Return(inst, pStk); + } + + CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // element for operation + inst->SetToken(p); // stores the operation + + + p = p->GivNext(); // skip the token of the operation + + // looking statements that may be suitable for right + + if ( NULL != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) ) + // expression (...) right + { + // there is an second operand acceptable + + type2 = pStk->GivTypResult(); // what kind of results? + + // what kind of result? + int TypeRes = MAX( type1.GivType(3), type2.GivType(3) ); + if ( TypeOp == ID_ADD && type1.Eq(CBotTypString) ) + { + TypeRes = CBotTypString; + type2 = type1; // any type convertible chain + } + else if ( TypeOp == ID_ADD && type2.Eq(CBotTypString) ) + { + TypeRes = CBotTypString; + type1 = type2; // any type convertible chain + } + else if (!TypeOk( TypeRes, typemasque )) type1.SetType(99);// error of type + + switch ( TypeOp ) + { + case ID_LOG_OR: + case ID_LOG_AND: + case ID_TXT_OR: + case ID_TXT_AND: + case ID_EQ: + case ID_NE: + case ID_HI: + case ID_LO: + case ID_HS: + case ID_LS: + TypeRes = CBotTypBoolean; + } + if ( TypeCompatible (type1, type2, TypeOp ) ) // the results are compatible + { + // ok so, saves the operand in the object + inst->m_leftop = left; + + // special for evaluation of the operations of the same level from left to right + while ( IsInList( p->GivType(), pOperations, typemasque ) ) // same operation(s) follows? + { + TypeOp = p->GivType(); + CBotTwoOpExpr* i = new CBotTwoOpExpr(); // element for operation + i->SetToken(p); // stores the operation + i->m_leftop = inst; // left operand + type1 = TypeRes; + + p = p->GivNext(); // advance after + i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp ); + type2 = pStk->GivTypResult(); + + if ( !TypeCompatible (type1, type2, TypeOp) ) // the results are compatible + { + pStk->SetError(TX_BAD2TYPE, &i->m_token); + delete i; + return pStack->Return(NULL, pStk); + } + + if ( TypeRes != CBotTypString ) + TypeRes = MAX(type1.GivType(), type2.GivType()); + inst = i; + } + + CBotTypResult t(type1); + t.SetType(TypeRes); + // is a variable on the stack for the type of result + pStk->SetVar(CBotVar::Create((CBotToken*)NULL, t)); + + // and returns the requested object + return pStack->Return(inst, pStk); + } + pStk->SetError(TX_BAD2TYPE, &inst->m_token); + } + + // in case of error, releases the elements + delete left; + delete inst; + // and transmits the error to the stack + return pStack->Return(NULL, pStk); + } + + // if we are not dealing with an operation + or - + // goes to that requested, the operand (left) found + // instead of the object "addition" + return pStack->Return(left, pStk); +} + + +bool IsNan(CBotVar* left, CBotVar* right, int* err = NULL) +{ + if ( left ->GivInit() > IS_DEF || right->GivInit() > IS_DEF ) + { + if ( err != NULL ) *err = TX_OPNAN ; + return true; + } + return false; +} + + +// performes the operation on two operands + +bool CBotTwoOpExpr::Execute(CBotStack* &pStack) +{ + CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack + // or return in case of recovery +// if ( pStk1 == EOX ) return true; + + // according to recovery, it may be in one of two states + + if ( pStk1->GivState() == 0 ) // first state, evaluates the left operand + { + if (!m_leftop->Execute(pStk1) ) return false; // interrupted here? + + // for OR and AND logic does not evaluate the second expression if not necessary + if ( (GivTokenType() == ID_LOG_AND || GivTokenType() == ID_TXT_AND ) && pStk1->GivVal() == false ) + { + CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean); + res->SetValInt(false); + pStk1->SetVar(res); + return pStack->Return(pStk1); // transmits the result + } + if ( (GivTokenType() == ID_LOG_OR||GivTokenType() == ID_TXT_OR) && pStk1->GivVal() == true ) + { + CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean); + res->SetValInt(true); + pStk1->SetVar(res); + return pStack->Return(pStk1); // transmits the result + } + + // passes to the next step + pStk1->SetState(1); // ready for further + } + + + // requires a little more stack to avoid touching the result + // of which is left on the stack, precisely + + CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack + // or return in case of recovery + + // 2e état, évalue l'opérande de droite + if ( pStk2->GivState() == 0 ) + { + if ( !m_rightop->Execute(pStk2) ) return false; // interrupted here? + pStk2->IncState(); + } + + CBotTypResult type1 = pStk1->GivTypResult(); // what kind of results? + CBotTypResult type2 = pStk2->GivTypResult(); + + CBotStack* pStk3 = pStk2->AddStack(this); // adds an item to the stack + if ( pStk3->IfStep() ) return false; // shows the operation if step by step + + // creates a temporary variable to put the result + // what kind of result? + int TypeRes = MAX(type1.GivType(), type2.GivType()); + + if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) ) + { + TypeRes = CBotTypString; + } + + switch ( GivTokenType() ) + { + case ID_LOG_OR: + case ID_LOG_AND: + case ID_TXT_OR: + case ID_TXT_AND: + case ID_EQ: + case ID_NE: + case ID_HI: + case ID_LO: + case ID_HS: + case ID_LS: + TypeRes = CBotTypBoolean; + break; + case ID_DIV: + TypeRes = MAX(TypeRes, CBotTypFloat); + } + + // creates a variable for the result + CBotVar* result = CBotVar::Create( (CBotToken*)NULL, TypeRes); + + // creates a variable to perform the calculation in the appropriate type + TypeRes = MAX(type1.GivType(), type2.GivType()); + + if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) ) + { + TypeRes = CBotTypString; + } + + CBotVar* temp; + + if ( TypeRes == CBotTypPointer ) TypeRes = CBotTypNullPointer; + if ( TypeRes == CBotTypClass ) temp = CBotVar::Create( (CBotToken*)NULL, CBotTypResult(CBotTypIntrinsic, type1.GivClass() ) ); + else temp = CBotVar::Create( (CBotToken*)NULL, TypeRes ); + + int err = 0; + // is a operation according to request + CBotVar* left = pStk1->GivVar(); + CBotVar* right = pStk2->GivVar(); + + switch (GivTokenType()) + { + case ID_ADD: + if ( !IsNan(left, right, &err) ) result->Add(left , right); // addition + break; + case ID_SUB: + if ( !IsNan(left, right, &err) ) result->Sub(left , right); // substraction + break; + case ID_MUL: + if ( !IsNan(left, right, &err) ) result->Mul(left , right); // multiplies + break; + case ID_POWER: + if ( !IsNan(left, right, &err) ) result->Power(left , right); // power + break; + case ID_DIV: + if ( !IsNan(left, right, &err) ) err = result->Div(left , right);// division + break; + case ID_MODULO: + if ( !IsNan(left, right, &err) ) err = result->Modulo(left , right);// remainder of division + break; + case ID_LO: + if ( !IsNan(left, right, &err) ) + result->SetValInt(temp->Lo(left , right)); // lower + break; + case ID_HI: + if ( !IsNan(left, right, &err) ) + result->SetValInt(temp->Hi(left , right)); // top + break; + case ID_LS: + if ( !IsNan(left, right, &err) ) + result->SetValInt(temp->Ls(left , right)); // less than or equal + break; + case ID_HS: + if ( !IsNan(left, right, &err) ) + result->SetValInt(temp->Hs(left , right)); // greater than or equal + break; + case ID_EQ: + if ( IsNan(left, right) ) + result->SetValInt(left->GivInit() == right->GivInit()) ; + else + result->SetValInt(temp->Eq(left , right)); // equal + break; + case ID_NE: + if ( IsNan(left, right) ) + result->SetValInt(left ->GivInit() != right->GivInit()) ; + else + result->SetValInt(temp->Ne(left , right)); // different + break; + case ID_TXT_AND: + case ID_LOG_AND: + case ID_AND: + if ( !IsNan(left, right, &err) ) result->And(left , right); // AND + break; + case ID_TXT_OR: + case ID_LOG_OR: + case ID_OR: + if ( !IsNan(left, right, &err) ) result->Or(left , right); // OR + break; + case ID_XOR: + if ( !IsNan(left, right, &err) ) result->XOr(left , right); // exclusive OR + break; + case ID_ASR: + if ( !IsNan(left, right, &err) ) result->ASR(left , right); + break; + case ID_SR: + if ( !IsNan(left, right, &err) ) result->SR(left , right); + break; + case ID_SL: + if ( !IsNan(left, right, &err) ) result->SL(left , right); + break; + default: + ASM_TRAP(); + } + delete temp; + + pStk2->SetVar(result); // puts the result on the stack + if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero) + +// pStk1->Return(pStk2); // releases the stack + return pStack->Return(pStk2); // transmits the result +} + +void CBotTwoOpExpr::RestoreState(CBotStack* &pStack, bool bMain) +{ + if ( !bMain ) return; + CBotStack* pStk1 = pStack->RestoreStack(this); // adds an item to the stack + if ( pStk1 == NULL ) return; + + // according to recovery, it may be in one of two states + + if ( pStk1->GivState() == 0 ) // first state, evaluates the left operand + { + m_leftop->RestoreState(pStk1, bMain); // interrupted here! + return; + } + + CBotStack* pStk2 = pStk1->RestoreStack(); // adds an item to the stack + if ( pStk2 == NULL ) return; + + // second state, evaluates the right operand + if ( pStk2->GivState() == 0 ) + { + m_rightop->RestoreState(pStk2, bMain); // interrupted here! + return; + } +} + + +bool CBotLogicExpr::Execute(CBotStack* &pStack) +{ + CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack + // or return in case of recovery +// if ( pStk1 == EOX ) return true; + + if ( pStk1->GivState() == 0 ) + { + if ( !m_condition->Execute(pStk1) ) return false; + if (!pStk1->SetState(1)) return false; + } + + if ( pStk1->GivVal() == true ) + { + if ( !m_op1->Execute(pStk1) ) return false; + } + else + { + if ( !m_op2->Execute(pStk1) ) return false; + } + + return pStack->Return(pStk1); // transmits the result +} + +void CBotLogicExpr::RestoreState(CBotStack* &pStack, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pStk1 = pStack->RestoreStack(this); // adds an item to the stack + if ( pStk1 == NULL ) return; + + if ( pStk1->GivState() == 0 ) + { + m_condition->RestoreState(pStk1, bMain); + return; + } + + if ( pStk1->GivVal() == true ) + { + m_op1->RestoreState(pStk1, bMain); + } + else + { + m_op2->RestoreState(pStk1, bMain); + } +} + +#if 0 +void t() +{ + int x,y; + 1>0 ? x = 0 : y = 0; +} +#endif + +#if 01 +void t(bool t) +{ + int x; + x = 1 + t ? 1 : 3 + 4 * 2 ; + t ? 0 : "test"; +} +#endif diff --git a/src/CBot/CBotVar.cpp b/src/CBot/CBotVar.cpp index 9070298..0d9bfb3 100644 --- a/src/CBot/CBotVar.cpp +++ b/src/CBot/CBotVar.cpp @@ -1,2245 +1,2248 @@ -// * 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 pour la classe CBotVar
-// gestion des variables du langage CBot
-
-// on ne crée jamais d'instance de la class mère CBotVar
-
-
-#include "CBot.h"
-#include <math.h>
-#include <stdio.h>
-
-long CBotVar::m_identcpt = 0;
-
-CBotVar::CBotVar( )
-{
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = -1;
- m_binit = false;
- m_ident = 0;
- m_bStatic = false;
- m_mPrivate = 0;
-}
-
-CBotVarInt::CBotVarInt( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypInt;
- m_binit = false;
- m_bStatic = false;
- m_mPrivate = 0;
-
- m_val = 0;
-}
-
-CBotVarFloat::CBotVarFloat( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypFloat;
- m_binit = false;
- m_bStatic = false;
- m_mPrivate = 0;
-
- m_val = 0;
-}
-
-CBotVarString::CBotVarString( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypString;
- m_binit = false;
- m_bStatic = false;
- m_mPrivate = 0;
-
- m_val.Empty();
-}
-
-CBotVarBoolean::CBotVarBoolean( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypBoolean;
- m_binit = false;
- m_bStatic = false;
- m_mPrivate = 0;
-
- m_val = 0;
-}
-
-CBotVarClass* CBotVarClass::m_ExClass = NULL;
-
-CBotVarClass::CBotVarClass( const CBotToken* name, const CBotTypResult& type)
-{
-/*
-// int nIdent = 0;
- InitCBotVarClass( name, type ) //, nIdent );
-}
-
-CBotVarClass::CBotVarClass( const CBotToken* name, CBotTypResult& type) //, int &nIdent )
-{
- InitCBotVarClass( name, type ); //, nIdent );
-}
-
-void CBotVarClass::InitCBotVarClass( const CBotToken* name, CBotTypResult& type ) //, int &nIdent )
-{*/
- if ( !type.Eq(CBotTypClass) &&
- !type.Eq(CBotTypIntrinsic) && // par comodité accepte ces types
- !type.Eq(CBotTypPointer) &&
- !type.Eq(CBotTypArrayPointer) &&
- !type.Eq(CBotTypArrayBody)) ASM_TRAP();
-
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = OBJECTCREATED;//NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_pVar = NULL;
- m_type = type;
- if ( type.Eq(CBotTypArrayPointer) ) m_type.SetType( CBotTypArrayBody );
- else if ( !type.Eq(CBotTypArrayBody) ) m_type.SetType( CBotTypClass );
- // type officel pour cet object
-
- m_pClass = NULL;
- m_pParent = NULL;
- m_binit = false;
- m_bStatic = false;
- m_mPrivate = 0;
- m_bConstructor = false;
- m_CptUse = 0;
- m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum();
-
- // se place tout seul dans la liste
- if (m_ExClass) m_ExClass->m_ExPrev = this;
- m_ExNext = m_ExClass;
- m_ExPrev = NULL;
- m_ExClass = this;
-
- CBotClass* pClass = type.GivClass();
- CBotClass* pClass2 = pClass->GivParent();
- if ( pClass2 != NULL )
- {
- // crée également une instance dans la classe père
- m_pParent = new CBotVarClass(name, CBotTypResult(type.GivType(),pClass2) ); //, nIdent);
- }
-
- SetClass( pClass ); //, nIdent );
-
-}
-
-CBotVarClass::~CBotVarClass( )
-{
- if ( m_CptUse != 0 )
- ASM_TRAP();
-
- if ( m_pParent ) delete m_pParent;
- m_pParent = NULL;
-
- // libère l'objet indirect s'il y a lieu
-// if ( m_Indirect != NULL )
-// m_Indirect->DecrementUse();
-
- // retire la classe de la liste
- if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
- else m_ExClass = m_ExNext;
-
- if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
- m_ExPrev = NULL;
- m_ExNext = NULL;
-
- delete m_pVar;
-}
-
-void CBotVarClass::ConstructorSet()
-{
- m_bConstructor = true;
-}
-
-
-CBotVar::~CBotVar( )
-{
- delete m_token;
- delete m_next;
-}
-
-void CBotVar::debug()
-{
- const char* p = (const char*) m_token->GivString();
- CBotString s = (const char*) GivValString();
- const char* v = (const char*) s;
-
- if ( m_type.Eq(CBotTypClass) )
- {
- CBotVar* pv = ((CBotVarClass*)this)->m_pVar;
- while (pv != NULL)
- {
- pv->debug();
- pv = pv->GivNext();
- }
- }
-}
-
-void CBotVar::ConstructorSet()
-{
- // nop
-}
-
-void CBotVar::SetUserPtr(void* pUser)
-{
- m_pUserPtr = pUser;
- if (m_type.Eq(CBotTypPointer) &&
- ((CBotVarPointer*)this)->m_pVarClass != NULL )
- ((CBotVarPointer*)this)->m_pVarClass->SetUserPtr(pUser);
-}
-
-void CBotVar::SetIdent(long n)
-{
- if (m_type.Eq(CBotTypPointer) &&
- ((CBotVarPointer*)this)->m_pVarClass != NULL )
- ((CBotVarPointer*)this)->m_pVarClass->SetIdent(n);
-}
-
-void CBotVar::SetUniqNum(long n)
-{
- m_ident = n;
-
- if ( n == 0 ) ASM_TRAP();
-}
-
-long CBotVar::NextUniqNum()
-{
- if (++m_identcpt < 10000) m_identcpt = 10000;
- return m_identcpt;
-}
-
-long CBotVar::GivUniqNum()
-{
- return m_ident;
-}
-
-
-void* CBotVar::GivUserPtr()
-{
- return m_pUserPtr;
-}
-
-bool CBotVar::Save1State(FILE* pf)
-{
- // cette routine "virtual" ne doit jamais être appellée,
- // il doit y avoir une routine pour chaque classe fille (CBotVarInt, CBotVarFloat, etc)
- // ( voir le type dans m_type )
- ASM_TRAP();
- return false;
-}
-
-void CBotVar::Maj(void* pUser, bool bContinu)
-{
-/* if (!bContinu && m_pMyThis != NULL)
- m_pMyThis->Maj(pUser, true);*/
-}
-
-
-// crée une variable selon son type
-
-CBotVar* CBotVar::Create(const CBotToken* name, int type )
-{
- CBotTypResult t(type);
- return Create(name, t);
-}
-
-CBotVar* CBotVar::Create(const CBotToken* name, CBotTypResult type)
-{
- switch (type.GivType())
- {
- case CBotTypShort:
- case CBotTypInt:
- return new CBotVarInt(name);
- case CBotTypFloat:
- return new CBotVarFloat(name);
- case CBotTypBoolean:
- return new CBotVarBoolean(name);
- case CBotTypString:
- return new CBotVarString(name);
- case CBotTypPointer:
- case CBotTypNullPointer:
- return new CBotVarPointer(name, type);
- case CBotTypIntrinsic:
- return new CBotVarClass(name, type);
-
- case CBotTypClass:
- // crée une nouvelle instance d'une classe
- // et retourne le POINTER sur cette instance
- {
- CBotVarClass* instance = new CBotVarClass(name, type);
- CBotVarPointer* pointer = new CBotVarPointer(name, type);
- pointer->SetPointer( instance );
- return pointer;
- }
-
- case CBotTypArrayPointer:
- return new CBotVarArray(name, type);
-
- case CBotTypArrayBody:
- {
- CBotVarClass* instance = new CBotVarClass(name, type);
- CBotVarArray* array = new CBotVarArray(name, type);
- array->SetPointer( instance );
-
- CBotVar* pv = array;
- while (type.Eq(CBotTypArrayBody))
- {
- type = type.GivTypElem();
- pv = ((CBotVarArray*)pv)->GivItem(0, true); // crée au moins l'élément [0]
- }
-
- return array;
- }
- }
-
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::Create( CBotVar* pVar )
-{
- CBotVar* p = Create(pVar->m_token->GivString(), pVar->GivTypResult(2));
- return p;
-}
-
-
-CBotVar* CBotVar::Create( const char* n, CBotTypResult type)
-{
- CBotToken name(n);
-
- switch (type.GivType())
- {
- case CBotTypShort:
- case CBotTypInt:
- return new CBotVarInt(&name);
- case CBotTypFloat:
- return new CBotVarFloat(&name);
- case CBotTypBoolean:
- return new CBotVarBoolean(&name);
- case CBotTypString:
- return new CBotVarString(&name);
- case CBotTypPointer:
- case CBotTypNullPointer:
- {
- CBotVarPointer* p = new CBotVarPointer(&name, type);
-// p->SetClass(type.GivClass());
- return p;
- }
- case CBotTypIntrinsic:
- {
- CBotVarClass* p = new CBotVarClass(&name, type);
-// p->SetClass(type.GivClass());
- return p;
- }
-
- case CBotTypClass:
- // crée une nouvelle instance d'une classe
- // et retourne le POINTER sur cette instance
- {
- CBotVarClass* instance = new CBotVarClass(&name, type);
- CBotVarPointer* pointer = new CBotVarPointer(&name, type);
- pointer->SetPointer( instance );
-// pointer->SetClass( type.GivClass() );
- return pointer;
- }
-
- case CBotTypArrayPointer:
- return new CBotVarArray(&name, type);
-
- case CBotTypArrayBody:
- {
- CBotVarClass* instance = new CBotVarClass(&name, type);
- CBotVarArray* array = new CBotVarArray(&name, type);
- array->SetPointer( instance );
-
- CBotVar* pv = array;
- while (type.Eq(CBotTypArrayBody))
- {
- type = type.GivTypElem();
- pv = ((CBotVarArray*)pv)->GivItem(0, true); // crée au moins l'élément [0]
- }
-
- return array;
- }
- }
-
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::Create( const char* name, int type, CBotClass* pClass)
-{
- CBotToken token( name, "" );
- CBotVar* pVar = Create( &token, type );
-
- if ( type == CBotTypPointer && pClass == NULL ) // pointeur "null" ?
- return pVar;
-
- if ( type == CBotTypClass || type == CBotTypPointer ||
- type == CBotTypIntrinsic )
- {
- if (pClass == NULL)
- {
- delete pVar;
- return NULL;
- }
- pVar->SetClass( pClass );
- }
- return pVar;
-}
-
-CBotVar* CBotVar::Create( const char* name, CBotClass* pClass)
-{
- CBotToken token( name, "" );
- CBotVar* pVar = Create( &token, CBotTypResult( CBotTypClass, pClass ) );
-// pVar->SetClass( pClass );
- return pVar;
-}
-
-CBotTypResult CBotVar::GivTypResult(int mode)
-{
- CBotTypResult r = m_type;
-
- if ( mode == 1 && m_type.Eq(CBotTypClass) )
- r.SetType(CBotTypPointer);
- if ( mode == 2 && m_type.Eq(CBotTypClass) )
- r.SetType(CBotTypIntrinsic);
-
- return r;
-}
-
-int CBotVar::GivType(int mode)
-{
- if ( mode == 1 && m_type.Eq(CBotTypClass) )
- return CBotTypPointer;
- if ( mode == 2 && m_type.Eq(CBotTypClass) )
- return CBotTypIntrinsic;
- return m_type.GivType();
-}
-
-void CBotVar::SetType(CBotTypResult& type)
-{
- m_type = type;
-}
-
-
-int CBotVar::GivInit()
-{
- if ( m_type.Eq(CBotTypClass) ) return IS_DEF; // toujours défini !
-
- return m_binit;
-}
-
-void CBotVar::SetInit(int bInit)
-{
- m_binit = bInit;
- if ( bInit == 2 ) m_binit = IS_DEF; // cas spécial
-
- if ( m_type.Eq(CBotTypPointer) && bInit == 2 )
- {
- CBotVarClass* instance = GivPointer();
- if ( instance == NULL )
- {
- instance = new CBotVarClass(NULL, m_type);
-// instance->SetClass(((CBotVarPointer*)this)->m_pClass);
- SetPointer(instance);
- }
- instance->SetInit(1);
- }
-
- if ( m_type.Eq(CBotTypClass) || m_type.Eq(CBotTypIntrinsic) )
- {
- CBotVar* p = ((CBotVarClass*)this)->m_pVar;
- while( p != NULL )
- {
- p->SetInit( bInit );
- p->m_pMyThis = (CBotVarClass*)this;
- p = p->GivNext();
- }
- }
-}
-
-CBotString CBotVar::GivName()
-{
- return m_token->GivString();
-}
-
-void CBotVar::SetName(const char* name)
-{
- m_token->SetString(name);
-}
-
-CBotToken* CBotVar::GivToken()
-{
- return m_token;
-}
-
-CBotVar* CBotVar::GivItem(const char* name)
-{
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::GivItemRef(int nIdent)
-{
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::GivItemList()
-{
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::GivItem(int row, bool bGrow)
-{
- ASM_TRAP();
- return NULL;
-}
-
-// dit si une variable appartient à une classe donnée
-bool CBotVar::IsElemOfClass(const char* name)
-{
- CBotClass* pc = NULL;
-
- if ( m_type.Eq(CBotTypPointer) )
- {
- pc = ((CBotVarPointer*)this)->m_pClass;
- }
- if ( m_type.Eq(CBotTypClass) )
- {
- pc = ((CBotVarClass*)this)->m_pClass;
- }
-
- while ( pc != NULL )
- {
- if ( pc->GivName() == name ) return true;
- pc = pc->GivParent();
- }
-
- return false;
-}
-
-
-CBotVar* CBotVar::GivStaticVar()
-{
- // rend le pointeur à la variable si elle est statique
- if ( m_bStatic == 0 || m_pMyThis == NULL ) return this;
-
- CBotClass* pClass = m_pMyThis->GivClass();
- return pClass->GivItem( m_token->GivString() );
-}
-
-
-CBotVar* CBotVar::GivNext()
-{
- return m_next;
-}
-
-void CBotVar::AddNext(CBotVar* pVar)
-{
- CBotVar* p = this;
- while (p->m_next != NULL) p = p->m_next;
-
- p->m_next = pVar;
-}
-
-void CBotVar::SetVal(CBotVar* var)
-{
- switch (/*var->*/GivType())
- {
- case CBotTypBoolean:
- SetValInt(var->GivValInt());
- break;
- case CBotTypInt:
- SetValInt(var->GivValInt(), ((CBotVarInt*)var)->m_defnum);
- break;
- case CBotTypFloat:
- SetValFloat(var->GivValFloat());
- break;
- case CBotTypString:
- SetValString(var->GivValString());
- break;
- case CBotTypPointer:
- case CBotTypNullPointer:
- case CBotTypArrayPointer:
- SetPointer(var->GivPointer());
- break;
- case CBotTypClass:
- {
- delete ((CBotVarClass*)this)->m_pVar;
- ((CBotVarClass*)this)->m_pVar = NULL;
- Copy(var, false);
- }
- break;
- default:
- ASM_TRAP();
- }
-
- m_binit = var->m_binit; // copie l'état nan s'il y a
-}
-
-void CBotVar::SetStatic(bool bStatic)
-{
- m_bStatic = bStatic;
-}
-
-void CBotVar::SetPrivate(int mPrivate)
-{
- m_mPrivate = mPrivate;
-}
-
-bool CBotVar::IsStatic()
-{
- return m_bStatic;
-}
-
-bool CBotVar::IsPrivate(int mode)
-{
- return m_mPrivate >= mode;
-}
-
-int CBotVar::GivPrivate()
-{
- return m_mPrivate;
-}
-
-
-void CBotVar::SetPointer(CBotVar* pVarClass)
-{
- ASM_TRAP();
-}
-
-CBotVarClass* CBotVar::GivPointer()
-{
- ASM_TRAP();
- return NULL;
-}
-
-// toutes ces fonctions doivent être définies dans les classes filles
-// dérivées de la classe CBotVar
-
-int CBotVar::GivValInt()
-{
- ASM_TRAP();
- return 0;
-}
-
-float CBotVar::GivValFloat()
-{
- ASM_TRAP();
- return 0;
-}
-
-void CBotVar::SetValInt(int c, const char* s)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SetValFloat(float c)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Mul(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Power(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-int CBotVar::Div(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return 0;
-}
-
-int CBotVar::Modulo(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return 0;
-}
-
-void CBotVar::Add(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Sub(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-bool CBotVar::Lo(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return false;
-}
-
-bool CBotVar::Hi(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return false;
-}
-
-bool CBotVar::Ls(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return false;
-}
-
-bool CBotVar::Hs(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return false;
-}
-
-bool CBotVar::Eq(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return false;
-}
-
-bool CBotVar::Ne(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return false;
-}
-
-void CBotVar::And(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Or(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::XOr(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::ASR(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SR(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SL(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Neg()
-{
- ASM_TRAP();
-}
-
-void CBotVar::Not()
-{
- ASM_TRAP();
-}
-
-void CBotVar::Inc()
-{
- ASM_TRAP();
-}
-void CBotVar::Dec()
-{
- ASM_TRAP();
-}
-
-void CBotVar::Copy(CBotVar* pSrc, bool bName)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SetValString(const char* p)
-{
- ASM_TRAP();
-}
-
-CBotString CBotVar::GivValString()
-{
- ASM_TRAP();
- return CBotString();
-}
-
-void CBotVar::SetClass(CBotClass* pClass)
-{
- ASM_TRAP();
-}
-
-CBotClass* CBotVar::GivClass()
-{
- ASM_TRAP();
- return NULL;
-}
-
-/*
-void CBotVar::SetIndirection(CBotVar* pVar)
-{
- // nop, uniquement pour CBotVarPointer::SetIndirection
-}
-*/
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarInt::Copy(CBotVar* pSrc, bool bName)
-{
- CBotVarInt* p = (CBotVarInt*)pSrc;
-
- if ( bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
- m_pMyThis = NULL;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-
- m_defnum = p->m_defnum;
-}
-
-
-
-
-void CBotVarInt::SetValInt(int val, const char* defnum)
-{
- m_val = val;
- m_binit = true;
- m_defnum = defnum;
-}
-
-
-
-void CBotVarInt::SetValFloat(float val)
-{
- m_val = (int)val;
- m_binit = true;
-}
-
-int CBotVarInt::GivValInt()
-{
- return m_val;
-}
-
-float CBotVarInt::GivValFloat()
-{
- return (float)m_val;
-}
-
-CBotString CBotVarInt::GivValString()
-{
- if ( !m_defnum.IsEmpty() ) return m_defnum;
-
- CBotString res;
-
- if ( !m_binit )
- {
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- res.LoadString(TX_NAN);
- return res;
- }
-
- char buffer[300];
- sprintf(buffer, "%d", m_val);
- res = buffer;
-
- return res;
-}
-
-
-void CBotVarInt::Mul(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() * right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::Power(CBotVar* left, CBotVar* right)
-{
- m_val = (int) pow( (double) left->GivValInt() , (double) right->GivValInt() );
- m_binit = true;
-}
-
-int CBotVarInt::Div(CBotVar* left, CBotVar* right)
-{
- int r = right->GivValInt();
- if ( r != 0 )
- {
- m_val = left->GivValInt() / r;
- m_binit = true;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-int CBotVarInt::Modulo(CBotVar* left, CBotVar* right)
-{
- int r = right->GivValInt();
- if ( r != 0 )
- {
- m_val = left->GivValInt() % r;
- m_binit = true;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-void CBotVarInt::Add(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() + right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::Sub(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() - right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::XOr(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() ^ right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::And(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() & right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::Or(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() | right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::SL(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() << right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::ASR(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() >> right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarInt::SR(CBotVar* left, CBotVar* right)
-{
- int source = left->GivValInt();
- int shift = right->GivValInt();
- if (shift>=1) source &= 0x7fffffff;
- m_val = source >> shift;
- m_binit = true;
-}
-
-void CBotVarInt::Neg()
-{
- m_val = -m_val;
-}
-
-void CBotVarInt::Not()
-{
- m_val = ~m_val;
-}
-
-void CBotVarInt::Inc()
-{
- m_val++;
- m_defnum.Empty();
-}
-
-void CBotVarInt::Dec()
-{
- m_val--;
- m_defnum.Empty();
-}
-
-bool CBotVarInt::Lo(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() < right->GivValInt();
-}
-
-bool CBotVarInt::Hi(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() > right->GivValInt();
-}
-
-bool CBotVarInt::Ls(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() <= right->GivValInt();
-}
-
-bool CBotVarInt::Hs(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() >= right->GivValInt();
-}
-
-bool CBotVarInt::Eq(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() == right->GivValInt();
-}
-
-bool CBotVarInt::Ne(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() != right->GivValInt();
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarFloat::Copy(CBotVar* pSrc, bool bName)
-{
- CBotVarFloat* p = (CBotVarFloat*)pSrc;
-
- if (bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-
-
-
-void CBotVarFloat::SetValInt(int val, const char* s)
-{
- m_val = (float)val;
- m_binit = true;
-}
-
-void CBotVarFloat::SetValFloat(float val)
-{
- m_val = val;
- m_binit = true;
-}
-
-int CBotVarFloat::GivValInt()
-{
- return (int)m_val;
-}
-
-float CBotVarFloat::GivValFloat()
-{
- return m_val;
-}
-
-CBotString CBotVarFloat::GivValString()
-{
- CBotString res;
-
- if ( !m_binit )
- {
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- res.LoadString(TX_NAN);
- return res;
- }
-
- char buffer[300];
- sprintf(buffer, "%.2f", m_val);
- res = buffer;
-
- return res;
-}
-
-
-void CBotVarFloat::Mul(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValFloat() * right->GivValFloat();
- m_binit = true;
-}
-
-void CBotVarFloat::Power(CBotVar* left, CBotVar* right)
-{
- m_val = (float)pow( left->GivValFloat() , right->GivValFloat() );
- m_binit = true;
-}
-
-int CBotVarFloat::Div(CBotVar* left, CBotVar* right)
-{
- float r = right->GivValFloat();
- if ( r != 0 )
- {
- m_val = left->GivValFloat() / r;
- m_binit = true;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-int CBotVarFloat::Modulo(CBotVar* left, CBotVar* right)
-{
- float r = right->GivValFloat();
- if ( r != 0 )
- {
- m_val = (float)fmod( left->GivValFloat() , r );
- m_binit = true;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-void CBotVarFloat::Add(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValFloat() + right->GivValFloat();
- m_binit = true;
-}
-
-void CBotVarFloat::Sub(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValFloat() - right->GivValFloat();
- m_binit = true;
-}
-
-void CBotVarFloat::Neg()
-{
- m_val = -m_val;
-}
-
-void CBotVarFloat::Inc()
-{
- m_val++;
-}
-
-void CBotVarFloat::Dec()
-{
- m_val--;
-}
-
-
-bool CBotVarFloat::Lo(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() < right->GivValFloat();
-}
-
-bool CBotVarFloat::Hi(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() > right->GivValFloat();
-}
-
-bool CBotVarFloat::Ls(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() <= right->GivValFloat();
-}
-
-bool CBotVarFloat::Hs(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() >= right->GivValFloat();
-}
-
-bool CBotVarFloat::Eq(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() == right->GivValFloat();
-}
-
-bool CBotVarFloat::Ne(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() != right->GivValFloat();
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarBoolean::Copy(CBotVar* pSrc, bool bName)
-{
- CBotVarBoolean* p = (CBotVarBoolean*)pSrc;
-
- if (bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-
-
-
-void CBotVarBoolean::SetValInt(int val, const char* s)
-{
- m_val = (bool)val;
- m_binit = true;
-}
-
-void CBotVarBoolean::SetValFloat(float val)
-{
- m_val = (bool)val;
- m_binit = true;
-}
-
-int CBotVarBoolean::GivValInt()
-{
- return m_val;
-}
-
-float CBotVarBoolean::GivValFloat()
-{
- return (float)m_val;
-}
-
-CBotString CBotVarBoolean::GivValString()
-{
- CBotString ret;
-
- CBotString res;
-
- if ( !m_binit )
- {
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- res.LoadString(TX_NAN);
- return res;
- }
-
- ret.LoadString( m_val > 0 ? ID_TRUE : ID_FALSE );
- return ret;
-}
-
-void CBotVarBoolean::And(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() && right->GivValInt();
- m_binit = true;
-}
-void CBotVarBoolean::Or(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() || right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarBoolean::XOr(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() ^ right->GivValInt();
- m_binit = true;
-}
-
-void CBotVarBoolean::Not()
-{
- m_val = m_val ? false : true ;
-}
-
-bool CBotVarBoolean::Eq(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() == right->GivValInt();
-}
-
-bool CBotVarBoolean::Ne(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() != right->GivValInt();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarString::Copy(CBotVar* pSrc, bool bName)
-{
- CBotVarString* p = (CBotVarString*)pSrc;
-
- if (bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-
-void CBotVarString::SetValString(const char* p)
-{
- m_val = p;
- m_binit = true;
-}
-
-CBotString CBotVarString::GivValString()
-{
- if ( !m_binit )
- {
- CBotString res;
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- CBotString res;
- res.LoadString(TX_NAN);
- return res;
- }
-
- return m_val;
-}
-
-
-void CBotVarString::Add(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValString() + right->GivValString();
- m_binit = true;
-}
-
-bool CBotVarString::Eq(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-bool CBotVarString::Ne(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() != right->GivValString());
-}
-
-
-bool CBotVarString::Lo(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-bool CBotVarString::Hi(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-bool CBotVarString::Ls(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-bool CBotVarString::Hs(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-
-////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarClass::Copy(CBotVar* pSrc, bool bName)
-{
- pSrc = pSrc->GivPointer(); // si source donné par un pointeur
-
- if ( pSrc->GivType() != CBotTypClass )
- ASM_TRAP();
-
- CBotVarClass* p = (CBotVarClass*)pSrc;
-
- if (bName) *m_token = *p->m_token;
-
- m_type = p->m_type;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_pClass = p->m_pClass;
- if ( p->m_pParent )
- {
- ASM_TRAP(); "que faire du pParent";
- }
-
-// m_next = NULL;
- m_pUserPtr = p->m_pUserPtr;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_ItemIdent = p->m_ItemIdent;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-
- delete m_pVar;
- m_pVar = NULL;
-
- CBotVar* pv = p->m_pVar;
- while( pv != NULL )
- {
- CBotVar* pn = CBotVar::Create(pv);
- pn->Copy( pv );
- if ( m_pVar == NULL ) m_pVar = pn;
- else m_pVar->AddNext(pn);
-
- pv = pv->GivNext();
- }
-}
-
-void CBotVarClass::SetItemList(CBotVar* pVar)
-{
- delete m_pVar;
- m_pVar = pVar; // remplace le pointeur existant
-}
-
-void CBotVarClass::SetIdent(long n)
-{
- m_ItemIdent = n;
-}
-
-void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent)
-{
- m_type.m_pClass = pClass;
-
- if ( m_pClass == pClass ) return;
-
- m_pClass = pClass;
-
- // initialise les variables associées à cette classe
- delete m_pVar;
- m_pVar = NULL;
-
- if (pClass == NULL) return;
-
- CBotVar* pv = pClass->GivVar(); // premier de la liste
- while ( pv != NULL )
- {
- // cherche les dimensions max du tableau
- CBotInstr* p = pv->m_LimExpr; // les différentes formules
- if ( p != NULL )
- {
- CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante
- int n = 0;
- int max[100];
-
- while (p != NULL)
- {
- while( pile->IsOk() && !p->Execute(pile) ) ; // calcul de la taille sans interruptions
- CBotVar* v = pile->GivVar(); // résultat
- max[n] = v->GivValInt(); // valeur
- n++;
- p = p->GivNext3();
- }
- while (n<100) max[n++] = 0;
-
- pv->m_type.SetArray( max ); // mémorise les limitations
- pile->Delete();
- }
-
- CBotVar* pn = CBotVar::Create( pv ); // une copie
- pn->SetStatic(pv->IsStatic());
- pn->SetPrivate(pv->GivPrivate());
-
- if ( pv->m_InitExpr != NULL ) // expression pour l'initialisation ?
- {
-#if STACKMEM
- CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante
-
- while(pile->IsOk() && !pv->m_InitExpr->Execute(pile, pn)); // évalue l'expression sans timer
-
- pile->Delete();
-#else
- CBotStack* pile = new CBotStack(NULL); // une pile indépendante
- while(!pv->m_InitExpr->Execute(pile)); // évalue l'expression sans timer
- pn->SetVal( pile->GivVar() ) ;
- delete pile;
-#endif
- }
-
-// pn->SetUniqNum(CBotVar::NextUniqNum()); // numérote les éléments
- pn->SetUniqNum(pv->GivUniqNum()); //++nIdent
- pn->m_pMyThis = this;
-
- if ( m_pVar == NULL) m_pVar = pn;
- else m_pVar->AddNext( pn );
- pv = pv->GivNext();
- }
-}
-
-CBotClass* CBotVarClass::GivClass()
-{
- return m_pClass;
-}
-
-
-void CBotVarClass::Maj(void* pUser, bool bContinu)
-{
-/* if (!bContinu && m_pMyThis != NULL)
- m_pMyThis->Maj(pUser, true);*/
-
- // une routine de mise à jour existe-elle ?
-
- if ( m_pClass->m_rMaj == NULL ) return;
-
- // récupère le pointeur user selon la classe
- // ou selon le paramètre passé au CBotProgram::Run()
-
- if ( m_pUserPtr != NULL) pUser = m_pUserPtr;
- if ( pUser == OBJECTDELETED ||
- pUser == OBJECTCREATED ) return;
- m_pClass->m_rMaj( this, pUser );
-}
-
-CBotVar* CBotVarClass::GivItem(const char* name)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->GivNext();
- }
-
- if ( m_pParent != NULL ) return m_pParent->GivItem(name);
- return NULL;
-}
-
-CBotVar* CBotVarClass::GivItemRef(int nIdent)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivUniqNum() == nIdent ) return p;
- p = p->GivNext();
- }
-
- if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent);
- return NULL;
-}
-
-// pour la gestion d'un tableau
-// bExtend permet d'agrandir le tableau, mais pas au dela de la taille fixée par SetArray()
-
-CBotVar* CBotVarClass::GivItem(int n, bool bExtend)
-{
- CBotVar* p = m_pVar;
-
- if ( n < 0 ) return NULL;
- if ( n > MAXARRAYSIZE ) return NULL;
-
- if ( m_type.GivLimite() >= 0 && n >= m_type.GivLimite() ) return NULL;
-
- if ( p == NULL && bExtend )
- {
- p = CBotVar::Create("", m_type.GivTypElem());
- m_pVar = p;
- }
-
- if ( n == 0 ) return p;
-
- while ( n-- > 0 )
- {
- if ( p->m_next == NULL )
- {
- if ( bExtend ) p->m_next = CBotVar::Create("", m_type.GivTypElem());
- if ( p->m_next == NULL ) return NULL;
- }
- p = p->m_next;
- }
-
- return p;
-}
-
-CBotVar* CBotVarClass::GivItemList()
-{
- return m_pVar;
-}
-
-
-CBotString CBotVarClass::GivValString()
-{
-// if ( m_Indirect != NULL) return m_Indirect->GivValString();
-
- CBotString res;
-
- if ( m_pClass != NULL ) // pas utilisé pour un array
- {
- res = m_pClass->GivName() + CBotString("( ");
-
- CBotVarClass* my = this;
- while ( my != NULL )
- {
- CBotVar* pv = my->m_pVar;
- while ( pv != NULL )
- {
- res += pv->GivName() + CBotString("=");
-
- if ( pv->IsStatic() )
- {
- CBotVar* pvv = my->m_pClass->GivItem(pv->GivName());
- res += pvv->GivValString();
- }
- else
- {
- res += pv->GivValString();
- }
- pv = pv->GivNext();
- if ( pv != NULL ) res += ", ";
- }
- my = my->m_pParent;
- if ( my != NULL )
- {
- res += ") extends ";
- res += my->m_pClass->GivName();
- res += " (";
- }
- }
- }
- else
- {
- res = "( ";
-
- CBotVar* pv = m_pVar;
- while ( pv != NULL )
- {
- res += pv->GivValString();
- if ( pv->GivNext() != NULL ) res += ", ";
- pv = pv->GivNext();
- }
- }
-
- res += " )";
- return res;
-}
-
-void CBotVarClass::IncrementUse()
-{
- m_CptUse++;
-}
-
-void CBotVarClass::DecrementUse()
-{
- m_CptUse--;
- if ( m_CptUse == 0 )
- {
- // s'il y en a un, appel le destructeur
- // mais seulement si un constructeur avait été appelé.
- if ( m_bConstructor )
- {
- m_CptUse++; // ne revient pas dans le destructeur
-
- // m_error est static dans le stack
- // sauve la valeur pour la remettre ensuite
- int err, start, end;
- CBotStack* pile = NULL;
- err = pile->GivError(start,end); // pile == NULL ça ne derange pas !!
-
- pile = CBotStack::FirstStack(); // efface l'erreur
- CBotVar* ppVars[1];
- ppVars[0] = NULL;
-
- CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer);
- pThis->SetPointer(this);
- CBotVar* pResult = NULL;
-
- CBotString nom = "~" + m_pClass->GivName();
- long ident = 0;
-
- while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, NULL)) ; // attend la fin
-
- pile->ResetError(err, start,end);
-
- pile->Delete();
- delete pThis;
- m_CptUse--;
- }
-
- delete this; // s'auto-détruit !!
- }
-}
-
-CBotVarClass* CBotVarClass::GivPointer()
-{
- return this;
-}
-
-
-// trouve une instance selon son numéro unique
-
-CBotVarClass* CBotVarClass::Find(long id)
-{
- CBotVarClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if ( p->m_ItemIdent == id ) return p;
- p = p->m_ExNext;
- }
-
- return NULL;
-}
-
-bool CBotVarClass::Eq(CBotVar* left, CBotVar* right)
-{
- CBotVar* l = left->GivItemList();
- CBotVar* r = right->GivItemList();
-
- while ( l != NULL && r != NULL )
- {
- if ( l->Ne(l, r) ) return false;
- l = l->GivNext();
- r = r->GivNext();
- }
-
- // devrait toujours arrivé simultanément au bout (mêmes classes)
- return l == r;
-}
-
-bool CBotVarClass::Ne(CBotVar* left, CBotVar* right)
-{
- CBotVar* l = left->GivItemList();
- CBotVar* r = right->GivItemList();
-
- while ( l != NULL && r != NULL )
- {
- if ( l->Ne(l, r) ) return true;
- l = l->GivNext();
- r = r->GivNext();
- }
-
- // devrait toujours arrivé simultanément au bout (mêmes classes)
- return l != r;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// gestion des tableaux de variables
-
-CBotVarArray::CBotVarArray(const CBotToken* name, CBotTypResult& type )
-{
- if ( !type.Eq(CBotTypArrayPointer) &&
- !type.Eq(CBotTypArrayBody)) ASM_TRAP();
-
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
-
- m_type = type;
- m_type.SetType(CBotTypArrayPointer);
- m_binit = false;
-
- m_pInstance = NULL; // la liste des éléments du tableau
-}
-
-CBotVarArray::~CBotVarArray()
-{
- if ( m_pInstance != NULL ) m_pInstance->DecrementUse(); // une référence en moins
-}
-
-// copie une variable dans une autre
-void CBotVarArray::Copy(CBotVar* pSrc, bool bName)
-{
- if ( pSrc->GivType() != CBotTypArrayPointer )
- ASM_TRAP();
-
- CBotVarArray* p = (CBotVarArray*)pSrc;
-
- if ( bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_pInstance = p->GivPointer();
-
- if ( m_pInstance != NULL )
- m_pInstance->IncrementUse(); // une référence en plus
-
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-void CBotVarArray::SetPointer(CBotVar* pVarClass)
-{
- m_binit = true; // init, même sur un pointeur null
-
- if ( m_pInstance == pVarClass) return; // spécial, ne pas décrémenter et réincrémenter
- // car le décrément peut détruire l'object
-
- if ( pVarClass != NULL )
- {
- if ( pVarClass->GivType() == CBotTypArrayPointer )
- pVarClass = pVarClass->GivPointer(); // le vrai pointeur à l'objet
-
- if ( !pVarClass->m_type.Eq(CBotTypClass) &&
- !pVarClass->m_type.Eq(CBotTypArrayBody))
- ASM_TRAP();
-
- ((CBotVarClass*)pVarClass)->IncrementUse(); // une référence en plus
- }
-
- if ( m_pInstance != NULL ) m_pInstance->DecrementUse();
- m_pInstance = (CBotVarClass*)pVarClass;
-}
-
-
-CBotVarClass* CBotVarArray::GivPointer()
-{
- if ( m_pInstance == NULL ) return NULL;
- return m_pInstance->GivPointer();
-}
-
-CBotVar* CBotVarArray::GivItem(int n, bool bExtend)
-{
- if ( m_pInstance == NULL )
- {
- if ( !bExtend ) return NULL;
- // crée une instance pour le tableau
-
- CBotVarClass* instance = new CBotVarClass(NULL, m_type);
- SetPointer( instance );
- }
- return m_pInstance->GivItem(n, bExtend);
-}
-
-CBotVar* CBotVarArray::GivItemList()
-{
- if ( m_pInstance == NULL) return NULL;
- return m_pInstance->GivItemList();
-}
-
-CBotString CBotVarArray::GivValString()
-{
- if ( m_pInstance == NULL ) return ( CBotString( "Null pointer" ) ) ;
- return m_pInstance->GivValString();
-}
-
-bool CBotVarArray::Save1State(FILE* pf)
-{
- if ( !WriteType(pf, m_type) ) return false;
- return SaveVar(pf, m_pInstance); // sauve l'instance qui gère le tableau
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-// gestion des pointeurs à une instance donnée
-
-CBotVarPointer::CBotVarPointer(const CBotToken* name, CBotTypResult& type )
-{
- if ( !type.Eq(CBotTypPointer) &&
- !type.Eq(CBotTypNullPointer) &&
- !type.Eq(CBotTypClass) && // par commodité accepte Class et Intrinsic
- !type.Eq(CBotTypIntrinsic) ) ASM_TRAP();
-
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
-
- m_type = type;
- if ( !type.Eq(CBotTypNullPointer) )
- m_type.SetType(CBotTypPointer); // quoi qu'il en soit, c'est un pointeur
- m_binit = false;
- m_pClass = NULL;
- m_pVarClass = NULL; // sera défini par un SetPointer()
-
- SetClass(type.GivClass() );
-}
-
-CBotVarPointer::~CBotVarPointer()
-{
- if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse(); // une référence en moins
-}
-
-
-void CBotVarPointer::Maj(void* pUser, bool bContinu)
-{
-/* if ( !bContinu && m_pMyThis != NULL )
- m_pMyThis->Maj(pUser, false);*/
-
- if ( m_pVarClass != NULL) m_pVarClass->Maj(pUser, false);
-}
-
-CBotVar* CBotVarPointer::GivItem(const char* name)
-{
- if ( m_pVarClass == NULL) // pas d'instance existant ?
- return m_pClass->GivItem(name); // rend le pointeur dans la classe elle-même
-
- return m_pVarClass->GivItem(name);
-}
-
-CBotVar* CBotVarPointer::GivItemRef(int nIdent)
-{
- if ( m_pVarClass == NULL) // pas d'instance existant ?
- return m_pClass->GivItemRef(nIdent);// rend le pointeur dans la classe elle-même
-
- return m_pVarClass->GivItemRef(nIdent);
-}
-
-CBotVar* CBotVarPointer::GivItemList()
-{
- if ( m_pVarClass == NULL) return NULL;
- return m_pVarClass->GivItemList();
-}
-
-CBotString CBotVarPointer::GivValString()
-{
- CBotString s = "Pointer to ";
- if ( m_pVarClass == NULL ) s = "Null pointer" ;
- else s += m_pVarClass->GivValString();
- return s;
-}
-
-
-void CBotVarPointer::ConstructorSet()
-{
- if ( m_pVarClass != NULL) m_pVarClass->ConstructorSet();
-}
-
-// initialise le pointeur vers l'instance d'une classe
-
-void CBotVarPointer::SetPointer(CBotVar* pVarClass)
-{
- m_binit = true; // init, même sur un pointeur null
-
- if ( m_pVarClass == pVarClass) return; // spécial, ne pas décrémenter et réincrémenter
- // car le décrément peut détruire l'object
-
- if ( pVarClass != NULL )
- {
- if ( pVarClass->GivType() == CBotTypPointer )
- pVarClass = pVarClass->GivPointer(); // le vrai pointeur à l'objet
-
-// if ( pVarClass->GivType() != CBotTypClass )
- if ( !pVarClass->m_type.Eq(CBotTypClass) )
- ASM_TRAP();
-
- ((CBotVarClass*)pVarClass)->IncrementUse(); // une référence en plus
- m_pClass = ((CBotVarClass*)pVarClass)->m_pClass;
- m_pUserPtr = pVarClass->m_pUserPtr; // pas vraiment indispensable
- m_type = CBotTypResult(CBotTypPointer, m_pClass); // un pointeur de quel genre
- }
-
- if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse();
- m_pVarClass = (CBotVarClass*)pVarClass;
-
-}
-
-CBotVarClass* CBotVarPointer::GivPointer()
-{
- if ( m_pVarClass == NULL ) return NULL;
- return m_pVarClass->GivPointer();
-}
-
-void CBotVarPointer::SetIdent(long n)
-{
- if ( m_pVarClass == NULL ) return;
- m_pVarClass->SetIdent( n );
-}
-
-long CBotVarPointer::GivIdent()
-{
- if ( m_pVarClass == NULL ) return 0;
- return m_pVarClass->m_ItemIdent;
-}
-
-
-void CBotVarPointer::SetClass(CBotClass* pClass)
-{
-// int nIdent = 0;
- m_type.m_pClass = m_pClass = pClass;
- if ( m_pVarClass != NULL ) m_pVarClass->SetClass(pClass); //, nIdent);
-}
-
-CBotClass* CBotVarPointer::GivClass()
-{
- if ( m_pVarClass != NULL ) return m_pVarClass->GivClass();
-
- return m_pClass;
-}
-
-
-bool CBotVarPointer::Save1State(FILE* pf)
-{
- if ( m_pClass )
- {
- if (!WriteString(pf, m_pClass->GivName())) return false; // nom de la classe
- }
- else
- {
- if (!WriteString(pf, "")) return false;
- }
-
- if (!WriteLong(pf, GivIdent())) return false; // la référence unique
-
- // sauve aussi une copie de l'instance
- return SaveVar(pf, GivPointer());
-}
-
-// copie une variable dans une autre
-void CBotVarPointer::Copy(CBotVar* pSrc, bool bName)
-{
- if ( pSrc->GivType() != CBotTypPointer &&
- pSrc->GivType() != CBotTypNullPointer)
- ASM_TRAP();
-
- CBotVarPointer* p = (CBotVarPointer*)pSrc;
-
- if ( bName) *m_token = *p->m_token;
- m_type = p->m_type;
-// m_pVarClass = p->m_pVarClass;
- m_pVarClass = p->GivPointer();
-
- if ( m_pVarClass != NULL )
- m_pVarClass->IncrementUse(); // une référence en plus
-
- m_pClass = p->m_pClass;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-bool CBotVarPointer::Eq(CBotVar* left, CBotVar* right)
-{
- CBotVarClass* l = left->GivPointer();
- CBotVarClass* r = right->GivPointer();
-
- if ( l == r ) return true;
- if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return true;
- if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return true;
- return false;
-}
-
-bool CBotVarPointer::Ne(CBotVar* left, CBotVar* right)
-{
- CBotVarClass* l = left->GivPointer();
- CBotVarClass* r = right->GivPointer();
-
- if ( l == r ) return false;
- if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return false;
- if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return false;
- return true;
-}
-
-
-
-///////////////////////////////////////////////////////
-// gestion des types de résultats
-
-
-CBotTypResult::CBotTypResult(int type)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = NULL;
- m_limite = -1;
-}
-
-CBotTypResult::CBotTypResult(int type, const char* name)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = NULL;
- m_limite = -1;
-
- if ( type == CBotTypPointer ||
- type == CBotTypClass ||
- type == CBotTypIntrinsic )
- {
- m_pClass = CBotClass::Find(name);
- if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic;
- }
-}
-
-CBotTypResult::CBotTypResult(int type, CBotClass* pClass)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = pClass;
- m_limite = -1;
-
- if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic;
-}
-
-CBotTypResult::CBotTypResult(int type, CBotTypResult elem)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = NULL;
- m_limite = -1;
-
- if ( type == CBotTypArrayPointer ||
- type == CBotTypArrayBody )
- m_pNext = new CBotTypResult( elem );
-}
-
-CBotTypResult::CBotTypResult(const CBotTypResult& typ)
-{
- m_type = typ.m_type;
- m_pClass = typ.m_pClass;
- m_pNext = NULL;
- m_limite = typ.m_limite;
-
- if ( typ.m_pNext )
- m_pNext = new CBotTypResult( *typ.m_pNext );
-}
-
-CBotTypResult::CBotTypResult()
-{
- m_type = 0;
- m_limite = -1;
- m_pNext = NULL;
- m_pClass = NULL;
-}
-
-CBotTypResult::~CBotTypResult()
-{
- delete m_pNext;
-}
-
-int CBotTypResult::GivType(int mode) const
-{
-#ifdef _DEBUG
- if ( m_type == CBotTypPointer ||
- m_type == CBotTypClass ||
- m_type == CBotTypIntrinsic )
-
- if ( m_pClass == NULL ) ASM_TRAP();
-
-
- if ( m_type == CBotTypArrayPointer )
- if ( m_pNext == NULL ) ASM_TRAP();
-#endif
- if ( mode == 3 && m_type == CBotTypNullPointer ) return CBotTypPointer;
- return m_type;
-}
-
-void CBotTypResult::SetType(int n)
-{
- m_type = n;
-}
-
-CBotClass* CBotTypResult::GivClass() const
-{
- return m_pClass;
-}
-
-CBotTypResult& CBotTypResult::GivTypElem() const
-{
- return *m_pNext;
-}
-
-int CBotTypResult::GivLimite() const
-{
- return m_limite;
-}
-
-void CBotTypResult::SetLimite(int n)
-{
- m_limite = n;
-}
-
-void CBotTypResult::SetArray( int* max )
-{
- m_limite = *max;
- if (m_limite < 1) m_limite = -1;
-
- if ( m_pNext != NULL ) // dernière dimension ?
- {
- m_pNext->SetArray( max+1 );
- }
-}
-
-
-
-bool CBotTypResult::Compare(const CBotTypResult& typ) const
-{
- if ( m_type != typ.m_type ) return false;
-
- if ( m_type == CBotTypArrayPointer ) return m_pNext->Compare(*typ.m_pNext);
-
- if ( m_type == CBotTypPointer ||
- m_type == CBotTypClass ||
- m_type == CBotTypIntrinsic )
- {
- return m_pClass == typ.m_pClass;
- }
-
- return true;
-}
-
-bool CBotTypResult::Eq(int type) const
-{
- return m_type == type;
-}
-
-CBotTypResult&
- CBotTypResult::operator=(const CBotTypResult& src)
-{
- m_type = src.m_type;
- m_limite = src.m_limite;
- m_pClass = src.m_pClass;
- m_pNext = NULL;
- if ( src.m_pNext != NULL )
- {
- m_pNext = new CBotTypResult(*src.m_pNext);
- }
- return *this;
-}
-
-
+// * 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 for the class CBotVar +// variables management of the language CBoT + +// it never creates an instance of the class mother CBotVar + +#include "CBot.h" +#include <math.h> +#include <stdio.h> + +long CBotVar::m_identcpt = 0; + +CBotVar::CBotVar( ) +{ + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = NULL; + m_InitExpr = NULL; + m_LimExpr = NULL; + m_type = -1; + m_binit = false; + m_ident = 0; + m_bStatic = false; + m_mPrivate = 0; +} + +CBotVarInt::CBotVarInt( const CBotToken* name ) +{ + m_token = new CBotToken(name); + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = NULL; + m_InitExpr = NULL; + m_LimExpr = NULL; + m_type = CBotTypInt; + m_binit = false; + m_bStatic = false; + m_mPrivate = 0; + + m_val = 0; +} + +CBotVarFloat::CBotVarFloat( const CBotToken* name ) +{ + m_token = new CBotToken(name); + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = NULL; + m_InitExpr = NULL; + m_LimExpr = NULL; + m_type = CBotTypFloat; + m_binit = false; + m_bStatic = false; + m_mPrivate = 0; + + m_val = 0; +} + +CBotVarString::CBotVarString( const CBotToken* name ) +{ + m_token = new CBotToken(name); + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = NULL; + m_InitExpr = NULL; + m_LimExpr = NULL; + m_type = CBotTypString; + m_binit = false; + m_bStatic = false; + m_mPrivate = 0; + + m_val.Empty(); +} + +CBotVarBoolean::CBotVarBoolean( const CBotToken* name ) +{ + m_token = new CBotToken(name); + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = NULL; + m_InitExpr = NULL; + m_LimExpr = NULL; + m_type = CBotTypBoolean; + m_binit = false; + m_bStatic = false; + m_mPrivate = 0; + + m_val = 0; +} + +CBotVarClass* CBotVarClass::m_ExClass = NULL; + +CBotVarClass::CBotVarClass( const CBotToken* name, const CBotTypResult& type) +{ +/* +// int nIdent = 0; + InitCBotVarClass( name, type ) //, nIdent ); +} + +CBotVarClass::CBotVarClass( const CBotToken* name, CBotTypResult& type) //, int &nIdent ) +{ + InitCBotVarClass( name, type ); //, nIdent ); +} + +void CBotVarClass::InitCBotVarClass( const CBotToken* name, CBotTypResult& type ) //, int &nIdent ) +{*/ + if ( !type.Eq(CBotTypClass) && + !type.Eq(CBotTypIntrinsic) && // by convenience there accepts these types + !type.Eq(CBotTypPointer) && + !type.Eq(CBotTypArrayPointer) && + !type.Eq(CBotTypArrayBody)) ASM_TRAP(); + + m_token = new CBotToken(name); + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = OBJECTCREATED;//NULL; + m_InitExpr = NULL; + m_LimExpr = NULL; + m_pVar = NULL; + m_type = type; + if ( type.Eq(CBotTypArrayPointer) ) m_type.SetType( CBotTypArrayBody ); + else if ( !type.Eq(CBotTypArrayBody) ) m_type.SetType( CBotTypClass ); + // officel type for this object + + m_pClass = NULL; + m_pParent = NULL; + m_binit = false; + m_bStatic = false; + m_mPrivate = 0; + m_bConstructor = false; + m_CptUse = 0; + m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum(); + + // se place tout seul dans la liste + // TODO stands alone in the list (stands only in a list) + if (m_ExClass) m_ExClass->m_ExPrev = this; + m_ExNext = m_ExClass; + m_ExPrev = NULL; + m_ExClass = this; + + CBotClass* pClass = type.GivClass(); + CBotClass* pClass2 = pClass->GivParent(); + if ( pClass2 != NULL ) + { + // also creates an instance of the parent class + m_pParent = new CBotVarClass(name, CBotTypResult(type.GivType(),pClass2) ); //, nIdent); + } + + SetClass( pClass ); //, nIdent ); + +} + +CBotVarClass::~CBotVarClass( ) +{ + if ( m_CptUse != 0 ) + ASM_TRAP(); + + if ( m_pParent ) delete m_pParent; + m_pParent = NULL; + + // frees the indirect object if necessary +// if ( m_Indirect != NULL ) +// m_Indirect->DecrementUse(); + + // removes the class list + if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext; + else m_ExClass = m_ExNext; + + if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev; + m_ExPrev = NULL; + m_ExNext = NULL; + + delete m_pVar; +} + +void CBotVarClass::ConstructorSet() +{ + m_bConstructor = true; +} + + +CBotVar::~CBotVar( ) +{ + delete m_token; + delete m_next; +} + +void CBotVar::debug() +{ + const char* p = (const char*) m_token->GivString(); + CBotString s = (const char*) GivValString(); + const char* v = (const char*) s; + + if ( m_type.Eq(CBotTypClass) ) + { + CBotVar* pv = ((CBotVarClass*)this)->m_pVar; + while (pv != NULL) + { + pv->debug(); + pv = pv->GivNext(); + } + } +} + +void CBotVar::ConstructorSet() +{ + // nop +} + +void CBotVar::SetUserPtr(void* pUser) +{ + m_pUserPtr = pUser; + if (m_type.Eq(CBotTypPointer) && + ((CBotVarPointer*)this)->m_pVarClass != NULL ) + ((CBotVarPointer*)this)->m_pVarClass->SetUserPtr(pUser); +} + +void CBotVar::SetIdent(long n) +{ + if (m_type.Eq(CBotTypPointer) && + ((CBotVarPointer*)this)->m_pVarClass != NULL ) + ((CBotVarPointer*)this)->m_pVarClass->SetIdent(n); +} + +void CBotVar::SetUniqNum(long n) +{ + m_ident = n; + + if ( n == 0 ) ASM_TRAP(); +} + +long CBotVar::NextUniqNum() +{ + if (++m_identcpt < 10000) m_identcpt = 10000; + return m_identcpt; +} + +long CBotVar::GivUniqNum() +{ + return m_ident; +} + + +void* CBotVar::GivUserPtr() +{ + return m_pUserPtr; +} + +bool CBotVar::Save1State(FILE* pf) +{ + // this routine "virtual" must never be called, + // there must be a routine for each of the subclasses (CBotVarInt, CBotVarFloat, etc) + // ( see the type in m_type ) + ASM_TRAP(); + return false; +} + +void CBotVar::Maj(void* pUser, bool bContinu) +{ +/* if (!bContinu && m_pMyThis != NULL) + m_pMyThis->Maj(pUser, true);*/ +} + + +// creates a variable depending on its type + +CBotVar* CBotVar::Create(const CBotToken* name, int type ) +{ + CBotTypResult t(type); + return Create(name, t); +} + +CBotVar* CBotVar::Create(const CBotToken* name, CBotTypResult type) +{ + switch (type.GivType()) + { + case CBotTypShort: + case CBotTypInt: + return new CBotVarInt(name); + case CBotTypFloat: + return new CBotVarFloat(name); + case CBotTypBoolean: + return new CBotVarBoolean(name); + case CBotTypString: + return new CBotVarString(name); + case CBotTypPointer: + case CBotTypNullPointer: + return new CBotVarPointer(name, type); + case CBotTypIntrinsic: + return new CBotVarClass(name, type); + + case CBotTypClass: + // creates a new instance of a class + // and returns the POINTER on this instance + { + CBotVarClass* instance = new CBotVarClass(name, type); + CBotVarPointer* pointer = new CBotVarPointer(name, type); + pointer->SetPointer( instance ); + return pointer; + } + + case CBotTypArrayPointer: + return new CBotVarArray(name, type); + + case CBotTypArrayBody: + { + CBotVarClass* instance = new CBotVarClass(name, type); + CBotVarArray* array = new CBotVarArray(name, type); + array->SetPointer( instance ); + + CBotVar* pv = array; + while (type.Eq(CBotTypArrayBody)) + { + type = type.GivTypElem(); + pv = ((CBotVarArray*)pv)->GivItem(0, true); // creates at least the element [0] + } + + return array; + } + } + + ASM_TRAP(); + return NULL; +} + +CBotVar* CBotVar::Create( CBotVar* pVar ) +{ + CBotVar* p = Create(pVar->m_token->GivString(), pVar->GivTypResult(2)); + return p; +} + + +CBotVar* CBotVar::Create( const char* n, CBotTypResult type) +{ + CBotToken name(n); + + switch (type.GivType()) + { + case CBotTypShort: + case CBotTypInt: + return new CBotVarInt(&name); + case CBotTypFloat: + return new CBotVarFloat(&name); + case CBotTypBoolean: + return new CBotVarBoolean(&name); + case CBotTypString: + return new CBotVarString(&name); + case CBotTypPointer: + case CBotTypNullPointer: + { + CBotVarPointer* p = new CBotVarPointer(&name, type); +// p->SetClass(type.GivClass()); + return p; + } + case CBotTypIntrinsic: + { + CBotVarClass* p = new CBotVarClass(&name, type); +// p->SetClass(type.GivClass()); + return p; + } + + case CBotTypClass: + // creates a new instance of a class + // and returns the POINTER on this instance + { + CBotVarClass* instance = new CBotVarClass(&name, type); + CBotVarPointer* pointer = new CBotVarPointer(&name, type); + pointer->SetPointer( instance ); +// pointer->SetClass( type.GivClass() ); + return pointer; + } + + case CBotTypArrayPointer: + return new CBotVarArray(&name, type); + + case CBotTypArrayBody: + { + CBotVarClass* instance = new CBotVarClass(&name, type); + CBotVarArray* array = new CBotVarArray(&name, type); + array->SetPointer( instance ); + + CBotVar* pv = array; + while (type.Eq(CBotTypArrayBody)) + { + type = type.GivTypElem(); + pv = ((CBotVarArray*)pv)->GivItem(0, true); // creates at least the element [0] + } + + return array; + } + } + + ASM_TRAP(); + return NULL; +} + +CBotVar* CBotVar::Create( const char* name, int type, CBotClass* pClass) +{ + CBotToken token( name, "" ); + CBotVar* pVar = Create( &token, type ); + + if ( type == CBotTypPointer && pClass == NULL ) // pointer "null" ? + return pVar; + + if ( type == CBotTypClass || type == CBotTypPointer || + type == CBotTypIntrinsic ) + { + if (pClass == NULL) + { + delete pVar; + return NULL; + } + pVar->SetClass( pClass ); + } + return pVar; +} + +CBotVar* CBotVar::Create( const char* name, CBotClass* pClass) +{ + CBotToken token( name, "" ); + CBotVar* pVar = Create( &token, CBotTypResult( CBotTypClass, pClass ) ); +// pVar->SetClass( pClass ); + return pVar; +} + +CBotTypResult CBotVar::GivTypResult(int mode) +{ + CBotTypResult r = m_type; + + if ( mode == 1 && m_type.Eq(CBotTypClass) ) + r.SetType(CBotTypPointer); + if ( mode == 2 && m_type.Eq(CBotTypClass) ) + r.SetType(CBotTypIntrinsic); + + return r; +} + +int CBotVar::GivType(int mode) +{ + if ( mode == 1 && m_type.Eq(CBotTypClass) ) + return CBotTypPointer; + if ( mode == 2 && m_type.Eq(CBotTypClass) ) + return CBotTypIntrinsic; + return m_type.GivType(); +} + +void CBotVar::SetType(CBotTypResult& type) +{ + m_type = type; +} + + +int CBotVar::GivInit() +{ + if ( m_type.Eq(CBotTypClass) ) return IS_DEF; // always set! + + return m_binit; +} + +void CBotVar::SetInit(int bInit) +{ + m_binit = bInit; + if ( bInit == 2 ) m_binit = IS_DEF; // cas spécial + + if ( m_type.Eq(CBotTypPointer) && bInit == 2 ) + { + CBotVarClass* instance = GivPointer(); + if ( instance == NULL ) + { + instance = new CBotVarClass(NULL, m_type); +// instance->SetClass(((CBotVarPointer*)this)->m_pClass); + SetPointer(instance); + } + instance->SetInit(1); + } + + if ( m_type.Eq(CBotTypClass) || m_type.Eq(CBotTypIntrinsic) ) + { + CBotVar* p = ((CBotVarClass*)this)->m_pVar; + while( p != NULL ) + { + p->SetInit( bInit ); + p->m_pMyThis = (CBotVarClass*)this; + p = p->GivNext(); + } + } +} + +CBotString CBotVar::GivName() +{ + return m_token->GivString(); +} + +void CBotVar::SetName(const char* name) +{ + m_token->SetString(name); +} + +CBotToken* CBotVar::GivToken() +{ + return m_token; +} + +CBotVar* CBotVar::GivItem(const char* name) +{ + ASM_TRAP(); + return NULL; +} + +CBotVar* CBotVar::GivItemRef(int nIdent) +{ + ASM_TRAP(); + return NULL; +} + +CBotVar* CBotVar::GivItemList() +{ + ASM_TRAP(); + return NULL; +} + +CBotVar* CBotVar::GivItem(int row, bool bGrow) +{ + ASM_TRAP(); + return NULL; +} + +// check if a variable belongs to a given class +bool CBotVar::IsElemOfClass(const char* name) +{ + CBotClass* pc = NULL; + + if ( m_type.Eq(CBotTypPointer) ) + { + pc = ((CBotVarPointer*)this)->m_pClass; + } + if ( m_type.Eq(CBotTypClass) ) + { + pc = ((CBotVarClass*)this)->m_pClass; + } + + while ( pc != NULL ) + { + if ( pc->GivName() == name ) return true; + pc = pc->GivParent(); + } + + return false; +} + + +CBotVar* CBotVar::GivStaticVar() +{ + // makes the pointer to the variable if it is static + if ( m_bStatic == 0 || m_pMyThis == NULL ) return this; + + CBotClass* pClass = m_pMyThis->GivClass(); + return pClass->GivItem( m_token->GivString() ); +} + + +CBotVar* CBotVar::GivNext() +{ + return m_next; +} + +void CBotVar::AddNext(CBotVar* pVar) +{ + CBotVar* p = this; + while (p->m_next != NULL) p = p->m_next; + + p->m_next = pVar; +} + +void CBotVar::SetVal(CBotVar* var) +{ + switch (/*var->*/GivType()) + { + case CBotTypBoolean: + SetValInt(var->GivValInt()); + break; + case CBotTypInt: + SetValInt(var->GivValInt(), ((CBotVarInt*)var)->m_defnum); + break; + case CBotTypFloat: + SetValFloat(var->GivValFloat()); + break; + case CBotTypString: + SetValString(var->GivValString()); + break; + case CBotTypPointer: + case CBotTypNullPointer: + case CBotTypArrayPointer: + SetPointer(var->GivPointer()); + break; + case CBotTypClass: + { + delete ((CBotVarClass*)this)->m_pVar; + ((CBotVarClass*)this)->m_pVar = NULL; + Copy(var, false); + } + break; + default: + ASM_TRAP(); + } + + m_binit = var->m_binit; // copie l'état nan s'il y a +} + +void CBotVar::SetStatic(bool bStatic) +{ + m_bStatic = bStatic; +} + +void CBotVar::SetPrivate(int mPrivate) +{ + m_mPrivate = mPrivate; +} + +bool CBotVar::IsStatic() +{ + return m_bStatic; +} + +bool CBotVar::IsPrivate(int mode) +{ + return m_mPrivate >= mode; +} + +int CBotVar::GivPrivate() +{ + return m_mPrivate; +} + + +void CBotVar::SetPointer(CBotVar* pVarClass) +{ + ASM_TRAP(); +} + +CBotVarClass* CBotVar::GivPointer() +{ + ASM_TRAP(); + return NULL; +} + +// All these functions must be defined in the subclasses +// derived from class CBotVar + +int CBotVar::GivValInt() +{ + ASM_TRAP(); + return 0; +} + +float CBotVar::GivValFloat() +{ + ASM_TRAP(); + return 0; +} + +void CBotVar::SetValInt(int c, const char* s) +{ + ASM_TRAP(); +} + +void CBotVar::SetValFloat(float c) +{ + ASM_TRAP(); +} + +void CBotVar::Mul(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::Power(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +int CBotVar::Div(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return 0; +} + +int CBotVar::Modulo(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return 0; +} + +void CBotVar::Add(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::Sub(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +bool CBotVar::Lo(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return false; +} + +bool CBotVar::Hi(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return false; +} + +bool CBotVar::Ls(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return false; +} + +bool CBotVar::Hs(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return false; +} + +bool CBotVar::Eq(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return false; +} + +bool CBotVar::Ne(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); + return false; +} + +void CBotVar::And(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::Or(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::XOr(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::ASR(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::SR(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::SL(CBotVar* left, CBotVar* right) +{ + ASM_TRAP(); +} + +void CBotVar::Neg() +{ + ASM_TRAP(); +} + +void CBotVar::Not() +{ + ASM_TRAP(); +} + +void CBotVar::Inc() +{ + ASM_TRAP(); +} +void CBotVar::Dec() +{ + ASM_TRAP(); +} + +void CBotVar::Copy(CBotVar* pSrc, bool bName) +{ + ASM_TRAP(); +} + +void CBotVar::SetValString(const char* p) +{ + ASM_TRAP(); +} + +CBotString CBotVar::GivValString() +{ + ASM_TRAP(); + return CBotString(); +} + +void CBotVar::SetClass(CBotClass* pClass) +{ + ASM_TRAP(); +} + +CBotClass* CBotVar::GivClass() +{ + ASM_TRAP(); + return NULL; +} + +/* +void CBotVar::SetIndirection(CBotVar* pVar) +{ + // nop, only CBotVarPointer::SetIndirection +} +*/ + +////////////////////////////////////////////////////////////////////////////////////// + +// copy a variable in to another +void CBotVarInt::Copy(CBotVar* pSrc, bool bName) +{ + CBotVarInt* p = (CBotVarInt*)pSrc; + + if ( bName) *m_token = *p->m_token; + m_type = p->m_type; + m_val = p->m_val; + m_binit = p->m_binit; + m_pMyThis = NULL; + m_pUserPtr = p->m_pUserPtr; + + // identificator is the same (by défaut) + if (m_ident == 0 ) m_ident = p->m_ident; + + m_defnum = p->m_defnum; +} + + + + +void CBotVarInt::SetValInt(int val, const char* defnum) +{ + m_val = val; + m_binit = true; + m_defnum = defnum; +} + + + +void CBotVarInt::SetValFloat(float val) +{ + m_val = (int)val; + m_binit = true; +} + +int CBotVarInt::GivValInt() +{ + return m_val; +} + +float CBotVarInt::GivValFloat() +{ + return (float)m_val; +} + +CBotString CBotVarInt::GivValString() +{ + if ( !m_defnum.IsEmpty() ) return m_defnum; + + CBotString res; + + if ( !m_binit ) + { + res.LoadString(TX_UNDEF); + return res; + } + if ( m_binit == IS_NAN ) + { + res.LoadString(TX_NAN); + return res; + } + + char buffer[300]; + sprintf(buffer, "%d", m_val); + res = buffer; + + return res; +} + + +void CBotVarInt::Mul(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() * right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::Power(CBotVar* left, CBotVar* right) +{ + m_val = (int) pow( (double) left->GivValInt() , (double) right->GivValInt() ); + m_binit = true; +} + +int CBotVarInt::Div(CBotVar* left, CBotVar* right) +{ + int r = right->GivValInt(); + if ( r != 0 ) + { + m_val = left->GivValInt() / r; + m_binit = true; + } + return ( r == 0 ? TX_DIVZERO : 0 ); +} + +int CBotVarInt::Modulo(CBotVar* left, CBotVar* right) +{ + int r = right->GivValInt(); + if ( r != 0 ) + { + m_val = left->GivValInt() % r; + m_binit = true; + } + return ( r == 0 ? TX_DIVZERO : 0 ); +} + +void CBotVarInt::Add(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() + right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::Sub(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() - right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::XOr(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() ^ right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::And(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() & right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::Or(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() | right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::SL(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() << right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::ASR(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() >> right->GivValInt(); + m_binit = true; +} + +void CBotVarInt::SR(CBotVar* left, CBotVar* right) +{ + int source = left->GivValInt(); + int shift = right->GivValInt(); + if (shift>=1) source &= 0x7fffffff; + m_val = source >> shift; + m_binit = true; +} + +void CBotVarInt::Neg() +{ + m_val = -m_val; +} + +void CBotVarInt::Not() +{ + m_val = ~m_val; +} + +void CBotVarInt::Inc() +{ + m_val++; + m_defnum.Empty(); +} + +void CBotVarInt::Dec() +{ + m_val--; + m_defnum.Empty(); +} + +bool CBotVarInt::Lo(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() < right->GivValInt(); +} + +bool CBotVarInt::Hi(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() > right->GivValInt(); +} + +bool CBotVarInt::Ls(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() <= right->GivValInt(); +} + +bool CBotVarInt::Hs(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() >= right->GivValInt(); +} + +bool CBotVarInt::Eq(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() == right->GivValInt(); +} + +bool CBotVarInt::Ne(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() != right->GivValInt(); +} + + +////////////////////////////////////////////////////////////////////////////////////// + +// copy a variable into another +void CBotVarFloat::Copy(CBotVar* pSrc, bool bName) +{ + CBotVarFloat* p = (CBotVarFloat*)pSrc; + + if (bName) *m_token = *p->m_token; + m_type = p->m_type; + m_val = p->m_val; + m_binit = p->m_binit; +//- m_bStatic = p->m_bStatic; + m_next = NULL; + m_pMyThis = NULL;//p->m_pMyThis; + m_pUserPtr = p->m_pUserPtr; + + // keeps indentificator the same (by default) + if (m_ident == 0 ) m_ident = p->m_ident; +} + + + + +void CBotVarFloat::SetValInt(int val, const char* s) +{ + m_val = (float)val; + m_binit = true; +} + +void CBotVarFloat::SetValFloat(float val) +{ + m_val = val; + m_binit = true; +} + +int CBotVarFloat::GivValInt() +{ + return (int)m_val; +} + +float CBotVarFloat::GivValFloat() +{ + return m_val; +} + +CBotString CBotVarFloat::GivValString() +{ + CBotString res; + + if ( !m_binit ) + { + res.LoadString(TX_UNDEF); + return res; + } + if ( m_binit == IS_NAN ) + { + res.LoadString(TX_NAN); + return res; + } + + char buffer[300]; + sprintf(buffer, "%.2f", m_val); + res = buffer; + + return res; +} + + +void CBotVarFloat::Mul(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValFloat() * right->GivValFloat(); + m_binit = true; +} + +void CBotVarFloat::Power(CBotVar* left, CBotVar* right) +{ + m_val = (float)pow( left->GivValFloat() , right->GivValFloat() ); + m_binit = true; +} + +int CBotVarFloat::Div(CBotVar* left, CBotVar* right) +{ + float r = right->GivValFloat(); + if ( r != 0 ) + { + m_val = left->GivValFloat() / r; + m_binit = true; + } + return ( r == 0 ? TX_DIVZERO : 0 ); +} + +int CBotVarFloat::Modulo(CBotVar* left, CBotVar* right) +{ + float r = right->GivValFloat(); + if ( r != 0 ) + { + m_val = (float)fmod( left->GivValFloat() , r ); + m_binit = true; + } + return ( r == 0 ? TX_DIVZERO : 0 ); +} + +void CBotVarFloat::Add(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValFloat() + right->GivValFloat(); + m_binit = true; +} + +void CBotVarFloat::Sub(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValFloat() - right->GivValFloat(); + m_binit = true; +} + +void CBotVarFloat::Neg() +{ + m_val = -m_val; +} + +void CBotVarFloat::Inc() +{ + m_val++; +} + +void CBotVarFloat::Dec() +{ + m_val--; +} + + +bool CBotVarFloat::Lo(CBotVar* left, CBotVar* right) +{ + return left->GivValFloat() < right->GivValFloat(); +} + +bool CBotVarFloat::Hi(CBotVar* left, CBotVar* right) +{ + return left->GivValFloat() > right->GivValFloat(); +} + +bool CBotVarFloat::Ls(CBotVar* left, CBotVar* right) +{ + return left->GivValFloat() <= right->GivValFloat(); +} + +bool CBotVarFloat::Hs(CBotVar* left, CBotVar* right) +{ + return left->GivValFloat() >= right->GivValFloat(); +} + +bool CBotVarFloat::Eq(CBotVar* left, CBotVar* right) +{ + return left->GivValFloat() == right->GivValFloat(); +} + +bool CBotVarFloat::Ne(CBotVar* left, CBotVar* right) +{ + return left->GivValFloat() != right->GivValFloat(); +} + + +////////////////////////////////////////////////////////////////////////////////////// + +// copy a variable into another +void CBotVarBoolean::Copy(CBotVar* pSrc, bool bName) +{ + CBotVarBoolean* p = (CBotVarBoolean*)pSrc; + + if (bName) *m_token = *p->m_token; + m_type = p->m_type; + m_val = p->m_val; + m_binit = p->m_binit; +//- m_bStatic = p->m_bStatic; + m_next = NULL; + m_pMyThis = NULL;//p->m_pMyThis; + m_pUserPtr = p->m_pUserPtr; + + // keeps indentificator the same (by default) + if (m_ident == 0 ) m_ident = p->m_ident; +} + + + + +void CBotVarBoolean::SetValInt(int val, const char* s) +{ + m_val = (bool)val; + m_binit = true; +} + +void CBotVarBoolean::SetValFloat(float val) +{ + m_val = (bool)val; + m_binit = true; +} + +int CBotVarBoolean::GivValInt() +{ + return m_val; +} + +float CBotVarBoolean::GivValFloat() +{ + return (float)m_val; +} + +CBotString CBotVarBoolean::GivValString() +{ + CBotString ret; + + CBotString res; + + if ( !m_binit ) + { + res.LoadString(TX_UNDEF); + return res; + } + if ( m_binit == IS_NAN ) + { + res.LoadString(TX_NAN); + return res; + } + + ret.LoadString( m_val > 0 ? ID_TRUE : ID_FALSE ); + return ret; +} + +void CBotVarBoolean::And(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() && right->GivValInt(); + m_binit = true; +} +void CBotVarBoolean::Or(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() || right->GivValInt(); + m_binit = true; +} + +void CBotVarBoolean::XOr(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValInt() ^ right->GivValInt(); + m_binit = true; +} + +void CBotVarBoolean::Not() +{ + m_val = m_val ? false : true ; +} + +bool CBotVarBoolean::Eq(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() == right->GivValInt(); +} + +bool CBotVarBoolean::Ne(CBotVar* left, CBotVar* right) +{ + return left->GivValInt() != right->GivValInt(); +} + +////////////////////////////////////////////////////////////////////////////////////// + +// copy a variable into another +void CBotVarString::Copy(CBotVar* pSrc, bool bName) +{ + CBotVarString* p = (CBotVarString*)pSrc; + + if (bName) *m_token = *p->m_token; + m_type = p->m_type; + m_val = p->m_val; + m_binit = p->m_binit; +//- m_bStatic = p->m_bStatic; + m_next = NULL; + m_pMyThis = NULL;//p->m_pMyThis; + m_pUserPtr = p->m_pUserPtr; + + // keeps indentificator the same (by default) + if (m_ident == 0 ) m_ident = p->m_ident; +} + + +void CBotVarString::SetValString(const char* p) +{ + m_val = p; + m_binit = true; +} + +CBotString CBotVarString::GivValString() +{ + if ( !m_binit ) + { + CBotString res; + res.LoadString(TX_UNDEF); + return res; + } + if ( m_binit == IS_NAN ) + { + CBotString res; + res.LoadString(TX_NAN); + return res; + } + + return m_val; +} + + +void CBotVarString::Add(CBotVar* left, CBotVar* right) +{ + m_val = left->GivValString() + right->GivValString(); + m_binit = true; +} + +bool CBotVarString::Eq(CBotVar* left, CBotVar* right) +{ + return (left->GivValString() == right->GivValString()); +} + +bool CBotVarString::Ne(CBotVar* left, CBotVar* right) +{ + return (left->GivValString() != right->GivValString()); +} + + +bool CBotVarString::Lo(CBotVar* left, CBotVar* right) +{ + return (left->GivValString() == right->GivValString()); +} + +bool CBotVarString::Hi(CBotVar* left, CBotVar* right) +{ + return (left->GivValString() == right->GivValString()); +} + +bool CBotVarString::Ls(CBotVar* left, CBotVar* right) +{ + return (left->GivValString() == right->GivValString()); +} + +bool CBotVarString::Hs(CBotVar* left, CBotVar* right) +{ + return (left->GivValString() == right->GivValString()); +} + + +//////////////////////////////////////////////////////////////// + +// copy a variable into another +void CBotVarClass::Copy(CBotVar* pSrc, bool bName) +{ + pSrc = pSrc->GivPointer(); // if source given by a pointer + + if ( pSrc->GivType() != CBotTypClass ) + ASM_TRAP(); + + CBotVarClass* p = (CBotVarClass*)pSrc; + + if (bName) *m_token = *p->m_token; + + m_type = p->m_type; + m_binit = p->m_binit; +//- m_bStatic = p->m_bStatic; + m_pClass = p->m_pClass; + if ( p->m_pParent ) + { + ASM_TRAP(); "que faire du pParent"; + } + +// m_next = NULL; + m_pUserPtr = p->m_pUserPtr; + m_pMyThis = NULL;//p->m_pMyThis; + m_ItemIdent = p->m_ItemIdent; + + // keeps indentificator the same (by default) + if (m_ident == 0 ) m_ident = p->m_ident; + + delete m_pVar; + m_pVar = NULL; + + CBotVar* pv = p->m_pVar; + while( pv != NULL ) + { + CBotVar* pn = CBotVar::Create(pv); + pn->Copy( pv ); + if ( m_pVar == NULL ) m_pVar = pn; + else m_pVar->AddNext(pn); + + pv = pv->GivNext(); + } +} + +void CBotVarClass::SetItemList(CBotVar* pVar) +{ + delete m_pVar; + m_pVar = pVar; // replaces the existing pointer +} + +void CBotVarClass::SetIdent(long n) +{ + m_ItemIdent = n; +} + +void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent) +{ + m_type.m_pClass = pClass; + + if ( m_pClass == pClass ) return; + + m_pClass = pClass; + + // initializes the variables associated with this class + delete m_pVar; + m_pVar = NULL; + + if (pClass == NULL) return; + + CBotVar* pv = pClass->GivVar(); // first on a list + while ( pv != NULL ) + { + // seeks the maximum dimensions of the table + CBotInstr* p = pv->m_LimExpr; // the different formulas + if ( p != NULL ) + { + CBotStack* pile = CBotStack::FirstStack(); // an independent stack + int n = 0; + int max[100]; + + while (p != NULL) + { + while( pile->IsOk() && !p->Execute(pile) ) ; // calculate size without interruptions + CBotVar* v = pile->GivVar(); // result + max[n] = v->GivValInt(); // value + n++; + p = p->GivNext3(); + } + while (n<100) max[n++] = 0; + + pv->m_type.SetArray( max ); // stores the limitations + pile->Delete(); + } + + CBotVar* pn = CBotVar::Create( pv ); // a copy + pn->SetStatic(pv->IsStatic()); + pn->SetPrivate(pv->GivPrivate()); + + if ( pv->m_InitExpr != NULL ) // expression for initialization? + { +#if STACKMEM + CBotStack* pile = CBotStack::FirstStack(); // an independent stack + + while(pile->IsOk() && !pv->m_InitExpr->Execute(pile, pn)); // evaluates the expression without timer + + pile->Delete(); +#else + CBotStack* pile = new CBotStack(NULL); // an independent stack + while(!pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer + pn->SetVal( pile->GivVar() ) ; + delete pile; +#endif + } + +// pn->SetUniqNum(CBotVar::NextUniqNum()); // enumerate elements + pn->SetUniqNum(pv->GivUniqNum()); //++nIdent + pn->m_pMyThis = this; + + if ( m_pVar == NULL) m_pVar = pn; + else m_pVar->AddNext( pn ); + pv = pv->GivNext(); + } +} + +CBotClass* CBotVarClass::GivClass() +{ + return m_pClass; +} + + +void CBotVarClass::Maj(void* pUser, bool bContinu) +{ +/* if (!bContinu && m_pMyThis != NULL) + m_pMyThis->Maj(pUser, true);*/ + + // an update routine exist? + + if ( m_pClass->m_rMaj == NULL ) return; + + // retrieves the user pointer according to the class + // or according to the parameter passed to CBotProgram::Run() + + if ( m_pUserPtr != NULL) pUser = m_pUserPtr; + if ( pUser == OBJECTDELETED || + pUser == OBJECTCREATED ) return; + m_pClass->m_rMaj( this, pUser ); +} + +CBotVar* CBotVarClass::GivItem(const char* name) +{ + CBotVar* p = m_pVar; + + while ( p != NULL ) + { + if ( p->GivName() == name ) return p; + p = p->GivNext(); + } + + if ( m_pParent != NULL ) return m_pParent->GivItem(name); + return NULL; +} + +CBotVar* CBotVarClass::GivItemRef(int nIdent) +{ + CBotVar* p = m_pVar; + + while ( p != NULL ) + { + if ( p->GivUniqNum() == nIdent ) return p; + p = p->GivNext(); + } + + if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent); + return NULL; +} + +// for the management of an array +// bExtend can enlarge the table, but not beyond the threshold size of SetArray () + +CBotVar* CBotVarClass::GivItem(int n, bool bExtend) +{ + CBotVar* p = m_pVar; + + if ( n < 0 ) return NULL; + if ( n > MAXARRAYSIZE ) return NULL; + + if ( m_type.GivLimite() >= 0 && n >= m_type.GivLimite() ) return NULL; + + if ( p == NULL && bExtend ) + { + p = CBotVar::Create("", m_type.GivTypElem()); + m_pVar = p; + } + + if ( n == 0 ) return p; + + while ( n-- > 0 ) + { + if ( p->m_next == NULL ) + { + if ( bExtend ) p->m_next = CBotVar::Create("", m_type.GivTypElem()); + if ( p->m_next == NULL ) return NULL; + } + p = p->m_next; + } + + return p; +} + +CBotVar* CBotVarClass::GivItemList() +{ + return m_pVar; +} + + +CBotString CBotVarClass::GivValString() +{ +// if ( m_Indirect != NULL) return m_Indirect->GivValString(); + + CBotString res; + + if ( m_pClass != NULL ) // not used for an array + { + res = m_pClass->GivName() + CBotString("( "); + + CBotVarClass* my = this; + while ( my != NULL ) + { + CBotVar* pv = my->m_pVar; + while ( pv != NULL ) + { + res += pv->GivName() + CBotString("="); + + if ( pv->IsStatic() ) + { + CBotVar* pvv = my->m_pClass->GivItem(pv->GivName()); + res += pvv->GivValString(); + } + else + { + res += pv->GivValString(); + } + pv = pv->GivNext(); + if ( pv != NULL ) res += ", "; + } + my = my->m_pParent; + if ( my != NULL ) + { + res += ") extends "; + res += my->m_pClass->GivName(); + res += " ("; + } + } + } + else + { + res = "( "; + + CBotVar* pv = m_pVar; + while ( pv != NULL ) + { + res += pv->GivValString(); + if ( pv->GivNext() != NULL ) res += ", "; + pv = pv->GivNext(); + } + } + + res += " )"; + return res; +} + +void CBotVarClass::IncrementUse() +{ + m_CptUse++; +} + +void CBotVarClass::DecrementUse() +{ + m_CptUse--; + if ( m_CptUse == 0 ) + { + // if there is one, call the destructor + // but only if a constructor had been called. + if ( m_bConstructor ) + { + m_CptUse++; // does not return to the destructor + + // m_error is static in the stack + // saves the value for return + int err, start, end; + CBotStack* pile = NULL; + err = pile->GivError(start,end); // stack == NULL it does not bother! + + pile = CBotStack::FirstStack(); // clears the error + CBotVar* ppVars[1]; + ppVars[0] = NULL; + + CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer); + pThis->SetPointer(this); + CBotVar* pResult = NULL; + + CBotString nom = "~" + m_pClass->GivName(); + long ident = 0; + + while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, NULL)) ; // waits for the end + + pile->ResetError(err, start,end); + + pile->Delete(); + delete pThis; + m_CptUse--; + } + + delete this; // self-destructs! + } +} + +CBotVarClass* CBotVarClass::GivPointer() +{ + return this; +} + + +// makes an instance according to its unique number + +CBotVarClass* CBotVarClass::Find(long id) +{ + CBotVarClass* p = m_ExClass; + + while ( p != NULL ) + { + if ( p->m_ItemIdent == id ) return p; + p = p->m_ExNext; + } + + return NULL; +} + +bool CBotVarClass::Eq(CBotVar* left, CBotVar* right) +{ + CBotVar* l = left->GivItemList(); + CBotVar* r = right->GivItemList(); + + while ( l != NULL && r != NULL ) + { + if ( l->Ne(l, r) ) return false; + l = l->GivNext(); + r = r->GivNext(); + } + + // should always arrived simultaneously at the end (same classes) + return l == r; +} + +bool CBotVarClass::Ne(CBotVar* left, CBotVar* right) +{ + CBotVar* l = left->GivItemList(); + CBotVar* r = right->GivItemList(); + + while ( l != NULL && r != NULL ) + { + if ( l->Ne(l, r) ) return true; + l = l->GivNext(); + r = r->GivNext(); + } + + // should always arrived simultaneously at the end (same classes) + return l != r; +} + +///////////////////////////////////////////////////////////////////////////// +// management of arrays + +CBotVarArray::CBotVarArray(const CBotToken* name, CBotTypResult& type ) +{ + if ( !type.Eq(CBotTypArrayPointer) && + !type.Eq(CBotTypArrayBody)) ASM_TRAP(); + + m_token = new CBotToken(name); + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = NULL; + + m_type = type; + m_type.SetType(CBotTypArrayPointer); + m_binit = false; + + m_pInstance = NULL; // the list of the array elements +} + +CBotVarArray::~CBotVarArray() +{ + if ( m_pInstance != NULL ) m_pInstance->DecrementUse(); // the lowest reference +} + +// copy a variable into another +void CBotVarArray::Copy(CBotVar* pSrc, bool bName) +{ + if ( pSrc->GivType() != CBotTypArrayPointer ) + ASM_TRAP(); + + CBotVarArray* p = (CBotVarArray*)pSrc; + + if ( bName) *m_token = *p->m_token; + m_type = p->m_type; + m_pInstance = p->GivPointer(); + + if ( m_pInstance != NULL ) + m_pInstance->IncrementUse(); // a reference increase + + m_binit = p->m_binit; +//- m_bStatic = p->m_bStatic; + m_pMyThis = NULL;//p->m_pMyThis; + m_pUserPtr = p->m_pUserPtr; + + // keeps indentificator the same (by default) + if (m_ident == 0 ) m_ident = p->m_ident; +} + +void CBotVarArray::SetPointer(CBotVar* pVarClass) +{ + m_binit = true; // init, even on a null pointer + + if ( m_pInstance == pVarClass) return; // Special, not decrement and reincrement + // because the decrement can destroy the object + + if ( pVarClass != NULL ) + { + if ( pVarClass->GivType() == CBotTypArrayPointer ) + pVarClass = pVarClass->GivPointer(); // the real pointer to the object + + if ( !pVarClass->m_type.Eq(CBotTypClass) && + !pVarClass->m_type.Eq(CBotTypArrayBody)) + ASM_TRAP(); + + ((CBotVarClass*)pVarClass)->IncrementUse(); // incement the reference + } + + if ( m_pInstance != NULL ) m_pInstance->DecrementUse(); + m_pInstance = (CBotVarClass*)pVarClass; +} + + +CBotVarClass* CBotVarArray::GivPointer() +{ + if ( m_pInstance == NULL ) return NULL; + return m_pInstance->GivPointer(); +} + +CBotVar* CBotVarArray::GivItem(int n, bool bExtend) +{ + if ( m_pInstance == NULL ) + { + if ( !bExtend ) return NULL; + // creates an instance of the table + + CBotVarClass* instance = new CBotVarClass(NULL, m_type); + SetPointer( instance ); + } + return m_pInstance->GivItem(n, bExtend); +} + +CBotVar* CBotVarArray::GivItemList() +{ + if ( m_pInstance == NULL) return NULL; + return m_pInstance->GivItemList(); +} + +CBotString CBotVarArray::GivValString() +{ + if ( m_pInstance == NULL ) return ( CBotString( "Null pointer" ) ) ; + return m_pInstance->GivValString(); +} + +bool CBotVarArray::Save1State(FILE* pf) +{ + if ( !WriteType(pf, m_type) ) return false; + return SaveVar(pf, m_pInstance); // saves the instance that manages the table +} + + +///////////////////////////////////////////////////////////////////////////// +// gestion des pointeurs à une instance donnée +// TODO management of pointers to a given instance + +CBotVarPointer::CBotVarPointer(const CBotToken* name, CBotTypResult& type ) +{ + if ( !type.Eq(CBotTypPointer) && + !type.Eq(CBotTypNullPointer) && + !type.Eq(CBotTypClass) && // for convenience accepts Class and Intrinsic + !type.Eq(CBotTypIntrinsic) ) ASM_TRAP(); + + m_token = new CBotToken(name); + m_next = NULL; + m_pMyThis = NULL; + m_pUserPtr = NULL; + + m_type = type; + if ( !type.Eq(CBotTypNullPointer) ) + m_type.SetType(CBotTypPointer); // anyway, this is a pointer + m_binit = false; + m_pClass = NULL; + m_pVarClass = NULL; // will be defined by a SetPointer() + + SetClass(type.GivClass() ); +} + +CBotVarPointer::~CBotVarPointer() +{ + if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse(); // decrement reference +} + + +void CBotVarPointer::Maj(void* pUser, bool bContinu) +{ +/* if ( !bContinu && m_pMyThis != NULL ) + m_pMyThis->Maj(pUser, false);*/ + + if ( m_pVarClass != NULL) m_pVarClass->Maj(pUser, false); +} + +CBotVar* CBotVarPointer::GivItem(const char* name) +{ + if ( m_pVarClass == NULL) // no existing instance? + return m_pClass->GivItem(name); // makes the pointer in the class itself + + return m_pVarClass->GivItem(name); +} + +CBotVar* CBotVarPointer::GivItemRef(int nIdent) +{ + if ( m_pVarClass == NULL) // no existing instance? + return m_pClass->GivItemRef(nIdent);// makes the pointer to the class itself + + return m_pVarClass->GivItemRef(nIdent); +} + +CBotVar* CBotVarPointer::GivItemList() +{ + if ( m_pVarClass == NULL) return NULL; + return m_pVarClass->GivItemList(); +} + +CBotString CBotVarPointer::GivValString() +{ + CBotString s = "Pointer to "; + if ( m_pVarClass == NULL ) s = "Null pointer" ; + else s += m_pVarClass->GivValString(); + return s; +} + + +void CBotVarPointer::ConstructorSet() +{ + if ( m_pVarClass != NULL) m_pVarClass->ConstructorSet(); +} + +// initializes the pointer to the instance of a class + +void CBotVarPointer::SetPointer(CBotVar* pVarClass) +{ + m_binit = true; // init, even on a null pointer + + if ( m_pVarClass == pVarClass) return; // special, not decrement and reincrement + // because the decrement can destroy the object + + if ( pVarClass != NULL ) + { + if ( pVarClass->GivType() == CBotTypPointer ) + pVarClass = pVarClass->GivPointer(); // the real pointer to the object + +// if ( pVarClass->GivType() != CBotTypClass ) + if ( !pVarClass->m_type.Eq(CBotTypClass) ) + ASM_TRAP(); + + ((CBotVarClass*)pVarClass)->IncrementUse(); // increment the reference + m_pClass = ((CBotVarClass*)pVarClass)->m_pClass; + m_pUserPtr = pVarClass->m_pUserPtr; // not really necessary + m_type = CBotTypResult(CBotTypPointer, m_pClass); // what kind of a pointer + } + + if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse(); + m_pVarClass = (CBotVarClass*)pVarClass; + +} + +CBotVarClass* CBotVarPointer::GivPointer() +{ + if ( m_pVarClass == NULL ) return NULL; + return m_pVarClass->GivPointer(); +} + +void CBotVarPointer::SetIdent(long n) +{ + if ( m_pVarClass == NULL ) return; + m_pVarClass->SetIdent( n ); +} + +long CBotVarPointer::GivIdent() +{ + if ( m_pVarClass == NULL ) return 0; + return m_pVarClass->m_ItemIdent; +} + + +void CBotVarPointer::SetClass(CBotClass* pClass) +{ +// int nIdent = 0; + m_type.m_pClass = m_pClass = pClass; + if ( m_pVarClass != NULL ) m_pVarClass->SetClass(pClass); //, nIdent); +} + +CBotClass* CBotVarPointer::GivClass() +{ + if ( m_pVarClass != NULL ) return m_pVarClass->GivClass(); + + return m_pClass; +} + + +bool CBotVarPointer::Save1State(FILE* pf) +{ + if ( m_pClass ) + { + if (!WriteString(pf, m_pClass->GivName())) return false; // name of the class + } + else + { + if (!WriteString(pf, "")) return false; + } + + if (!WriteLong(pf, GivIdent())) return false; // the unique reference + + // also saves the proceedings copies + return SaveVar(pf, GivPointer()); +} + +// copy a variable into another +void CBotVarPointer::Copy(CBotVar* pSrc, bool bName) +{ + if ( pSrc->GivType() != CBotTypPointer && + pSrc->GivType() != CBotTypNullPointer) + ASM_TRAP(); + + CBotVarPointer* p = (CBotVarPointer*)pSrc; + + if ( bName) *m_token = *p->m_token; + m_type = p->m_type; +// m_pVarClass = p->m_pVarClass; + m_pVarClass = p->GivPointer(); + + if ( m_pVarClass != NULL ) + m_pVarClass->IncrementUse(); // incerement the reference + + m_pClass = p->m_pClass; + m_binit = p->m_binit; +//- m_bStatic = p->m_bStatic; + m_next = NULL; + m_pMyThis = NULL;//p->m_pMyThis; + m_pUserPtr = p->m_pUserPtr; + + // keeps indentificator the same (by default) + if (m_ident == 0 ) m_ident = p->m_ident; +} + +bool CBotVarPointer::Eq(CBotVar* left, CBotVar* right) +{ + CBotVarClass* l = left->GivPointer(); + CBotVarClass* r = right->GivPointer(); + + if ( l == r ) return true; + if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return true; + if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return true; + return false; +} + +bool CBotVarPointer::Ne(CBotVar* left, CBotVar* right) +{ + CBotVarClass* l = left->GivPointer(); + CBotVarClass* r = right->GivPointer(); + + if ( l == r ) return false; + if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return false; + if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return false; + return true; +} + + + +/////////////////////////////////////////////////////// +// management of results types + + +CBotTypResult::CBotTypResult(int type) +{ + m_type = type; + m_pNext = NULL; + m_pClass = NULL; + m_limite = -1; +} + +CBotTypResult::CBotTypResult(int type, const char* name) +{ + m_type = type; + m_pNext = NULL; + m_pClass = NULL; + m_limite = -1; + + if ( type == CBotTypPointer || + type == CBotTypClass || + type == CBotTypIntrinsic ) + { + m_pClass = CBotClass::Find(name); + if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic; + } +} + +CBotTypResult::CBotTypResult(int type, CBotClass* pClass) +{ + m_type = type; + m_pNext = NULL; + m_pClass = pClass; + m_limite = -1; + + if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic; +} + +CBotTypResult::CBotTypResult(int type, CBotTypResult elem) +{ + m_type = type; + m_pNext = NULL; + m_pClass = NULL; + m_limite = -1; + + if ( type == CBotTypArrayPointer || + type == CBotTypArrayBody ) + m_pNext = new CBotTypResult( elem ); +} + +CBotTypResult::CBotTypResult(const CBotTypResult& typ) +{ + m_type = typ.m_type; + m_pClass = typ.m_pClass; + m_pNext = NULL; + m_limite = typ.m_limite; + + if ( typ.m_pNext ) + m_pNext = new CBotTypResult( *typ.m_pNext ); +} + +CBotTypResult::CBotTypResult() +{ + m_type = 0; + m_limite = -1; + m_pNext = NULL; + m_pClass = NULL; +} + +CBotTypResult::~CBotTypResult() +{ + delete m_pNext; +} + +int CBotTypResult::GivType(int mode) const +{ +#ifdef _DEBUG + if ( m_type == CBotTypPointer || + m_type == CBotTypClass || + m_type == CBotTypIntrinsic ) + + if ( m_pClass == NULL ) ASM_TRAP(); + + + if ( m_type == CBotTypArrayPointer ) + if ( m_pNext == NULL ) ASM_TRAP(); +#endif + if ( mode == 3 && m_type == CBotTypNullPointer ) return CBotTypPointer; + return m_type; +} + +void CBotTypResult::SetType(int n) +{ + m_type = n; +} + +CBotClass* CBotTypResult::GivClass() const +{ + return m_pClass; +} + +CBotTypResult& CBotTypResult::GivTypElem() const +{ + return *m_pNext; +} + +int CBotTypResult::GivLimite() const +{ + return m_limite; +} + +void CBotTypResult::SetLimite(int n) +{ + m_limite = n; +} + +void CBotTypResult::SetArray( int* max ) +{ + m_limite = *max; + if (m_limite < 1) m_limite = -1; + + if ( m_pNext != NULL ) // last dimension? + { + m_pNext->SetArray( max+1 ); + } +} + + + +bool CBotTypResult::Compare(const CBotTypResult& typ) const +{ + if ( m_type != typ.m_type ) return false; + + if ( m_type == CBotTypArrayPointer ) return m_pNext->Compare(*typ.m_pNext); + + if ( m_type == CBotTypPointer || + m_type == CBotTypClass || + m_type == CBotTypIntrinsic ) + { + return m_pClass == typ.m_pClass; + } + + return true; +} + +bool CBotTypResult::Eq(int type) const +{ + return m_type == type; +} + +CBotTypResult& + CBotTypResult::operator=(const CBotTypResult& src) +{ + m_type = src.m_type; + m_limite = src.m_limite; + m_pClass = src.m_pClass; + m_pNext = NULL; + if ( src.m_pNext != NULL ) + { + m_pNext = new CBotTypResult(*src.m_pNext); + } + return *this; +} + + diff --git a/src/CBot/CBotWhile.cpp b/src/CBot/CBotWhile.cpp index fcb825c..36923ae 100644 --- a/src/CBot/CBotWhile.cpp +++ b/src/CBot/CBotWhile.cpp @@ -1,1427 +1,1433 @@ -// * 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/.///////////////////////////////////////////////////////////////////////
-// ce fichier défini les instructions suivantes:
-// CBotWhile "while (condition) {instructions}"
-// CBotDo "do {instructions} while (condition)"
-// CBotFor "for (init, condition, incr) {instructions}"
-// CBotSwitch "switch (val) {instructions}"
-// CBotCase "case val:"
-// CBotBreak "break", "break label", "continu", "continu label"
-// CBotTry "try {instructions}"
-// CBotCatch "catch (condition) {instructions}" ou "finally"
-// CBotThrow "throw execption"
-
-
-#include "CBot.h"
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "while"
-
-CBotWhile::CBotWhile()
-{
- m_Condition =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotWhile"; // debug
-}
-
-CBotWhile::~CBotWhile()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotWhile* inst = new CBotWhile(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_WHILE)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe
-
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (il peut être vide !
-
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "while"
-
-bool CBotWhile :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != true )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // la condition est vrai, passe dans le second mode
-
- if (!pile->SetState(1)) return false; // prêt pour la suite
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(0, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au test pour recommencer
- if (!pile->SetState(0, 0)) return false;
- continue;
- }
-}
-
-void CBotWhile :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- m_Condition->RestoreState(pile, bMain);
- return;
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "repeat"
-
-CBotRepeat::CBotRepeat()
-{
- m_NbIter =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotRepeat"; // debug
-}
-
-CBotRepeat::~CBotRepeat()
-{
- delete m_NbIter; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotRepeat* inst = new CBotRepeat(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_REPEAT)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( IsOfType(p, ID_OPENPAR ) )
- {
- CBotToken* ppp = p; // conserve le ^au token (position début)
- if ( NULL != (inst->m_NbIter = CBotExpression::Compile( p, pStk )) )
- {
- if ( pStk->GivType() < CBotTypLong )
- {
- if ( IsOfType(p, ID_CLOSEPAR ) )
- {
-
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (il peut être vide !
-
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStk->SetStartError(ppp->GivStart());
- pStk->SetError( TX_BADTYPE, p->GivStart() );
- }
- pStack->SetError(TX_ENDOF, p);
- }
- pStack->SetError(TX_OPENPAR, p->GivStart()); // manque la parenthèse
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "repeat"
-
-bool CBotRepeat :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue le nombre d'itération
- if ( !m_NbIter->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- int n;
- if ( !pile->IsOk() || ( n = pile->GivVal() ) < 1 )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // met le nombre d'itération +1 dans le "state"
-
- if (!pile->SetState(n+1)) return false; // prêt pour la suite
- continue; // passe à la suite
-
- case 1:
- // fin normale de la boucle
- return pj->Return(pile); // transmet le résultat et libère la pile
-
- default:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(pile->GivState()-1, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au test pour recommencer
- if (!pile->SetState(pile->GivState()-1, 0)) return false;
- continue;
- }
-}
-
-void CBotRepeat :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- m_NbIter->RestoreState(pile, bMain);
- return;
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "do"
-
-CBotDo::CBotDo()
-{
- m_Condition =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotDo"; // debug
-}
-
-CBotDo::~CBotDo()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotDo* inst = new CBotDo(); // crée l'objet
-
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_DO)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
-
- // cherche un bloc d'instruction après le do
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- if (IsOfType(p, ID_WHILE))
- {
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe
- if (IsOfType(p, ID_SEP))
- {
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
- }
- pStk->SetError(TX_WHILE, p->GivStart());
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "do"
-
-bool CBotDo :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(1, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- if (!pile->SetState(1)) return false; // prêt pour la suite
-
- case 1:
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != true )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au bloc d'instruction pour recommencer
- if (!pile->SetState(0, 0)) return false;
- continue;
- }
-}
-
-void CBotDo :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // restitue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
-
- case 1:
- // restitue la condition
- m_Condition->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "for"
-
-CBotFor::CBotFor()
-{
- m_Init =
- m_Test =
- m_Incr =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotFor"; // debug
-}
-
-CBotFor::~CBotFor()
-{
- delete m_Init;
- delete m_Test;
- delete m_Incr;
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotFor* inst = new CBotFor(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_FOR)) return NULL; // ne devrait jamais arriver
-
- if ( !IsOfType(p, ID_OPENPAR)) // manque la parenthèse ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- return NULL;
- }
-
- CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp
-
- // compile les instructions pour initialisation
- inst->m_Init = CBotListExpression::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( !IsOfType(p, ID_SEP)) // manque le point-virgule ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
- }
- inst->m_Test = CBotBoolExpr::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( !IsOfType(p, ID_SEP)) // manque le point-virgule ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
- }
- inst->m_Incr = CBotListExpression::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( IsOfType(p, ID_CLOSEPAR)) // manque la parenthèse ?
- {
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
- DecLvl();
- if ( pStk->IsOk() )
- return pStack->Return(inst, pStk);;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- }
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction "for"
-
-bool CBotFor :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this, true); // ajoute un élément à la pile (variables locales)
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- while( true ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 4 états possibles (selon reprise)
- case 0:
- // évalue l'initialisation
- if ( m_Init != NULL &&
- !m_Init->Execute(pile) ) return false; // interrompu ici ?
- if (!pile->SetState(1)) return false; // prêt pour la suite
-
- case 1:
- // évalue la condition
- if ( m_Test != NULL ) // pas de condition ? -> vrai !
- {
- if (!m_Test->Execute(pile) ) return false; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != true )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
- }
-
- // la condition est vrai, passe à la suite
- if (!pile->SetState(2)) return false; // prêt pour la suite
-
- case 2:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(3, m_label)) continue; // si continue, passe à l'incrémentation
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- if (!pile->SetState(3)) return false; // prêt pour la suite
-
- case 3:
- // évalue l'incrémentation
- if ( m_Incr != NULL &&
- !m_Incr->Execute(pile) ) return false; // interrompu ici ?
-
- // repasse au test pour recommencer
- if (!pile->SetState(1, 0)) return false; // revient au test
- continue;
- }
-}
-
-void CBotFor :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile (variables locales)
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 4 états possibles (selon reprise)
- case 0:
- // évalue l'initialisation
- if ( m_Init != NULL ) m_Init->RestoreState(pile, true); // interrompu ici !
- return;
-
- case 1:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // définitions variables
-
- // évalue la condition
- if ( m_Test != NULL ) m_Test->RestoreState(pile, true); // interrompu ici !
- return;
-
- case 2:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // définitions variables
-
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, true);
- return;
-
- case 3:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // définitions variables
-
- // évalue l'incrémentation
- if ( m_Incr != NULL ) m_Incr->RestoreState(pile, true); // interrompu ici !
- return;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une liste d'expression
-// n'est utilisé que pour l'instruction for
-// dans l'intitialisation et dans l'incrémentation
-
-CBotListExpression::CBotListExpression()
-{
- m_Expr = NULL;
- name = "CBotListExpression";
-}
-
-CBotListExpression::~CBotListExpression()
-{
- delete m_Expr;
-}
-
-// cherche une déclaration de variable ou une expression
-
-static CBotInstr* CompileInstrOrDefVar(CBotToken* &p, CBotCStack* pStack)
-{
- CBotInstr* i = CBotInt::Compile( p, pStack, false, true ); // est-ce une déclaration d'un entier ?
- if ( i== NULL ) i = CBotFloat::Compile( p, pStack, false, true ); // ou d'un nombre réel ?
- if ( i== NULL ) i = CBotBoolean::Compile( p, pStack, false, true ); // ou d'un booléen ?
- if ( i== NULL ) i = CBotIString::Compile( p, pStack, false, true ); // ou d'une chaîne ?
- if ( i== NULL ) i = CBotExpression::Compile( p, pStack ); // compile une expression
- return i;
-}
-
-CBotInstr* CBotListExpression::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotListExpression* inst = new CBotListExpression();
-
- inst->m_Expr = CompileInstrOrDefVar( p, pStack ); // compile la première expression de la liste
- if (pStack->IsOk())
- {
- while ( IsOfType(p, ID_COMMA) ) // plusieurs instructions ?
- {
- CBotInstr* i = CompileInstrOrDefVar( p, pStack ); // est-ce une déclaration d'un entier ?
- inst->m_Expr->AddNext(i); // ajoute à la suite
- if ( !pStack->IsOk() )
- {
- delete inst;
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
- }
- return inst;
- }
- delete inst;
- return NULL;
-}
-
-bool CBotListExpression::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack();// indispensable
- CBotInstr* p = m_Expr; // la première expression
-
- int state = pile->GivState();
- while (state-->0) p = p->GivNext(); // revient sur l'opération interrompue
-
- if ( p != NULL ) while (true)
- {
- if ( !p->Execute(pile) ) return false;
- p = p->GivNext();
- if ( p == NULL ) break;
- if (!pile->IncState()) return false; // prêt pour la suivante
- }
- return pj->Return(pile);
-}
-
-void CBotListExpression::RestoreState(CBotStack* &pj, bool bMain)
-{
- CBotStack* pile = pj;
- int state = 0x7000;
-
- if ( bMain )
- {
- pile = pj->RestoreStack();
- if ( pile == NULL ) return;
- state = pile->GivState();
- }
-
- CBotInstr* p = m_Expr; // la première expression
-
- while (p != NULL && state-->0)
- {
- p->RestoreState(pile, false);
- p = p->GivNext(); // revient sur l'opération interrompue
- }
-
- if ( p != NULL )
- {
- p->RestoreState(pile, bMain);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "switch"
-
-CBotSwitch::CBotSwitch()
-{
- m_Value =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotSwitch"; // debug
-}
-
-CBotSwitch::~CBotSwitch()
-{
- delete m_Value; // libère la valeur
- delete m_Block; // libère le bloc d'instruction
-}
-
-
-CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotSwitch* inst = new CBotSwitch(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_SWITCH)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( IsOfType(p, ID_OPENPAR ) )
- {
- if ( NULL != (inst->m_Value = CBotExpression::Compile( p, pStk )) )
- {
- if ( pStk->GivType() < CBotTypLong )
- {
- if ( IsOfType(p, ID_CLOSEPAR ) )
- {
- if ( IsOfType(p, ID_OPBLK ) )
- {
- IncLvl();
-
- while( !IsOfType( p, ID_CLBLK ) )
- {
- if ( p->GivType() == ID_CASE || p->GivType() == ID_DEFAULT)
- {
- CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp
-
- CBotInstr* i = CBotCase::Compile( p, pStk2 );
- if (i == NULL)
- {
- delete inst;
- return pStack->Return(NULL, pStk2);
- }
- delete pStk2;
- if ( inst->m_Block == NULL ) inst->m_Block = i;
- else inst->m_Block->AddNext(i);
- continue;
- }
-
- if ( inst->m_Block == NULL )
- {
- pStk->SetError(TX_NOCASE, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true );
- if ( !pStk->IsOk() )
- {
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- inst->m_Block->AddNext(i);
-
- if ( p == NULL )
- {
- pStk->SetError(TX_CLOSEBLK, -1);
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- }
- DecLvl();
-
- if ( inst->m_Block == NULL )
- {
- pStk->SetError(TX_NOCASE, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- // le bloc d'instruction est ok
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- pStk->SetError( TX_OPENBLK, p->GivStart() );
- }
- pStk->SetError( TX_CLOSEPAR, p->GivStart() );
- }
- pStk->SetError( TX_BADTYPE, p->GivStart() );
- }
- }
- pStk->SetError( TX_OPENPAR, p->GivStart());
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "switch"
-
-bool CBotSwitch :: Execute(CBotStack* &pj)
-{
- CBotStack* pile1 = pj->AddStack(this); // ajoute un élément à la pile
-// if ( pile1 == EOX ) return true;
-
- CBotInstr* p = m_Block; // la première expression
-
- int state = pile1->GivState();
- if (state == 0)
- {
- if ( !m_Value->Execute(pile1) ) return false;
- pile1->SetState(state = -1);
- }
-
- if ( pile1->IfStep() ) return false;
-
- if ( state == -1 )
- {
- state = 0;
- int val = pile1->GivVal(); // résultat de la valeur
-
- CBotStack* pile2 = pile1->AddStack();
- while ( p != NULL ) // recherche le case correspondant dans la liste
- {
- state++;
- if ( p->CompCase( pile2, val ) ) break; // trouvé le case
- p = p->GivNext();
- }
- pile2->Delete();
-
- if ( p == NULL ) return pj->Return(pile1); // terminé si plus rien
-
- if ( !pile1->SetState(state) ) return false;
- }
-
- p = m_Block; // revient au début
- while (state-->0) p = p->GivNext(); // avance dans la liste
-
- while( p != NULL )
- {
- if ( !p->Execute(pile1) ) return pj->BreakReturn(pile1);
- if ( !pile1->IncState() ) return false;
- p = p->GivNext();
- }
- return pj->Return(pile1);
-}
-
-void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile1 = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile1 == NULL ) return;
-
- CBotInstr* p = m_Block; // la première expression
-
- int state = pile1->GivState();
- if (state == 0)
- {
- m_Value->RestoreState(pile1, bMain);
- return;
- }
-
- if ( state == -1 )
- {
- return;
- }
-
-// p = m_Block; // revient au début
- while ( p != NULL && state-- > 0 )
- {
- p->RestoreState(pile1, false);
- p = p->GivNext(); // avance dans la liste
- }
-
- if( p != NULL )
- {
- p->RestoreState(pile1, true);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "case"
-// on est forcément dans un bloc d'instruction "switch"
-
-CBotCase::CBotCase()
-{
- m_Value = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotCase"; // debug
-}
-
-CBotCase::~CBotCase()
-{
- delete m_Value; // libère la valeur
-}
-
-
-CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCase* inst = new CBotCase(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return NULL; // ne devrait jamais arriver
-
- if ( pp->GivType() == ID_CASE )
- {
- pp = p;
- inst->m_Value = CBotExprNum::Compile(p, pStack);
- if ( inst->m_Value == NULL )
- {
- pStack->SetError( TX_BADNUM, pp );
- delete inst;
- return NULL;
- }
- }
- if ( !IsOfType( p, ID_DOTS ))
- {
- pStack->SetError( TX_MISDOTS, p->GivStart() );
- delete inst;
- return NULL;
- }
-
- return inst;
-}
-
-// exécution de l'instruction "case"
-
-bool CBotCase::Execute(CBotStack* &pj)
-{
- return true; // l'instruction "case" ne fait rien !
-}
-
-void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
-{
-}
-
-// routine permettant de trouver le point d'entrée "case"
-// correspondant à la valeur cherchée
-
-bool CBotCase::CompCase(CBotStack* &pile, int val)
-{
- if ( m_Value == NULL ) return true; // cas pour "default"
-
- while (!m_Value->Execute(pile)); // met sur la pile la valeur correpondant (sans interruption)
- return (pile->GivVal() == val); // compare avec la valeur cherchée
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "break" ou "continu"
-
-CBotBreak::CBotBreak()
-{
- name = "CBotBreak"; // debug
-}
-
-CBotBreak::~CBotBreak()
-{
-}
-
-CBotInstr* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p; // conserve le ^au token (position début)
- int type = p->GivType();
-
- if (!IsOfType(p, ID_BREAK, ID_CONTINUE)) return NULL; // ne devrait jamais arriver
-
- if ( !ChkLvl(CBotString(), type ) )
- {
- pStack->SetError(TX_BREAK, pp);
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
-
- CBotBreak* inst = new CBotBreak(); // crée l'objet
- inst->SetToken(pp); // garde l'opération
-
- pp = p;
- if ( IsOfType( p, TokenTypVar ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- if ( !ChkLvl(inst->m_label, type ) )
- {
- delete inst;
- pStack->SetError(TX_NOLABEL, pp);
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
- }
-
- if (IsOfType(p, ID_SEP))
- {
- return inst; // et le donne à qui veux
- }
- delete inst;
-
- pStack->SetError(TX_ENDOF, p->GivStart());
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécution l'instructino "break" ou "continu"
-
-bool CBotBreak :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return true;
-
- if ( pile->IfStep() ) return false;
-
- pile->SetBreak(m_token.GivType()==ID_BREAK ? 1 : 2, m_label);
- return pj->Return(pile);
-}
-
-void CBotBreak :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "try"
-
-CBotTry::CBotTry()
-{
- m_ListCatch = NULL;
- m_FinalInst =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotTry"; // debug
-}
-
-CBotTry::~CBotTry()
-{
- delete m_ListCatch; // libère la liste
- delete m_Block; // libère le bloc d'instruction
- delete m_FinalInst;
-}
-
-CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotTry* inst = new CBotTry(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_TRY)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk );
- CBotCatch** pn = &inst->m_ListCatch;
-
- while (pStk->IsOk() && p->GivType() == ID_CATCH)
- {
- CBotCatch* i = CBotCatch::Compile(p, pStk);
- *pn = i;
- pn = &i->m_next;
- }
-
- if (pStk->IsOk() && IsOfType( p, ID_FINALLY) )
- {
- inst->m_FinalInst = CBotBlock::CompileBlkOrInst( p, pStk );
- }
-
- if (pStk->IsOk())
- {
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction Try
-// gère le retour d'exceptions
-// les arrêts par suspension
-// et les "finaly"
-
-bool CBotTry :: Execute(CBotStack* &pj)
-{
- int val;
-
- CBotStack* pile1 = pj->AddStack(this); // ajoute un élément à la pile
-// if ( pile1 == EOX ) return true;
-
- if ( pile1->IfStep() ) return false;
- // ou le retrouve en cas de reprise
- CBotStack* pile0 = pj->AddStack2(); // ajoute un élément à la pile secondaire
- CBotStack* pile2 = pile0->AddStack();
-
- if ( pile1->GivState() == 0 )
- {
- if ( m_Block->Execute(pile1) )
- {
- if ( m_FinalInst == NULL ) return pj->Return(pile1);
- pile1->SetState(-2); // passe au final
- }
-
- val = pile1->GivError();
- if ( val == 0 && CBotStack::m_initimer == 0 ) // en mode de step ?
- return false; // ne fait pas le catch
-
- pile1->IncState();
- pile2->SetState(val); // mémorise le numéro de l'erreur
- pile1->SetError(0); // pour l'instant il n'y a plus d'erreur !
-
- if ( val == 0 && CBotStack::m_initimer < 0 ) // en mode de step ?
- return false; // ne fait pas le catch
- }
-
- // il y a eu une interruption
- // voir de quoi il en retourne
-
- CBotCatch* pc = m_ListCatch;
- int state = (short)pile1->GivState(); // où en étions-nous ?
- val = pile2->GivState(); // pour quelle erreur ?
- pile0->SetState(1); // marquage pour GetRunPos
-
- if ( val >= 0 && state > 0 ) while ( pc != NULL )
- {
- if ( --state <= 0 )
- {
- // demande au bloc catch s'il se sent concerné
- if ( !pc->TestCatch(pile2, val) ) return false; // suspendu !
- pile1->IncState();
- }
- if ( --state <= 0 )
- {
- if ( pile2->GivVal() == true )
- {
-// pile0->SetState(1);
-
- if ( !pc->Execute(pile2) ) return false; // exécute l'opération
- if ( m_FinalInst == NULL )
- return pj->Return(pile2); // termine le try
-
- pile1->SetState(-2); // passe au final
- break;
- }
- pile1->IncState();
- }
- pc = pc->m_next;
- }
- if ( m_FinalInst != NULL &&
- pile1->GivState() > 0 && val != 0 ) pile1->SetState(-1);// si arret alors fait le final
-
- if (pile1->GivState() <= -1)
- {
-// pile0->SetState(1);
-
- if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return false;
- if (!pile2->IsOk()) return pj->Return(pile2); // garde cette exception
- pile2->SetError(pile1->GivState()==-1 ? val : 0); // remet l'erreur initiale
- return pj->Return(pile2);
- }
-
- pile1->SetState(0); // revient à l'évaluation
- pile0->SetState(0); // revient à l'évaluation
- if ( val != 0 && m_ListCatch == NULL && m_FinalInst == NULL )
- return pj->Return(pile2); // termine le try sans exception aucune
-
- pile1->SetError(val); // remet l'erreur
- return false; // ce n'est pas pour nous
-}
-
-
-void CBotTry :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- int val;
- CBotStack* pile1 = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile1 == NULL ) return;
- // ou le retrouve en cas de reprise
- CBotStack* pile0 = pj->AddStack2(); // ajoute un élément à la pile secondaire
- if ( pile0 == NULL ) return;
-
- CBotStack* pile2 = pile0->RestoreStack();
- if ( pile2 == NULL ) return;
-
- m_Block->RestoreState(pile1, bMain);
- if ( pile0->GivState() == 0 )
- {
- return;
- }
-
- // il y a eu une interruption
- // voir de quoi il en retourne
-
- CBotCatch* pc = m_ListCatch;
- int state = pile1->GivState(); // où en étions-nous ?
- val = pile2->GivState(); // pour quelle erreur ?
-
- if ( val >= 0 && state > 0 ) while ( pc != NULL )
- {
- if ( --state <= 0 )
- {
- // demande au bloc catch s'il se sent concerné
- pc->RestoreCondState(pile2, bMain); // suspendu !
- return;
- }
- if ( --state <= 0 )
- {
- if ( pile2->GivVal() == true )
- {
- pc->RestoreState(pile2, bMain); // exécute l'opération
- return;
- }
- }
- pc = pc->m_next;
- }
-
- if (pile1->GivState() <= -1)
- {
- m_FinalInst->RestoreState(pile2, bMain);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "catch"
-
-CBotCatch::CBotCatch()
-{
- m_Cond =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- m_next = NULL;
-
- name = "CBotCatch"; // debug
-}
-
-CBotCatch::~CBotCatch()
-{
- delete m_Cond; // libère la liste
- delete m_Block; // libère le bloc d'instruction
- delete m_next; // et la suite
-}
-
-CBotCatch* CBotCatch::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCatch* inst = new CBotCatch(); // crée l'objet
- pStack->SetStartError(p->GivStart());
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_CATCH)) return NULL; // ne devrait jamais arriver
-
- if (IsOfType(p, ID_OPENPAR))
- {
- inst->m_Cond = CBotExpression::Compile(p, pStack);
- if (( pStack->GivType() < CBotTypLong ||
- pStack->GivTypResult().Eq(CBotTypBoolean) )&& pStack->IsOk() )
- {
- if (IsOfType(p, ID_CLOSEPAR))
- {
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStack );
- if ( pStack->IsOk() )
- return inst; // rend l'objet à qui le demande
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStack->SetError(TX_BADTYPE, p->GivStart());
- }
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst; // erreur, libère la place
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécution de "catch"
-
-bool CBotCatch :: Execute(CBotStack* &pj)
-{
- if ( m_Block == NULL ) return true;
- return m_Block->Execute(pj); // exécute le bloc associé
-}
-
-void CBotCatch :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( bMain && m_Block != NULL ) m_Block->RestoreState(pj, bMain);
-}
-
-void CBotCatch :: RestoreCondState(CBotStack* &pj, bool bMain)
-{
- m_Cond->RestoreState(pj, bMain);
-}
-
-// routine pour savoir si le catch est à faire ou non
-
-bool CBotCatch :: TestCatch(CBotStack* &pile, int val)
-{
- if ( !m_Cond->Execute(pile) ) return false;
-
- if ( val > 0 || pile->GivType() != CBotTypBoolean )
- {
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
- var->SetValInt( pile->GivVal() == val );
- pile->SetVar(var); // remet sur la pile
- }
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "throw"
-
-CBotThrow::CBotThrow()
-{
- m_Value = NULL; // NULL pour que delete soit possible sans autre
-
- name = "CBotThrow"; // debug
-}
-
-CBotThrow::~CBotThrow()
-{
- delete m_Value;
-}
-
-CBotInstr* CBotThrow::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- pStack->SetStartError(p->GivStart());
-
- CBotThrow* inst = new CBotThrow(); // crée l'objet
- inst->SetToken(p);
-
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if (!IsOfType(p, ID_THROW)) return NULL; // ne devrait jamais arriver
-
- inst->m_Value = CBotExpression::Compile( p, pStack );
-
- if (pStack->GivType() < CBotTypLong && pStack->IsOk())
- {
- return inst; // rend l'objet à qui le demande
- }
- pStack->SetError(TX_BADTYPE, pp);
-
- delete inst; // erreur, libère la place
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction "throw"
-
-bool CBotThrow :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return true;
-
- if ( pile->GivState() == 0 )
- {
- if ( !m_Value->Execute(pile) ) return false;
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return false;
-
- int val = pile->GivVal();
- if ( val < 0 ) val = TX_BADTHROW;
- pile->SetError( val, &m_token );
- return pj->Return( pile );
-}
-
-void CBotThrow :: RestoreState(CBotStack* &pj, bool bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState() == 0 )
- {
- m_Value->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-
-////////////////////////////////////////////////////////////
-
-
-CBotStartDebugDD::CBotStartDebugDD()
-{
- name = "CBotStartDebugDD"; // debug
-}
-
-CBotStartDebugDD::~CBotStartDebugDD()
-{
-}
-
-CBotInstr* CBotStartDebugDD::Compile(CBotToken* &p, CBotCStack* pStack)
-{
-
- if (!IsOfType(p, ID_DEBUGDD)) return NULL; // ne devrait jamais arriver
-
- return new CBotStartDebugDD(); // crée l'objet
-
-}
-
-// exécute l'instruction "throw"
-
-bool CBotStartDebugDD :: Execute(CBotStack* &pj)
-{
- CBotProgram* p = pj->GivBotCall();
- p->m_bDebugDD = true;
-
- return true;
-}
-
+// * 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/. + +/////////////////////////////////////////////////////////////////////// +// This file defined the following statements: +// CBotWhile "while (condition) {instructions}" +// CBotDo "do {instructions} while (condition)" +// CBotFor "for (init, condition, incr) {instructions}" +// CBotSwitch "switch (val) {instructions}" +// CBotCase "case val:" +// CBotBreak "break", "break label", "continu", "continu label" +// CBotTry "try {instructions}" +// CBotCatch "catch (condition) {instructions}" or "finally" +// CBotThrow "throw execption" + + +#include "CBot.h" + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compile an instruction "while" + +CBotWhile::CBotWhile() +{ + m_Condition = + m_Block = NULL; // NULL so that delete is not possible further + name = "CBotWhile"; // debug +} + +CBotWhile::~CBotWhile() +{ + delete m_Condition; // frees the condition + delete m_Block; // releases the block instruction +} + +CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotWhile* inst = new CBotWhile(); // creates the object + CBotToken* pp = p; // preserves at the ^ token (starting position) + + if ( IsOfType( p, TokenTypVar ) && + IsOfType( p, ID_DOTS ) ) + { + inst->m_label = pp->GivString(); // records the name of the label + } + + inst->SetToken(p); + if (!IsOfType(p, ID_WHILE)) return NULL; // should never happen + + CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + // a bit of battery please (??) + + if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) ) + { + // the condition exists + + IncLvl(inst->m_label); + inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); + DecLvl(); + + if ( pStk->IsOk() ) + { + // the statement block is ok (it may be empty! + + return pStack->Return(inst, pStk); // return an object to the application + // makes the object to which the application + } + } + + delete inst; // error, frees the place + return pStack->Return(NULL, pStk); // no object, the error is on the stack +} + +// executes a "while" instruction + +bool CBotWhile :: Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); // adds an item to the stack + // or find in case of recovery +// if ( pile == EOX ) return true; + + if ( pile->IfStep() ) return false; + + while( true ) switch( pile->GivState() ) // executes the loop + { // there are two possible states (depending on recovery) + case 0: + // evaluates the condition + if ( !m_Condition->Execute(pile) ) return false; // interrupted here? + + // the result of the condition is on the stack + + // terminates if an error or if the condition is false + if ( !pile->IsOk() || pile->GivVal() != true ) + { + return pj->Return(pile); // sends the results and releases the stack + } + + // the condition is true, pass in the second mode + + if (!pile->SetState(1)) return false; // ready for further + + case 1: + // evaluates the associated statement block + if ( m_Block != NULL && + !m_Block->Execute(pile) ) + { + if (pile->IfContinue(0, m_label)) continue; // if continued, will return to test + return pj->BreakReturn(pile, m_label); // sends the results and releases the stack + } + + // terminates if there is an error + if ( !pile->IsOk() ) + { + return pj->Return(pile); // sends the results and releases the stack + } + + // returns to the test again + if (!pile->SetState(0, 0)) return false; + continue; + } +} + +void CBotWhile :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack + if ( pile == NULL ) return; + + switch( pile->GivState() ) + { // there are two possible states (depending on recovery) + case 0: + // evaluates the condition + m_Condition->RestoreState(pile, bMain); + return; + + case 1: + // evaluates the associated statement block + if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain); + return; + } +} + + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "repeat" + +CBotRepeat::CBotRepeat() +{ + m_NbIter = + m_Block = NULL; // NULL so that delete is not possible further + name = "CBotRepeat"; // debug +} + +CBotRepeat::~CBotRepeat() +{ + delete m_NbIter; // frees the condition + delete m_Block; // frees the instruction block +} + +CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotRepeat* inst = new CBotRepeat(); // creates the object + CBotToken* pp = p; // preserves at the ^ token (starting position) + + if ( IsOfType( p, TokenTypVar ) && + IsOfType( p, ID_DOTS ) ) + { + inst->m_label = pp->GivString(); // register the name of label + } + + inst->SetToken(p); + if (!IsOfType(p, ID_REPEAT)) return NULL; // should never happen + + CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + + if ( IsOfType(p, ID_OPENPAR ) ) + { + CBotToken* ppp = p; // preserves the ^ token (starting position) + if ( NULL != (inst->m_NbIter = CBotExpression::Compile( p, pStk )) ) + { + if ( pStk->GivType() < CBotTypLong ) + { + if ( IsOfType(p, ID_CLOSEPAR ) ) + { + + IncLvl(inst->m_label); + inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); + DecLvl(); + + if ( pStk->IsOk() ) + { + // the statement block is ok (it may be empty! + + return pStack->Return(inst, pStk); // return an object to the application + } + } + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + } + pStk->SetStartError(ppp->GivStart()); + pStk->SetError( TX_BADTYPE, p->GivStart() ); + } + pStack->SetError(TX_ENDOF, p); + } + pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis + + delete inst; // error, frees up + return pStack->Return(NULL, pStk); // no object, the error is on the stack +} + +// execution of intruction "repeat" + +bool CBotRepeat :: Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); // adds an item to the stack + // or find in case of recovery +// if ( pile == EOX ) return true; + + if ( pile->IfStep() ) return false; + + while( true ) switch( pile->GivState() ) // executes the loop + { // there are two possible states (depending on recovery) + case 0: + // evaluates the number of iterations + if ( !m_NbIter->Execute(pile) ) return false; // interrupted here ? + + // the result of the condition is on the stack + + // terminates if an error or if the condition is false + int n; + if ( !pile->IsOk() || ( n = pile->GivVal() ) < 1 ) + { + return pj->Return(pile); // sends the results and releases the stack + } + + // puts the number of iterations +1 to the "state" + + if (!pile->SetState(n+1)) return false; // ready for further + continue; // continue as a result + + case 1: + // normal end of the loop + return pj->Return(pile); // sends the results and releases the stack + + default: + // evaluates the associated statement block + if ( m_Block != NULL && + !m_Block->Execute(pile) ) + { + if (pile->IfContinue(pile->GivState()-1, m_label)) continue; // if continued, will return to test + return pj->BreakReturn(pile, m_label); // sends the results and releases the stack + } + + // terminates if there is an error + if ( !pile->IsOk() ) + { + return pj->Return(pile); // sends the results and releases the stack + } + + // returns to the test again + if (!pile->SetState(pile->GivState()-1, 0)) return false; + continue; + } +} + +void CBotRepeat :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack + if ( pile == NULL ) return; + + switch( pile->GivState() ) + { // there are two possible states (depending on recovery) + case 0: + // evaluates the condition + m_NbIter->RestoreState(pile, bMain); + return; + + case 1: + // evaluates the associated statement block + if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain); + return; + } +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compile the instruction "do" + +CBotDo::CBotDo() +{ + m_Condition = + m_Block = NULL; // NULL so that delete is not possible further + name = "CBotDo"; // debug +} + +CBotDo::~CBotDo() +{ + delete m_Condition; // frees the condition + delete m_Block; // frees the instruction block +} + +CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotDo* inst = new CBotDo(); // creates the object + + CBotToken* pp = p; // preserves at the ^ token (starting position) + + if ( IsOfType( p, TokenTypVar ) && + IsOfType( p, ID_DOTS ) ) + { + inst->m_label = pp->GivString(); // register the name of label + } + + inst->SetToken(p); + if (!IsOfType(p, ID_DO)) return NULL; // should never happen + + CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + + + // looking for a statement block after the do + IncLvl(inst->m_label); + inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); + DecLvl(); + + if ( pStk->IsOk() ) + { + if (IsOfType(p, ID_WHILE)) + { + if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) ) + { + // the condition exists + if (IsOfType(p, ID_SEP)) + { + return pStack->Return(inst, pStk); // return an object to the application + } + pStk->SetError(TX_ENDOF, p->GivStart()); + } + } + pStk->SetError(TX_WHILE, p->GivStart()); + } + + delete inst; // error, frees up + return pStack->Return(NULL, pStk); // no object, the error is on the stack +} + +// executes instruction "do" + +bool CBotDo :: Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); // adds an item to the stack + // or find in case of recovery +// if ( pile == EOX ) return true; + + if ( pile->IfStep() ) return false; + + while( true ) switch( pile->GivState() ) // executes the loop + { // there are two possible states (depending on recovery) + case 0: + // evaluates the associated statement block + if ( m_Block != NULL && + !m_Block->Execute(pile) ) + { + if (pile->IfContinue(1, m_label)) continue; // if continued, will return to test + return pj->BreakReturn(pile, m_label); // sends the results and releases the stack + } + + // terminates if there is an error + if ( !pile->IsOk() ) + { + return pj->Return(pile); // sends the results and releases the stack + } + + if (!pile->SetState(1)) return false; // ready for further + + case 1: + // evaluates the condition + if ( !m_Condition->Execute(pile) ) return false; // interrupted here ? + + // the result of the condition is on the stack + + // terminates if an error or if the condition is false + if ( !pile->IsOk() || pile->GivVal() != true ) + { + return pj->Return(pile); // sends the results and releases the stack + } + + // returns to instruction block to start + if (!pile->SetState(0, 0)) return false; + continue; + } +} + +void CBotDo :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack + if ( pile == NULL ) return; + + switch( pile->GivState() ) + { // there are two possible states (depending on recovery) + case 0: + // restores the assosiated statement's block + if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain); + return; + + case 1: + // restores the condition + m_Condition->RestoreState(pile, bMain); + return; + } +} + + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "for" + +CBotFor::CBotFor() +{ + m_Init = + m_Test = + m_Incr = + m_Block = NULL; // NULL so that delete is not possible further + name = "CBotFor"; // debug +} + +CBotFor::~CBotFor() +{ + delete m_Init; + delete m_Test; + delete m_Incr; + delete m_Block; // frees the instruction block +} + +CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotFor* inst = new CBotFor(); // creates the object + CBotToken* pp = p; // preserves at the ^ token (starting position) + + if ( IsOfType( p, TokenTypVar ) && + IsOfType( p, ID_DOTS ) ) + { + inst->m_label = pp->GivString(); // register the name of label + } + + inst->SetToken(p); + if (!IsOfType(p, ID_FOR)) return NULL; // should never happen + + if ( !IsOfType(p, ID_OPENPAR)) // missing parenthesis ? + { + pStack->SetError(TX_OPENPAR, p->GivStart()); + return NULL; + } + + CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp + + // compiles instructions for initialization + inst->m_Init = CBotListExpression::Compile( p, pStk ); + if ( pStk->IsOk() ) + { + if ( !IsOfType(p, ID_SEP)) // lack the semicolon? + { + pStack->SetError(TX_OPENPAR, p->GivStart()); + delete inst; + return pStack->Return(NULL, pStk); // no object, the error is on the stack + } + inst->m_Test = CBotBoolExpr::Compile( p, pStk ); + if ( pStk->IsOk() ) + { + if ( !IsOfType(p, ID_SEP)) // lack the semicolon? + { + pStack->SetError(TX_OPENPAR, p->GivStart()); + delete inst; + return pStack->Return(NULL, pStk); // no object, the error is on the stack + } + inst->m_Incr = CBotListExpression::Compile( p, pStk ); + if ( pStk->IsOk() ) + { + if ( IsOfType(p, ID_CLOSEPAR)) // missing parenthesis ? + { + IncLvl(inst->m_label); + inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true ); + DecLvl(); + if ( pStk->IsOk() ) + return pStack->Return(inst, pStk);; + } + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + } + } + } + + delete inst; // error, frees up + return pStack->Return(NULL, pStk); // no object, the error is on the stack +} + +// execution of instruction "for" + +bool CBotFor :: Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this, true); // adds an item to the stack (variables locales) + // or find in case of recovery +// if ( pile == EOX ) return true; + + if ( pile->IfStep() ) return false; + + while( true ) switch( pile->GivState() ) // executes the loop + { // there are four possible states (depending on recovery) + case 0: + // initialize + if ( m_Init != NULL && + !m_Init->Execute(pile) ) return false; // interrupted here ? + if (!pile->SetState(1)) return false; // ready for further + + case 1: + // evaluates the condition + if ( m_Test != NULL ) // no strings attached? -> True! + { + if (!m_Test->Execute(pile) ) return false; // interrupted here ? + + // the result of the condition is on the stack + + // terminates if an error or if the condition is false + if ( !pile->IsOk() || pile->GivVal() != true ) + { + return pj->Return(pile); // sends the results and releases the stack + } + } + + // la condition est vrai, passe à la suite + if (!pile->SetState(2)) return false; // ready for further + + case 2: + // evaluates the associated statement block + if ( m_Block != NULL && + !m_Block->Execute(pile) ) + { + if (pile->IfContinue(3, m_label)) continue; // if continued, going on to incrementation + return pj->BreakReturn(pile, m_label); // sends the results and releases the stack + } + + // terminates if there is an error + if ( !pile->IsOk() ) + { + return pj->Return(pile); // sends the results and releases the stack + } + + if (!pile->SetState(3)) return false; // ready for further + + case 3: + // evalutate the incrementation + if ( m_Incr != NULL && + !m_Incr->Execute(pile) ) return false; // interrupted here ? + + // returns to the test again + if (!pile->SetState(1, 0)) return false; // returns to the test + continue; + } +} + +void CBotFor :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack (variables locales) + if ( pile == NULL ) return; + + switch( pile->GivState() ) + { // there are four possible states (depending on recovery) + case 0: + // initialize + if ( m_Init != NULL ) m_Init->RestoreState(pile, true); // interrupted here ! + return; + + case 1: + if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variables definitions + + // evaluates the condition + if ( m_Test != NULL ) m_Test->RestoreState(pile, true); // interrupted here ! + return; + + case 2: + if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variable definitions + + // evaluates the associated statement block + if ( m_Block != NULL ) m_Block->RestoreState(pile, true); + return; + + case 3: + if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variable definitions + + // evaluate the incrementation + if ( m_Incr != NULL ) m_Incr->RestoreState(pile, true); // interrupted here ! + return; + } +} + +////////////////////////////////////////////////////////////////////////////////////// +// compiles a list of expressions +// is used only in "for" statement +// in incrementing and intitialisation + +CBotListExpression::CBotListExpression() +{ + m_Expr = NULL; + name = "CBotListExpression"; +} + +CBotListExpression::~CBotListExpression() +{ + delete m_Expr; +} + +// seeks a declaration of variable or expression + +static CBotInstr* CompileInstrOrDefVar(CBotToken* &p, CBotCStack* pStack) +{ + CBotInstr* i = CBotInt::Compile( p, pStack, false, true ); // Is this a declaration of an integer? + if ( i== NULL ) i = CBotFloat::Compile( p, pStack, false, true ); // or a real number? + if ( i== NULL ) i = CBotBoolean::Compile( p, pStack, false, true ); // or a boolean? + if ( i== NULL ) i = CBotIString::Compile( p, pStack, false, true ); // ar a string? + if ( i== NULL ) i = CBotExpression::Compile( p, pStack ); // compiles an expression + return i; +} + +CBotInstr* CBotListExpression::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotListExpression* inst = new CBotListExpression(); + + inst->m_Expr = CompileInstrOrDefVar( p, pStack ); // compile the first expression in a list + if (pStack->IsOk()) + { + while ( IsOfType(p, ID_COMMA) ) // more instructions? + { + CBotInstr* i = CompileInstrOrDefVar( p, pStack ); // Is this a declaration of an integer? + inst->m_Expr->AddNext(i); // added after + if ( !pStack->IsOk() ) + { + delete inst; + return NULL; // no object, the error is on the stack + } + } + return inst; + } + delete inst; + return NULL; +} + +bool CBotListExpression::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(); // essential + CBotInstr* p = m_Expr; // the first expression + + int state = pile->GivState(); + while (state-->0) p = p->GivNext(); // returns to the interrupted operation + + if ( p != NULL ) while (true) + { + if ( !p->Execute(pile) ) return false; + p = p->GivNext(); + if ( p == NULL ) break; + if (!pile->IncState()) return false; // ready for next + } + return pj->Return(pile); +} + +void CBotListExpression::RestoreState(CBotStack* &pj, bool bMain) +{ + CBotStack* pile = pj; + int state = 0x7000; + + if ( bMain ) + { + pile = pj->RestoreStack(); + if ( pile == NULL ) return; + state = pile->GivState(); + } + + CBotInstr* p = m_Expr; // the first expression + + while (p != NULL && state-->0) + { + p->RestoreState(pile, false); + p = p->GivNext(); // returns to the interrupted operation + } + + if ( p != NULL ) + { + p->RestoreState(pile, bMain); + } +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "switch" + +CBotSwitch::CBotSwitch() +{ + m_Value = + m_Block = NULL; // NULL so that delete is not possible further + name = "CBotSwitch"; // debug +} + +CBotSwitch::~CBotSwitch() +{ + delete m_Value; // frees the value + delete m_Block; // frees the instruction block +} + + +CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotSwitch* inst = new CBotSwitch(); // creates the object + CBotToken* pp = p; // preserves at the ^ token (starting position) + + inst->SetToken(p); + if (!IsOfType(p, ID_SWITCH)) return NULL; // should never happen + + CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + + if ( IsOfType(p, ID_OPENPAR ) ) + { + if ( NULL != (inst->m_Value = CBotExpression::Compile( p, pStk )) ) + { + if ( pStk->GivType() < CBotTypLong ) + { + if ( IsOfType(p, ID_CLOSEPAR ) ) + { + if ( IsOfType(p, ID_OPBLK ) ) + { + IncLvl(); + + while( !IsOfType( p, ID_CLBLK ) ) + { + if ( p->GivType() == ID_CASE || p->GivType() == ID_DEFAULT) + { + CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp + + CBotInstr* i = CBotCase::Compile( p, pStk2 ); + if (i == NULL) + { + delete inst; + return pStack->Return(NULL, pStk2); + } + delete pStk2; + if ( inst->m_Block == NULL ) inst->m_Block = i; + else inst->m_Block->AddNext(i); + continue; + } + + if ( inst->m_Block == NULL ) + { + pStk->SetError(TX_NOCASE, p->GivStart()); + delete inst; + return pStack->Return(NULL, pStk); + } + + CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true ); + if ( !pStk->IsOk() ) + { + delete inst; + return pStack->Return(NULL, pStk); + } + inst->m_Block->AddNext(i); + + if ( p == NULL ) + { + pStk->SetError(TX_CLOSEBLK, -1); + delete inst; + return pStack->Return(NULL, pStk); + } + } + DecLvl(); + + if ( inst->m_Block == NULL ) + { + pStk->SetError(TX_NOCASE, p->GivStart()); + delete inst; + return pStack->Return(NULL, pStk); + } + // the statement block is ok + return pStack->Return(inst, pStk); // return an object to the application + } + pStk->SetError( TX_OPENBLK, p->GivStart() ); + } + pStk->SetError( TX_CLOSEPAR, p->GivStart() ); + } + pStk->SetError( TX_BADTYPE, p->GivStart() ); + } + } + pStk->SetError( TX_OPENPAR, p->GivStart()); + + delete inst; // error, frees up + return pStack->Return(NULL, pStk); // no object, the error is on the stack +} + +// executes instruction "switch" + +bool CBotSwitch :: Execute(CBotStack* &pj) +{ + CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack +// if ( pile1 == EOX ) return true; + + CBotInstr* p = m_Block; // first expression + + int state = pile1->GivState(); + if (state == 0) + { + if ( !m_Value->Execute(pile1) ) return false; + pile1->SetState(state = -1); + } + + if ( pile1->IfStep() ) return false; + + if ( state == -1 ) + { + state = 0; + int val = pile1->GivVal(); // result of the value + + CBotStack* pile2 = pile1->AddStack(); + while ( p != NULL ) // search for the corresponding case in a list + { + state++; + if ( p->CompCase( pile2, val ) ) break; // found the case + p = p->GivNext(); + } + pile2->Delete(); + + if ( p == NULL ) return pj->Return(pile1); // completed if nothing + + if ( !pile1->SetState(state) ) return false; + } + + p = m_Block; // returns to the beginning + while (state-->0) p = p->GivNext(); // advance in the list + + while( p != NULL ) + { + if ( !p->Execute(pile1) ) return pj->BreakReturn(pile1); + if ( !pile1->IncState() ) return false; + p = p->GivNext(); + } + return pj->Return(pile1); +} + +void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack + if ( pile1 == NULL ) return; + + CBotInstr* p = m_Block; // first expression + + int state = pile1->GivState(); + if (state == 0) + { + m_Value->RestoreState(pile1, bMain); + return; + } + + if ( state == -1 ) + { + return; + } + +// p = m_Block; // returns to the beginning + while ( p != NULL && state-- > 0 ) + { + p->RestoreState(pile1, false); + p = p->GivNext(); // advance in the list + } + + if( p != NULL ) + { + p->RestoreState(pile1, true); + return; + } +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "case" +// we are bound to the statement block "switch" + +CBotCase::CBotCase() +{ + m_Value = NULL; // NULL so that delete is not possible further + name = "CBotCase"; // debug +} + +CBotCase::~CBotCase() +{ + delete m_Value; // frees the value +} + + +CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCase* inst = new CBotCase(); // creates the object + CBotToken* pp = p; // preserves at the ^ token (starting position) + + inst->SetToken(p); + if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return NULL; // should never happen + + if ( pp->GivType() == ID_CASE ) + { + pp = p; + inst->m_Value = CBotExprNum::Compile(p, pStack); + if ( inst->m_Value == NULL ) + { + pStack->SetError( TX_BADNUM, pp ); + delete inst; + return NULL; + } + } + if ( !IsOfType( p, ID_DOTS )) + { + pStack->SetError( TX_MISDOTS, p->GivStart() ); + delete inst; + return NULL; + } + + return inst; +} + +// execution of instruction "case" + +bool CBotCase::Execute(CBotStack* &pj) +{ + return true; // the "case" statement does nothing! +} + +void CBotCase::RestoreState(CBotStack* &pj, bool bMain) +{ +} + +// routine to find the entry point of "case" +// corresponding to the value seen + +bool CBotCase::CompCase(CBotStack* &pile, int val) +{ + if ( m_Value == NULL ) return true; // "default" case + + while (!m_Value->Execute(pile)); // puts the value on the correspondent stack (without interruption) + return (pile->GivVal() == val); // compared with the given value +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "break" or "continu" + +CBotBreak::CBotBreak() +{ + name = "CBotBreak"; // debug +} + +CBotBreak::~CBotBreak() +{ +} + +CBotInstr* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotToken* pp = p; // preserves at the ^ token (starting position) + int type = p->GivType(); + + if (!IsOfType(p, ID_BREAK, ID_CONTINUE)) return NULL; // should never happen + + if ( !ChkLvl(CBotString(), type ) ) + { + pStack->SetError(TX_BREAK, pp); + return NULL; // no object, the error is on the stack + } + + CBotBreak* inst = new CBotBreak(); // creates the object + inst->SetToken(pp); // keeps the operation + + pp = p; + if ( IsOfType( p, TokenTypVar ) ) + { + inst->m_label = pp->GivString(); // register the name of label + if ( !ChkLvl(inst->m_label, type ) ) + { + delete inst; + pStack->SetError(TX_NOLABEL, pp); + return NULL; // no object, the error is on the stack + } + } + + if (IsOfType(p, ID_SEP)) + { + return inst; // return what it wants + } + delete inst; + + pStack->SetError(TX_ENDOF, p->GivStart()); + return NULL; // no object, the error is on the stack +} + +// execution of statement "break" or "continu" + +bool CBotBreak :: Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); +// if ( pile == EOX ) return true; + + if ( pile->IfStep() ) return false; + + pile->SetBreak(m_token.GivType()==ID_BREAK ? 1 : 2, m_label); + return pj->Return(pile); +} + +void CBotBreak :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( bMain ) pj->RestoreStack(this); +} + + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "try" + +CBotTry::CBotTry() +{ + m_ListCatch = NULL; + m_FinalInst = + m_Block = NULL; // NULL so that delete is not possible further + name = "CBotTry"; // debug +} + +CBotTry::~CBotTry() +{ + delete m_ListCatch; // frees the list + delete m_Block; // frees the instruction block + delete m_FinalInst; +} + +CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotTry* inst = new CBotTry(); // creates the object + CBotToken* pp = p; // preserves at the ^ token (starting position) + + inst->SetToken(p); + if (!IsOfType(p, ID_TRY)) return NULL; // should never happen + + CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp + + inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk ); + CBotCatch** pn = &inst->m_ListCatch; + + while (pStk->IsOk() && p->GivType() == ID_CATCH) + { + CBotCatch* i = CBotCatch::Compile(p, pStk); + *pn = i; + pn = &i->m_next; + } + + if (pStk->IsOk() && IsOfType( p, ID_FINALLY) ) + { + inst->m_FinalInst = CBotBlock::CompileBlkOrInst( p, pStk ); + } + + if (pStk->IsOk()) + { + return pStack->Return(inst, pStk); // return an object to the application + } + + delete inst; // error, frees up + return pStack->Return(NULL, pStk); // no object, the error is on the stack +} + +// execution of instruction Try +// manages the return of exceptions +// stops (judgements) by suspension +// and "finally" + +bool CBotTry :: Execute(CBotStack* &pj) +{ + int val; + + CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack +// if ( pile1 == EOX ) return true; + + if ( pile1->IfStep() ) return false; + // or find in case of recovery + CBotStack* pile0 = pj->AddStack2(); // adds an element to the secondary stack + CBotStack* pile2 = pile0->AddStack(); + + if ( pile1->GivState() == 0 ) + { + if ( m_Block->Execute(pile1) ) + { + if ( m_FinalInst == NULL ) return pj->Return(pile1); + pile1->SetState(-2); // passes final + } + + val = pile1->GivError(); + if ( val == 0 && CBotStack::m_initimer == 0 ) // mode step? + return false; // does not make the catch + + pile1->IncState(); + pile2->SetState(val); // stores the error number + pile1->SetError(0); // for now there is are more errors! + + if ( val == 0 && CBotStack::m_initimer < 0 ) // mode step? + return false; // does not make the catch + } + + // there was an interruption + // see what it returns + + CBotCatch* pc = m_ListCatch; + int state = (short)pile1->GivState(); // where were we? + val = pile2->GivState(); // what error? + pile0->SetState(1); // marking the GetRunPos + + if ( val >= 0 && state > 0 ) while ( pc != NULL ) + { + if ( --state <= 0 ) + { + // request to the catch block if they feel concerned + // demande au bloc catch s'il se sent concerné + if ( !pc->TestCatch(pile2, val) ) return false; // suspend ! + pile1->IncState(); + } + if ( --state <= 0 ) + { + if ( pile2->GivVal() == true ) + { +// pile0->SetState(1); + + if ( !pc->Execute(pile2) ) return false; // performs the operation + if ( m_FinalInst == NULL ) + return pj->Return(pile2); // ends the try + + pile1->SetState(-2); // passes final + break; + } + pile1->IncState(); + } + pc = pc->m_next; + } + if ( m_FinalInst != NULL && + pile1->GivState() > 0 && val != 0 ) pile1->SetState(-1);// if stop then made the final + + if (pile1->GivState() <= -1) + { +// pile0->SetState(1); + + if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return false; + if (!pile2->IsOk()) return pj->Return(pile2); // keep this exception + pile2->SetError(pile1->GivState()==-1 ? val : 0); // gives the initial error + return pj->Return(pile2); + } + + pile1->SetState(0); // returns to the evaluation + pile0->SetState(0); // returns to the evaluation + if ( val != 0 && m_ListCatch == NULL && m_FinalInst == NULL ) + return pj->Return(pile2); // ends the try without exception + + pile1->SetError(val); // gives the error + return false; // it's not for us +} + + +void CBotTry :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + int val; + CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack + if ( pile1 == NULL ) return; + // or find in case of recovery + CBotStack* pile0 = pj->AddStack2(); // adds an item to the secondary stack + if ( pile0 == NULL ) return; + + CBotStack* pile2 = pile0->RestoreStack(); + if ( pile2 == NULL ) return; + + m_Block->RestoreState(pile1, bMain); + if ( pile0->GivState() == 0 ) + { + return; + } + + // there was an interruption + // see what it returns + + CBotCatch* pc = m_ListCatch; + int state = pile1->GivState(); // where were we ? + val = pile2->GivState(); // what error ? + + if ( val >= 0 && state > 0 ) while ( pc != NULL ) + { + if ( --state <= 0 ) + { + // request to the catch block if they feel concerned + // demande au bloc catch s'il se sent concerné + pc->RestoreCondState(pile2, bMain); // suspend ! + return; + } + if ( --state <= 0 ) + { + if ( pile2->GivVal() == true ) + { + pc->RestoreState(pile2, bMain); // execute the operation + return; + } + } + pc = pc->m_next; + } + + if (pile1->GivState() <= -1) + { + m_FinalInst->RestoreState(pile2, bMain); + return; + } +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "catch" + +CBotCatch::CBotCatch() +{ + m_Cond = + m_Block = NULL; // NULL so that delete is not possible further + m_next = NULL; + + name = "CBotCatch"; // debug +} + +CBotCatch::~CBotCatch() +{ + delete m_Cond; // frees the list + delete m_Block; // frees the instruction block + delete m_next; // and subsequent +} + +CBotCatch* CBotCatch::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotCatch* inst = new CBotCatch(); // creates the object + pStack->SetStartError(p->GivStart()); + + inst->SetToken(p); + if (!IsOfType(p, ID_CATCH)) return NULL; // should never happen + + if (IsOfType(p, ID_OPENPAR)) + { + inst->m_Cond = CBotExpression::Compile(p, pStack); + if (( pStack->GivType() < CBotTypLong || + pStack->GivTypResult().Eq(CBotTypBoolean) )&& pStack->IsOk() ) + { + if (IsOfType(p, ID_CLOSEPAR)) + { + inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStack ); + if ( pStack->IsOk() ) + return inst; // return an object to the application + } + pStack->SetError(TX_CLOSEPAR, p->GivStart()); + } + pStack->SetError(TX_BADTYPE, p->GivStart()); + } + pStack->SetError(TX_OPENPAR, p->GivStart()); + delete inst; // error, frees up + return NULL; // no object, the error is on the stack +} + +// execution of "catch" + +bool CBotCatch :: Execute(CBotStack* &pj) +{ + if ( m_Block == NULL ) return true; + return m_Block->Execute(pj); // executes the associated block +} + +void CBotCatch :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( bMain && m_Block != NULL ) m_Block->RestoreState(pj, bMain); +} + +void CBotCatch :: RestoreCondState(CBotStack* &pj, bool bMain) +{ + m_Cond->RestoreState(pj, bMain); +} + +// routine to see if the catch is to do or not + +bool CBotCatch :: TestCatch(CBotStack* &pile, int val) +{ + if ( !m_Cond->Execute(pile) ) return false; + + if ( val > 0 || pile->GivType() != CBotTypBoolean ) + { + CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean); + var->SetValInt( pile->GivVal() == val ); + pile->SetVar(var); // calls on the stack + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// compiles instruction "throw" + +CBotThrow::CBotThrow() +{ + m_Value = NULL; // NULL so that delete is not possible further + + name = "CBotThrow"; // debug +} + +CBotThrow::~CBotThrow() +{ + delete m_Value; +} + +CBotInstr* CBotThrow::Compile(CBotToken* &p, CBotCStack* pStack) +{ + pStack->SetStartError(p->GivStart()); + + CBotThrow* inst = new CBotThrow(); // creates the object + inst->SetToken(p); + + CBotToken* pp = p; // preserves at the ^ token (starting position) + + if (!IsOfType(p, ID_THROW)) return NULL; // should never happen + + inst->m_Value = CBotExpression::Compile( p, pStack ); + + if (pStack->GivType() < CBotTypLong && pStack->IsOk()) + { + return inst; // return an object to the application + } + pStack->SetError(TX_BADTYPE, pp); + + delete inst; // error, frees up + return NULL; // no object, the error is on the stack +} + +// execution of instruction "throw" + +bool CBotThrow :: Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); +// if ( pile == EOX ) return true; + + if ( pile->GivState() == 0 ) + { + if ( !m_Value->Execute(pile) ) return false; + pile->IncState(); + } + + if ( pile->IfStep() ) return false; + + int val = pile->GivVal(); + if ( val < 0 ) val = TX_BADTHROW; + pile->SetError( val, &m_token ); + return pj->Return( pile ); +} + +void CBotThrow :: RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + + CBotStack* pile = pj->RestoreStack(this); + if ( pile == NULL ) return; + + if ( pile->GivState() == 0 ) + { + m_Value->RestoreState(pile, bMain); + return; + } +} + + + +//////////////////////////////////////////////////////////// + + +CBotStartDebugDD::CBotStartDebugDD() +{ + name = "CBotStartDebugDD"; // debug +} + +CBotStartDebugDD::~CBotStartDebugDD() +{ +} + +CBotInstr* CBotStartDebugDD::Compile(CBotToken* &p, CBotCStack* pStack) +{ + + if (!IsOfType(p, ID_DEBUGDD)) return NULL; // should never happen + + return new CBotStartDebugDD(); // creates the object + +} + +// execution of instruction "throw" + +bool CBotStartDebugDD :: Execute(CBotStack* &pj) +{ + CBotProgram* p = pj->GivBotCall(); + p->m_bDebugDD = true; + + return true; +} + diff --git a/src/CBot/ClassFILE.cpp b/src/CBot/ClassFILE.cpp index 330e814..418ddb3 100644 --- a/src/CBot/ClassFILE.cpp +++ b/src/CBot/ClassFILE.cpp @@ -12,13 +12,15 @@ // * 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/.// ClassFile.cpp
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// ClassFile.cpp
//
-// définition des méthodes pour la classe FILE
+// definition of methods for class FILE
-// Variables statiques
+// Static variables
static CBotClass* m_pClassFILE;
static CBotProgram* m_pFuncFile;
@@ -26,7 +28,7 @@ static int m_CompteurFileOpen = 0; -// Prépare un nom de fichier.
+// Prepares a file name.
void PrepareFilename(CBotString &filename) //DD!
{
@@ -35,110 +37,110 @@ void PrepareFilename(CBotString &filename) //DD! pos = filename.ReverseFind('\\');
if ( pos > 0 )
{
- filename = filename.Mid(pos+1); // enlève les dossiers
+ filename = filename.Mid(pos+1); // remove the records (files)??
}
pos = filename.ReverseFind('/');
if ( pos > 0 )
{
- filename = filename.Mid(pos+1); // aussi ceux avec /
+ filename = filename.Mid(pos+1); // also those with /
}
pos = filename.ReverseFind(':');
if ( pos > 0 )
{
- filename = filename.Mid(pos+1); // enlève aussi la lettre d'unité C:
+ filename = filename.Mid(pos+1); // also removes the drive letter C:
}
filename = CBotString("files\\") + filename;
}
-// constructeur de la classe
-// reçois le nom du fichier en paramètre
+// constructor of the class
+// gets the filename as a parameter
-// exécution
+// execution
bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
CBotString mode;
- // accepte sans paramètre
- if ( pVar == NULL ) return TRUE;
+ // accepts no parameters
+ if ( pVar == NULL ) return true;
- // qui doit être une chaîne de caractères
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
+ // must be a string
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
CBotString filename = pVar->GivValString();
PrepareFilename(filename); //DR
- // il peut y avoir un second paramètre
+ // there may be a second parameter
pVar = pVar->GivNext();
if ( pVar != NULL )
{
- // récupère le mode
+ // recovers the mode
mode = pVar->GivValString();
- if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
+ if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ // no third parameter, only two or one possible
+ if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return false; }
}
- // enregistre le nom du fichier
+ // save the file name
pVar = pThis->GivItem("filename");
pVar->SetValString(filename);
if ( ! mode.IsEmpty() )
{
- // ouvre le ficher demandé
+ // 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 ++;
- // enregiste le canal du fichier
+ // save the handle of file
pVar = pThis->GivItem("handle");
pVar->SetValInt((long)pFile);
}
- return TRUE;
+ return true;
}
// compilation
CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
{
- // accepte sans paramètre
+ // accepts no parameters
if ( pVar == NULL ) return CBotTypResult( 0 );
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // il peut y avoir un second paramètre
+ // there may be a second parameter
pVar = pVar->GivNext();
if ( pVar != NULL )
{
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // pas de 3e paramètre
+ // no third parameter
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 );
}
-// destructeur de la classe
+// destructor of the class
-// exécution
+// execution
bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // récupère l'élément "handle"
+ // retrieves the element "handle"
pVar = pThis->GivItem("handle");
- // pas ouvert ? pas de problème
- if ( pVar->GivInit() != IS_DEF) return TRUE;
+ // not open? no problem
+ if ( pVar->GivInit() != IS_DEF) return true;
FILE* pFile= (FILE*)pVar->GivValInt();
fclose(pFile);
@@ -146,112 +148,112 @@ bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception pVar->SetInit(IS_NAN);
- return TRUE;
+ return true;
}
-// méthode FILE :: open
-// reçois le mode r/w en paramètre
+// FILE :: open method
+// get the r / w mode as a parameter
-// exécution
+// execution
bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il doit y avoir un paramètre
- if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
+ // there must be a parameter
+ if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
- // qui doit être une chaîne de caractères
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
+ // must be a string
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
- // il peut y avoir un second paramètre
+ // there may be a second parameter
if ( pVar->GivNext() != NULL )
{
- // dans ce cas le premier paramètre est le nom du fichier
+ // in this case the first parameter is the file name
CBotString filename = pVar->GivValString();
PrepareFilename(filename); //DR
- // enregistre le nom du fichier
+ // saves the file name
CBotVar* pVar2 = pThis->GivItem("filename");
pVar2->SetValString(filename);
- // paramètre suivant est le mode
+ // next parameter is the mode
pVar = pVar -> GivNext();
}
CBotString mode = pVar->GivValString();
- if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
+ if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ // No third parameter
+ if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return false; }
- // récupère l'élément "handle"
+ // retrieves the element "handle"
pVar = pThis->GivItem("handle");
- // qui doit pas être initialisé
- if ( pVar->GivInit() == IS_DEF) { Exception = CBotErrFileOpen; return FALSE; }
+ // which must not be initialized
+ if ( pVar->GivInit() == IS_DEF) { Exception = CBotErrFileOpen; return false; }
- // reprend le nom du fichier
+ // contains filename
pVar = pThis->GivItem("filename");
CBotString filename = pVar->GivValString();
- PrepareFilename(filename); //DD! (si le nom a été attribué par h.filename = "...";
+ PrepareFilename(filename); //DD! (if the name was assigned by h.filename = "...";
- // ouvre le ficher demandé
+ // open requsted file
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 ++;
- // enregiste le canal du fichier
+ // saves the handle of file
pVar = pThis->GivItem("handle");
pVar->SetValInt((long)pFile);
- pResult->SetValInt(TRUE); //DR
- return TRUE;
+ pResult->SetValInt(true); //DR
+ return true;
}
// compilation
CBotTypResult cfopen (CBotVar* pThis, CBotVar* &pVar)
{
- // il doit y avoir un paramètre
+ // there must be a parameter
if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // il peut y avoir un second paramètre
+ // there may be a second parameter
pVar = pVar->GivNext();
if ( pVar != NULL )
{
- // qui doit être une chaine
+ // must be a string
if ( pVar->GivType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
- // pas de 3e paramètre
+ // no third parameter
if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
}
- // le résultat est de type bool
+ // the result is of type bool
return CBotTypResult(CBotTypBoolean); //DR
}
-// méthode FILE :: close
+// FILE :: close method
-// exécution
+// execution
bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il ne doit pas y avoir de paramètre
+ // it should not be any parameter
if ( pVar != NULL ) return CBotErrOverParam;
- // récupère l'élément "handle"
+ // 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);
@@ -259,75 +261,75 @@ bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception) pVar->SetInit(IS_NAN);
- return TRUE;
+ return true;
}
// compilation
CBotTypResult cfclose (CBotVar* pThis, CBotVar* &pVar)
{
- // il ne doit pas y avoir de paramètre
+ // it should not be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat "void"
+ // function returns a result "void"
return CBotTypResult( 0 );
}
-// méthode FILE :: writeln
+// FILE :: writeln method
-// exécution
+// execution
bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il doit y avoir un paramètre
- if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
+ // there must be a parameter
+ if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
- // qui doit être une chaîne de caractères
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
+ // must be a string
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
CBotString param = pVar->GivValString();
- // récupère l'élément "handle"
+ //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);
- // en cas d'erreur génère une exception
- if ( res < 0 ) { Exception = CBotErrWrite; return FALSE; }
+ // on error throws an exception
+ if ( res < 0 ) { Exception = CBotErrWrite; return false; }
- return TRUE;
+ return true;
}
// compilation
CBotTypResult cfwrite (CBotVar* pThis, CBotVar* &pVar)
{
- // il doit y avoir un paramètre
+ // there must be a parameter
if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
- // qui doit être une chaîne de caractères
+ // must be a string
if ( pVar->GivType() != CBotTypString ) return CBotTypResult( CBotErrBadString );
- // pas d'autre paramètre
+ // no other parameter
if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat void
+ // function returns "void" result
return CBotTypResult( 0 );
}
-// méthode FILE :: readln
+// FILE :: readln method
-// exécution
+// execution
bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ // there shouldn't be any parameter
+ if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
- // récupère l'élément "handle"
+ //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();
@@ -339,51 +341,51 @@ bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception) for ( i = 0 ; i < 2000 ; i++ ) if (chaine[i] == '\n') chaine[i] = 0;
- // en cas d'erreur génère une exception
- if ( ferror(pFile) ) { Exception = CBotErrRead; return FALSE; }
+ // on error throws an exception
+ if ( ferror(pFile) ) { Exception = CBotErrRead; return false; }
pResult->SetValString( chaine );
- return TRUE;
+ return true;
}
// compilation
CBotTypResult cfread (CBotVar* pThis, CBotVar* &pVar)
{
- // il ne doit pas y avoir de paramètre
+ // there shouldn't be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat "string"
+ // function return "string" result
return CBotTypResult( CBotTypString );
}
-// méthode FILE :: readln
+// FILE :: readln method
-// exécution
+// execution
bool rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
+ // there shouldn't be any parameter
+ if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
- // récupère l'élément "handle"
+ // 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
CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar)
{
- // il ne doit pas y avoir de paramètre
+ // there shouldn't be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
- // la fonction retourne un résultat booleen
+ // function return boolean result
return CBotTypResult( CBotTypBoolean );
}
@@ -393,25 +395,25 @@ CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar) void InitClassFILE()
{
-// crée une classe pour la gestion des fichiers
-// l'utilisation en est la suivante:
+// creates a class for file management
+// the usage is as follows:
// file canal( "NomFichier.txt" )
-// canal.open( "r" ); // ouvre en lecture
-// s = canal.readln( ); // lit une ligne
-// canal.close(); // referme le fichier
+// canal.open( "r" ); // open reading
+// s = canal.readln( ); // reads a line
+// canal.close(); // closes the file
- // crée la classe FILE
+ // create class FILE
m_pClassFILE = new CBotClass("file", NULL);
- // ajoute le composant ".filename"
+ // add the component ".filename"
m_pClassFILE->AddItem("filename", CBotTypString);
- // ajoute le composant ".handle"
+ // add the component ".handle"
m_pClassFILE->AddItem("handle", CBotTypInt, PR_PRIVATE);
- // défini un constructeur et un destructeur
+ // define a constructor and destructor
m_pClassFILE->AddFunction("file", rfconstruct, cfconstruct );
m_pClassFILE->AddFunction("~file", rfdestruct, NULL );
- // défini les méthodes associées
+ // defined associated methods
m_pClassFILE->AddFunction("open", rfopen, cfopen );
m_pClassFILE->AddFunction("close", rfclose, cfclose );
m_pClassFILE->AddFunction("writeln", rfwrite, cfwrite );
@@ -421,6 +423,6 @@ void InitClassFILE() m_pFuncFile = new CBotProgram( );
CBotStringArray ListFonctions;
m_pFuncFile->Compile( "public file openfile(string name, string mode) {return new file(name, mode);}", ListFonctions);
- m_pFuncFile->SetIdent(-2); // identificateur spécial pour RestoreState dans cette fonction
+ m_pFuncFile->SetIdent(-2); // restoreState as a special identifier for this function
}
diff --git a/src/CBot/StringFunctions.cpp b/src/CBot/StringFunctions.cpp index 27332db..213b956 100644 --- a/src/CBot/StringFunctions.cpp +++ b/src/CBot/StringFunctions.cpp @@ -1,434 +1,436 @@ -// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU General Public License as published by
-// * the Free Software Foundation, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// * GNU General Public License for more details.
-// *
-// * You should have received a copy of the GNU General Public License
-// * along with this program. If not, see http://www.gnu.org/licenses/.// définition des fonctions sur les chaînes
-
-
-// donne la longueur d'une chaîne
-// exécution
-
-bool rStrLen( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // pas de second paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // met la longueur sur la pile
- pResult->SetValInt( s.GivLength() );
- return true;
-}
-
-// int xxx ( string )
-// compilation
-
-CBotTypResult cIntStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADPARAM );
-
- // pas de second paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre entier
- return CBotTypResult( CBotTypInt );
-}
-
-
-// donne la partie gauche d'une chaîne
-// exécution
-
-bool rStrLeft( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // prend la partie intéressante
- s = s.Left( n );
-
- // la met sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// string xxx ( string, int )
-// compilation
-
-CBotTypResult cStrStrInt( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-// donne la partie droite d'une chaîne
-// exécution
-
-bool rStrRight( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // prend la partie intéressante
- s = s.Right( n );
-
- // la met sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// donne la partie centrale d'une chaîne
-// exécution
-
-bool rStrMid( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // 3e paramètre optionnel
- if ( pVar->GivNext() != NULL )
- {
- pVar = pVar->GivNext();
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
-
- // récupère ce nombre
- int l = pVar->GivValInt();
-
- // mais pas de 4e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
- // prend la partie intéressante
- s = s.Mid( n, l );
- }
- else
- {
- // prend la partie intéressante
- s = s.Mid( n );
- }
-
- // la met sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// donne la partie centrale d'une chaîne
-// compilation
-
-CBotTypResult cStrStrIntInt( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // 3e paramètre optionnel
- if ( pVar->GivNext() != NULL )
- {
-
- pVar = pVar->GivNext();
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // pas de 4e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
- }
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-
-// donne le nombre contenu dans une chaîne
-// exécution
-
-bool rStrVal( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
- float val = GivNumFloat(s);
-
- // la met la valeur sur la pile
- pResult->SetValFloat( val );
- return true;
-}
-
-// float xxx ( string )
-// compilation
-
-CBotTypResult cFloatStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 2e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre
- return CBotTypResult( CBotTypFloat );
-}
-
-
-// trouve une chaine dans une autre
-// exécution
-
-bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // récupère ce nombre
- CBotString s2 = pVar->GivValString();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
-
- // met le résultat sur la pile
- int res = s.Find(s2);
- pResult->SetValInt( res );
- if ( res < 0 ) pResult->SetInit( IS_NAN );
- return true;
-}
-
-// int xxx ( string, string )
-// compilation
-
-CBotTypResult cIntStrStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre
- return CBotTypResult( CBotTypInt );
-}
-
-// donne une chaine en majuscule
-// exécution
-
-bool rStrUpper( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
-
- s.MakeUpper();
-
- // la met la valeur sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// donne une chaine en minuscules
-// exécution
-
-bool rStrLower( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
-
-
- s.MakeLower();
-
- // la met la valeur sur la pile
- pResult->SetValString( s );
- return true;
-}
-
-// string xxx ( string )
-// compilation
-
-CBotTypResult cStrStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 2e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-
-void InitStringFunctions()
-{
- CBotProgram::AddFunction("strlen", rStrLen, cIntStr );
- CBotProgram::AddFunction("strleft", rStrLeft, cStrStrInt );
- CBotProgram::AddFunction("strright", rStrRight, cStrStrInt );
- CBotProgram::AddFunction("strmid", rStrMid, cStrStrIntInt );
-
- CBotProgram::AddFunction("strval", rStrVal, cFloatStr );
- CBotProgram::AddFunction("strfind", rStrFind, cIntStrStr );
-
- CBotProgram::AddFunction("strupper", rStrUpper, cStrStr );
- CBotProgram::AddFunction("strlower", rStrLower, cStrStr );
-}
+// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// definition of string functions + + +// gives the length of a chain +// execution + +bool rStrLen( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // no second parameter + if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // puts the length of the stack + pResult->SetValInt( s.GivLength() ); + return true; +} + +// int xxx ( string ) +// compilation + +CBotTypResult cIntStr( CBotVar* &pVar, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // to be a string + if ( pVar->GivType() != CBotTypString ) + return CBotTypResult( TX_BADPARAM ); + + // no second parameter + if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM ); + + // the end result is an integer + return CBotTypResult( CBotTypInt ); +} + + +// gives the left side of a chain +// execution + +bool rStrLeft( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // it takes a second parameter + pVar = pVar->GivNext(); + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // which must be a number + if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; } + + // retrieves this number + int n = pVar->GivValInt(); + + // no third parameter + if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; } + + // takes the interesting part + s = s.Left( n ); + + // puts on the stack + pResult->SetValString( s ); + return true; +} + +// string xxx ( string, int ) +// compilation + +CBotTypResult cStrStrInt( CBotVar* &pVar, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // to be a string + if ( pVar->GivType() != CBotTypString ) + return CBotTypResult( TX_BADSTRING ); + + // it takes a second parameter + pVar = pVar->GivNext(); + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // which must be a number + if ( pVar->GivType() > CBotTypDouble ) + return CBotTypResult( TX_BADNUM ); + + // no third parameter + if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM ); + + // the end result is a string + return CBotTypResult( CBotTypString ); +} + +// gives the right of a string +// execution + +bool rStrRight( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // it takes a second parameter + pVar = pVar->GivNext(); + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // which must be a number + if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; } + + // retrieves this number + int n = pVar->GivValInt(); + + // no third parameter + if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; } + + // takes the interesting part + s = s.Right( n ); + + // puts on the stack + pResult->SetValString( s ); + return true; +} + +// gives the central part of a chain +// execution + +bool rStrMid( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // it takes a second parameter + pVar = pVar->GivNext(); + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // which must be a number + if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; } + + // retrieves this number + int n = pVar->GivValInt(); + + // third parameter optional + if ( pVar->GivNext() != NULL ) + { + pVar = pVar->GivNext(); + + // which must be a number + if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; } + + // retrieves this number + int l = pVar->GivValInt(); + + // but no fourth parameter + if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; } + + // takes the interesting part + s = s.Mid( n, l ); + } + else + { + // takes the interesting part + s = s.Mid( n ); + } + + // puts on the stack + pResult->SetValString( s ); + return true; +} + +// gives the central part of a chain +// compilation + +CBotTypResult cStrStrIntInt( CBotVar* &pVar, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // to be a string + if ( pVar->GivType() != CBotTypString ) + return CBotTypResult( TX_BADSTRING ); + + // it takes a second parameter + pVar = pVar->GivNext(); + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // which must be a number + if ( pVar->GivType() > CBotTypDouble ) + return CBotTypResult( TX_BADNUM ); + + // third parameter optional + if ( pVar->GivNext() != NULL ) + { + + pVar = pVar->GivNext(); + // which must be a number + if ( pVar->GivType() > CBotTypDouble ) + return CBotTypResult( TX_BADNUM ); + + // no fourth parameter + if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM ); + } + + // the end result is a string + return CBotTypResult( CBotTypString ); +} + + +// gives the number stored in a string +// execution + +bool rStrVal( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // but no second parameter + if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; } + + float val = GivNumFloat(s); + + // puts the value on the stack + pResult->SetValFloat( val ); + return true; +} + +// float xxx ( string ) +// compilation + +CBotTypResult cFloatStr( CBotVar* &pVar, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // to be a string + if ( pVar->GivType() != CBotTypString ) + return CBotTypResult( TX_BADSTRING ); + + // no second parameter + if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM ); + + // the end result is a number + return CBotTypResult( CBotTypFloat ); +} + + +// find string in other +// exécution + +bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // it takes a second parameter + pVar = pVar->GivNext(); + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // retrieves this number + CBotString s2 = pVar->GivValString(); + + // no third parameter + if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; } + + // puts the result on the stack + int res = s.Find(s2); + pResult->SetValInt( res ); + if ( res < 0 ) pResult->SetInit( IS_NAN ); + return true; +} + +// int xxx ( string, string ) +// compilation + +CBotTypResult cIntStrStr( CBotVar* &pVar, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // to be a string + if ( pVar->GivType() != CBotTypString ) + return CBotTypResult( TX_BADSTRING ); + + // it takes a second parameter + pVar = pVar->GivNext(); + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // to be a string + if ( pVar->GivType() != CBotTypString ) + return CBotTypResult( TX_BADSTRING ); + + // no third parameter + if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM ); + + // the end result is a number + return CBotTypResult( CBotTypInt ); +} + +// gives a string to uppercase +// exécution + +bool rStrUpper( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // but no second parameter + if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; } + + + s.MakeUpper(); + + // puts the value on the stack + pResult->SetValString( s ); + return true; +} + +// gives a string to lowercase +// exécution + +bool rStrLower( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; } + + // to be a string + if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; } + + // get the contents of the string + CBotString s = pVar->GivValString(); + + // but no second parameter + if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; } + + + s.MakeLower(); + + // puts the value on the stack + pResult->SetValString( s ); + return true; +} + +// string xxx ( string ) +// compilation + +CBotTypResult cStrStr( CBotVar* &pVar, void* pUser ) +{ + // it takes a parameter + if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM ); + + // to be a string + if ( pVar->GivType() != CBotTypString ) + return CBotTypResult( TX_BADSTRING ); + + // no second parameter + if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM ); + + // the end result is a string + return CBotTypResult( CBotTypString ); +} + + +void InitStringFunctions() +{ + CBotProgram::AddFunction("strlen", rStrLen, cIntStr ); + CBotProgram::AddFunction("strleft", rStrLeft, cStrStrInt ); + CBotProgram::AddFunction("strright", rStrRight, cStrStrInt ); + CBotProgram::AddFunction("strmid", rStrMid, cStrStrIntInt ); + + CBotProgram::AddFunction("strval", rStrVal, cFloatStr ); + CBotProgram::AddFunction("strfind", rStrFind, cIntStrStr ); + + CBotProgram::AddFunction("strupper", rStrUpper, cStrStr ); + CBotProgram::AddFunction("strlower", rStrLower, cStrStr ); +} diff --git a/src/CBot/_Copy.bat b/src/CBot/_Copy.bat deleted file mode 100644 index 510dc5a..0000000 --- a/src/CBot/_Copy.bat +++ /dev/null @@ -1,2 +0,0 @@ -copy debug\cbot.dll "F:\Program Files\Ceebot\cbot.dll"
-cls
\ No newline at end of file diff --git a/src/CBot/colobot.ini b/src/CBot/colobot.ini deleted file mode 100644 index 32163db..0000000 --- a/src/CBot/colobot.ini +++ /dev/null @@ -1,49 +0,0 @@ -[Directory]
-scene=scene
-savegame=savegame
-public=program
-user=user
-[Setup]
-TotoMode=1
-Tooltips=1
-InterfaceGlint=1
-NiceMouse=0
-Movies=1
-NiceReset=1
-HimselfDamage=1
-CameraScroll=1
-CameraInvertX=0
-InterfaceEffect=1
-GroundShadow=1
-GroundSpot=1
-ObjectDirty=1
-FogMode=1
-LensMode=1
-SkyMode=1
-PlanetMode=1
-LightMode=1
-UseJoystick=0
-ParticuleDensity=1.00
-ClippingDistance=1.00
-ObjectDetail=2.00
-GadgetQuantity=1.00
-TextureQuality=1
-AudioVolume=20
-MidiVolume=15
-Sound3D=0
-EditIndentMode=1
-EditIndentValue=4
-KeyMap=37+0 39+0 38+0 40+0 16+0 17+0 32+258 96+262 13+257 107+261 109+260 9+259 36+263 27+0 112+0 113+0 110+0 115+0 116+0 117+0
-[Engine]
-AlphaMode=1
-StateColor=-1
-BlackSrcBlend=0
-BlackDestBlend=0
-WhiteSrcBlend=0
-WhiteDestBlend=0
-DiffuseSrcBlend=0
-DiffuseDestBlend=0
-AlphaSrcBlend=0
-AlphaDestBlend=0
-[Gamer]
-LastName=Player
diff --git a/src/CBot/resource.h b/src/CBot/resource.h index 6bf48e1..da1ad23 100644 --- a/src/CBot/resource.h +++ b/src/CBot/resource.h @@ -12,7 +12,9 @@ // * 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/.//{{NO_DEPENDENCIES}}
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+#pragma once
#ifndef _RESOURCE_H_
#define _RESOURCE_H_
@@ -173,4 +175,3 @@ enum EID #define TX_ERRWRITE 6015
#endif //_RESOURCE_H_
-
diff --git a/src/CBot/TestCBot/CBotConsoleDlg.cpp b/src/CBot/tests/TestCBot/CBotConsoleDlg.cpp index 55a271a..55a271a 100644 --- a/src/CBot/TestCBot/CBotConsoleDlg.cpp +++ b/src/CBot/tests/TestCBot/CBotConsoleDlg.cpp diff --git a/src/CBot/TestCBot/CBotConsoleDlg.h b/src/CBot/tests/TestCBot/CBotConsoleDlg.h index f289a4d..f289a4d 100644 --- a/src/CBot/TestCBot/CBotConsoleDlg.h +++ b/src/CBot/tests/TestCBot/CBotConsoleDlg.h diff --git a/src/CBot/TestCBot/ChildFrm.cpp b/src/CBot/tests/TestCBot/ChildFrm.cpp index 4c40f90..4c40f90 100644 --- a/src/CBot/TestCBot/ChildFrm.cpp +++ b/src/CBot/tests/TestCBot/ChildFrm.cpp diff --git a/src/CBot/TestCBot/ChildFrm.h b/src/CBot/tests/TestCBot/ChildFrm.h index 2ad57b6..2ad57b6 100644 --- a/src/CBot/TestCBot/ChildFrm.h +++ b/src/CBot/tests/TestCBot/ChildFrm.h diff --git a/src/CBot/TestCBot/MainFrm.cpp b/src/CBot/tests/TestCBot/MainFrm.cpp index 6669350..6669350 100644 --- a/src/CBot/TestCBot/MainFrm.cpp +++ b/src/CBot/tests/TestCBot/MainFrm.cpp diff --git a/src/CBot/TestCBot/MainFrm.h b/src/CBot/tests/TestCBot/MainFrm.h index a1d34f4..a1d34f4 100644 --- a/src/CBot/TestCBot/MainFrm.h +++ b/src/CBot/tests/TestCBot/MainFrm.h diff --git a/src/CBot/TestCBot/PerformDlg.cpp b/src/CBot/tests/TestCBot/PerformDlg.cpp index 8abbb4b..8abbb4b 100644 --- a/src/CBot/TestCBot/PerformDlg.cpp +++ b/src/CBot/tests/TestCBot/PerformDlg.cpp diff --git a/src/CBot/TestCBot/PerformDlg.h b/src/CBot/tests/TestCBot/PerformDlg.h index 29d567f..29d567f 100644 --- a/src/CBot/TestCBot/PerformDlg.h +++ b/src/CBot/tests/TestCBot/PerformDlg.h diff --git a/src/CBot/TestCBot/Routines.cpp b/src/CBot/tests/TestCBot/Routines.cpp index b37f027..b37f027 100644 --- a/src/CBot/TestCBot/Routines.cpp +++ b/src/CBot/tests/TestCBot/Routines.cpp diff --git a/src/CBot/TestCBot/StdAfx.cpp b/src/CBot/tests/TestCBot/StdAfx.cpp index 7dd0f00..7dd0f00 100644 --- a/src/CBot/TestCBot/StdAfx.cpp +++ b/src/CBot/tests/TestCBot/StdAfx.cpp diff --git a/src/CBot/TestCBot/StdAfx.h b/src/CBot/tests/TestCBot/StdAfx.h index c3659fb..c3659fb 100644 --- a/src/CBot/TestCBot/StdAfx.h +++ b/src/CBot/tests/TestCBot/StdAfx.h diff --git a/src/CBot/TestCBot/TestCBot.clw b/src/CBot/tests/TestCBot/TestCBot.clw index 13f20f4..13f20f4 100644 --- a/src/CBot/TestCBot/TestCBot.clw +++ b/src/CBot/tests/TestCBot/TestCBot.clw diff --git a/src/CBot/TestCBot/TestCBot.cpp b/src/CBot/tests/TestCBot/TestCBot.cpp index a76040a..a76040a 100644 --- a/src/CBot/TestCBot/TestCBot.cpp +++ b/src/CBot/tests/TestCBot/TestCBot.cpp diff --git a/src/CBot/TestCBot/TestCBot.dsp b/src/CBot/tests/TestCBot/TestCBot.dsp index 8ed9b11..8ed9b11 100644 --- a/src/CBot/TestCBot/TestCBot.dsp +++ b/src/CBot/tests/TestCBot/TestCBot.dsp diff --git a/src/CBot/TestCBot/TestCBot.h b/src/CBot/tests/TestCBot/TestCBot.h index b3b15db..c2595b6 100644 --- a/src/CBot/TestCBot/TestCBot.h +++ b/src/CBot/tests/TestCBot/TestCBot.h @@ -26,7 +26,7 @@ #error include 'stdafx.h' before including this file for PCH
#endif
-#include "resource.h" // main symbols
+#include "resource.h" // main symbols
//#include "../CbotDll.h" // librairie CBot
#include "../Cbot.h" // complet pour Browse
@@ -43,7 +43,7 @@ public: CTestCBotApp();
CEdit* m_pConsole;
- CTestCBotView* m_LastActive;
+ CTestCBotView* m_LastActive;
CBotClass* m_pClassPoint;
CBotClass* m_pClassPointIntr;
diff --git a/src/CBot/TestCBot/TestCBot.rc b/src/CBot/tests/TestCBot/TestCBot.rc index 137458c..137458c 100644 --- a/src/CBot/TestCBot/TestCBot.rc +++ b/src/CBot/tests/TestCBot/TestCBot.rc diff --git a/src/CBot/TestCBot/TestCBotDoc.cpp b/src/CBot/tests/TestCBot/TestCBotDoc.cpp index 8880c57..8880c57 100644 --- a/src/CBot/TestCBot/TestCBotDoc.cpp +++ b/src/CBot/tests/TestCBot/TestCBotDoc.cpp diff --git a/src/CBot/TestCBot/TestCBotDoc.h b/src/CBot/tests/TestCBot/TestCBotDoc.h index 548607f..548607f 100644 --- a/src/CBot/TestCBot/TestCBotDoc.h +++ b/src/CBot/tests/TestCBot/TestCBotDoc.h diff --git a/src/CBot/TestCBot/TestCBotView.cpp b/src/CBot/tests/TestCBot/TestCBotView.cpp index bca3c56..bca3c56 100644 --- a/src/CBot/TestCBot/TestCBotView.cpp +++ b/src/CBot/tests/TestCBot/TestCBotView.cpp diff --git a/src/CBot/TestCBot/TestCBotView.h b/src/CBot/tests/TestCBot/TestCBotView.h index 065ee08..065ee08 100644 --- a/src/CBot/TestCBot/TestCBotView.h +++ b/src/CBot/tests/TestCBot/TestCBotView.h diff --git a/src/CBot/TestCBot/a§1.txt b/src/CBot/tests/TestCBot/a§1.txt~ index 0c57950..0c57950 100644 --- a/src/CBot/TestCBot/a§1.txt +++ b/src/CBot/tests/TestCBot/a§1.txt~ diff --git a/src/CBot/TestCBot/res/TestCBot.ico b/src/CBot/tests/TestCBot/res/TestCBot.ico Binary files differindex 06a649d..06a649d 100644 --- a/src/CBot/TestCBot/res/TestCBot.ico +++ b/src/CBot/tests/TestCBot/res/TestCBot.ico diff --git a/src/CBot/TestCBot/res/TestCBot.rc2 b/src/CBot/tests/TestCBot/res/TestCBot.rc2 index b55f0d9..b55f0d9 100644 --- a/src/CBot/TestCBot/res/TestCBot.rc2 +++ b/src/CBot/tests/TestCBot/res/TestCBot.rc2 diff --git a/src/CBot/TestCBot/res/TestCBotDoc.ico b/src/CBot/tests/TestCBot/res/TestCBotDoc.ico Binary files differindex 3545614..3545614 100644 --- a/src/CBot/TestCBot/res/TestCBotDoc.ico +++ b/src/CBot/tests/TestCBot/res/TestCBotDoc.ico diff --git a/src/CBot/TestCBot/res/Toolbar.bmp b/src/CBot/tests/TestCBot/res/Toolbar.bmp Binary files differindex 04a71af..04a71af 100644 --- a/src/CBot/TestCBot/res/Toolbar.bmp +++ b/src/CBot/tests/TestCBot/res/Toolbar.bmp diff --git a/src/CBot/TestCBot/resource.h b/src/CBot/tests/TestCBot/resource.h index d661201..d661201 100644 --- a/src/CBot/TestCBot/resource.h +++ b/src/CBot/tests/TestCBot/resource.h diff --git a/src/CBot/TestCBot/B.txt b/src/CBot/tests/TestCBot/scenarios/B.txt index 53715f8..53715f8 100644 --- a/src/CBot/TestCBot/B.txt +++ b/src/CBot/tests/TestCBot/scenarios/B.txt diff --git a/src/CBot/TestCBot/BUG2.txt b/src/CBot/tests/TestCBot/scenarios/BUG2.txt index 44de05a..44de05a 100644 --- a/src/CBot/TestCBot/BUG2.txt +++ b/src/CBot/tests/TestCBot/scenarios/BUG2.txt diff --git a/src/CBot/TestCBot/Deleted.txt b/src/CBot/tests/TestCBot/scenarios/Deleted.txt index 469a624..469a624 100644 --- a/src/CBot/TestCBot/Deleted.txt +++ b/src/CBot/tests/TestCBot/scenarios/Deleted.txt diff --git a/src/CBot/TestCBot/MaClass.txt b/src/CBot/tests/TestCBot/scenarios/MaClass.txt index ac472b4..ac472b4 100644 --- a/src/CBot/TestCBot/MaClass.txt +++ b/src/CBot/tests/TestCBot/scenarios/MaClass.txt diff --git a/src/CBot/TestCBot/Mc2.txt b/src/CBot/tests/TestCBot/scenarios/Mc2.txt index 172c259..172c259 100644 --- a/src/CBot/TestCBot/Mc2.txt +++ b/src/CBot/tests/TestCBot/scenarios/Mc2.txt diff --git a/src/CBot/TestCBot/Mon fichier.txt b/src/CBot/tests/TestCBot/scenarios/Mon fichier.txt index 6b35bf8..6b35bf8 100644 --- a/src/CBot/TestCBot/Mon fichier.txt +++ b/src/CBot/tests/TestCBot/scenarios/Mon fichier.txt diff --git a/src/CBot/TestCBot/Nop.txt b/src/CBot/tests/TestCBot/scenarios/Nop.txt index 6a66f6f..6a66f6f 100644 --- a/src/CBot/TestCBot/Nop.txt +++ b/src/CBot/tests/TestCBot/scenarios/Nop.txt diff --git a/src/CBot/TestCBot/POS.txt b/src/CBot/tests/TestCBot/scenarios/POS.txt index 688e4fb..688e4fb 100644 --- a/src/CBot/TestCBot/POS.txt +++ b/src/CBot/tests/TestCBot/scenarios/POS.txt diff --git a/src/CBot/TestCBot/T.txt b/src/CBot/tests/TestCBot/scenarios/T.txt index 50a792b..50a792b 100644 --- a/src/CBot/TestCBot/T.txt +++ b/src/CBot/tests/TestCBot/scenarios/T.txt diff --git a/src/CBot/TestCBot/TESTALL.txt b/src/CBot/tests/TestCBot/scenarios/TESTALL.txt index 82247a0..82247a0 100644 --- a/src/CBot/TestCBot/TESTALL.txt +++ b/src/CBot/tests/TestCBot/scenarios/TESTALL.txt diff --git a/src/CBot/TestCBot/TestCB1.txt b/src/CBot/tests/TestCBot/scenarios/TestCB1.txt index 516db47..516db47 100644 --- a/src/CBot/TestCBot/TestCB1.txt +++ b/src/CBot/tests/TestCBot/scenarios/TestCB1.txt diff --git a/src/CBot/TestCBot/TestCBot1.txt b/src/CBot/tests/TestCBot/scenarios/TestCBot1.txt index d27b4f8..d27b4f8 100644 --- a/src/CBot/TestCBot/TestCBot1.txt +++ b/src/CBot/tests/TestCBot/scenarios/TestCBot1.txt diff --git a/src/CBot/TestCBot/TestCBot3.txt b/src/CBot/tests/TestCBot/scenarios/TestCBot3.txt index b915f96..b915f96 100644 --- a/src/CBot/TestCBot/TestCBot3.txt +++ b/src/CBot/tests/TestCBot/scenarios/TestCBot3.txt diff --git a/src/CBot/TestCBot/TestNull.txt b/src/CBot/tests/TestCBot/scenarios/TestNull.txt index f447245..f447245 100644 --- a/src/CBot/TestCBot/TestNull.txt +++ b/src/CBot/tests/TestCBot/scenarios/TestNull.txt diff --git a/src/CBot/TestCBot/TestRestoreState.txt b/src/CBot/tests/TestCBot/scenarios/TestRestoreState.txt index 1e49e37..1e49e37 100644 --- a/src/CBot/TestCBot/TestRestoreState.txt +++ b/src/CBot/tests/TestCBot/scenarios/TestRestoreState.txt diff --git a/src/CBot/TestCBot/TestStatic.txt b/src/CBot/tests/TestCBot/scenarios/TestStatic.txt index f501aa5..f501aa5 100644 --- a/src/CBot/TestCBot/TestStatic.txt +++ b/src/CBot/tests/TestCBot/scenarios/TestStatic.txt diff --git a/src/CBot/TestCBot/TestStr.txt b/src/CBot/tests/TestCBot/scenarios/TestStr.txt index 683ec1b..683ec1b 100644 --- a/src/CBot/TestCBot/TestStr.txt +++ b/src/CBot/tests/TestCBot/scenarios/TestStr.txt diff --git a/src/CBot/TestCBot/Z.txt b/src/CBot/tests/TestCBot/scenarios/Z.txt index 714119b..714119b 100644 --- a/src/CBot/TestCBot/Z.txt +++ b/src/CBot/tests/TestCBot/scenarios/Z.txt diff --git a/src/CBot/TestCBot/až1.txt b/src/CBot/tests/TestCBot/scenarios/a1.txt index 165bc95..165bc95 100644 --- a/src/CBot/TestCBot/až1.txt +++ b/src/CBot/tests/TestCBot/scenarios/a1.txt diff --git a/src/CBot/TestCBot/array.txt b/src/CBot/tests/TestCBot/scenarios/array.txt index 081b60e..081b60e 100644 --- a/src/CBot/TestCBot/array.txt +++ b/src/CBot/tests/TestCBot/scenarios/array.txt diff --git a/src/CBot/tests/TestCBot/scenarios/až1.txt b/src/CBot/tests/TestCBot/scenarios/až1.txt new file mode 100644 index 0000000..165bc95 --- /dev/null +++ b/src/CBot/tests/TestCBot/scenarios/až1.txt @@ -0,0 +1,96 @@ +object radarGuepe(point orig, float dist) +{ + int i; + object pr, r; + float mindist; + + i = 0; + mindist = 1000; + while (i<30) + { + pr = radar(i); + if (pr != null) + { + + if (F(orig, pr.position) < mindist and pr.category == AlienWasp and pr.altitude > 3) + { + mindist = distance(orig, pr.position); + r = pr; + } + } + i = i+1; + } + if (mindist < dist) return(r); else return(null); +} + + +class Guepe +{ + + point pos; + + + void cherche(point orig, float dist) + { + object p; + point o; + + p = radarGuepe(orig, dist); + while (p == null) + { + wait(0.1); + p = radarGuepe(orig, dist); + } + + pos.x = p.position.x; + pos.y = p.position.y; + pos.z = p.position.z; + + //o = p.position; + //wait(0.1); + + //vitessex = (p.position.x - o.x)/0.1; + //vitessey = (p.position.y - o.y)/0.1; + //vitessez = (p.position.z - o.z)/0.1; + + } + + + void tire(point orig, float orient) + { + //float t = 3; //temps d'anticipation + float angle; + point cible; + + cible.x = pos.x;// + t*vitessex; + cible.y = pos.y;// + t*vitessey; + cible.z = pos.z;// + t*vitessez; + + if (cible.x == 0) angle = 90; else + angle = atan(cible.y / cible.x); + if (cible.x < 0) angle = angle + 180; + angle = angle - orient; + if (angle > 180) angle = angle - 360; + if (angle < -180) angle = angle + 360; + turn(angle); + + angle = atan((cible.z-orig.z) / distance2d(orig, cible)); + aim(angle); + + fire(0.1); + + } +} + +extern void object::Fourmi6() +{ + //fps(1000); + Guepe guepe = new Guepe(); + + while (true) + { + guepe.cherche(position, 50); + + guepe.tire(position, orientation); + } +} diff --git a/src/CBot/tests/TestCBot/scenarios/a§1.txt b/src/CBot/tests/TestCBot/scenarios/a§1.txt new file mode 100644 index 0000000..0c57950 --- /dev/null +++ b/src/CBot/tests/TestCBot/scenarios/a§1.txt @@ -0,0 +1,96 @@ +object radarGuepe(point orig, float dist)
+{
+ int i;
+ object pr, r;
+ float mindist;
+
+ i = 0;
+ mindist = 1000;
+ while (i<30)
+ {
+ pr = radar(i);
+ if (pr != null)
+ {
+
+ if (F(orig, pr.position) < mindist and pr.category == AlienWasp and pr.altitude > 3)
+ {
+ mindist = distance(orig, pr.position);
+ r = pr;
+ }
+ }
+ i = i+1;
+ }
+ if (mindist < dist) return(r); else return(null);
+}
+
+
+class Guepe
+{
+
+ point pos;
+
+
+ void cherche(point orig, float dist)
+ {
+ object p;
+ point o;
+
+ p = radarGuepe(orig, dist);
+ while (p == null)
+ {
+ wait(0.1);
+ p = radarGuepe(orig, dist);
+ }
+
+ pos.x = p.position.x;
+ pos.y = p.position.y;
+ pos.z = p.position.z;
+
+ //o = p.position;
+ //wait(0.1);
+
+ //vitessex = (p.position.x - o.x)/0.1;
+ //vitessey = (p.position.y - o.y)/0.1;
+ //vitessez = (p.position.z - o.z)/0.1;
+
+ }
+
+
+ void tire(point orig, float orient)
+ {
+ //float t = 3; //temps d'anticipation
+ float angle;
+ point cible;
+
+ cible.x = pos.x;// + t*vitessex;
+ cible.y = pos.y;// + t*vitessey;
+ cible.z = pos.z;// + t*vitessez;
+
+ if (cible.x == 0) angle = 90; else
+ angle = atan(cible.y / cible.x);
+ if (cible.x < 0) angle = angle + 180;
+ angle = angle - orient;
+ if (angle > 180) angle = angle - 360;
+ if (angle < -180) angle = angle + 360;
+ turn(angle);
+
+ angle = atan((cible.z-orig.z) / distance2d(orig, cible));
+ aim(angle);
+
+ fire(0.1);
+
+ }
+}
+
+extern void object::Fourmi6()
+{
+ //fps(1000);
+ Guepe guepe = new Guepe();
+
+ while (true)
+ {
+ guepe.cherche(position, 50);
+
+ guepe.tire(position, orientation);
+ }
+}
diff --git a/src/CBot/TestCBot/bug.txt b/src/CBot/tests/TestCBot/scenarios/bug.txt index 4ec6eb3..4ec6eb3 100644 --- a/src/CBot/TestCBot/bug.txt +++ b/src/CBot/tests/TestCBot/scenarios/bug.txt diff --git a/src/CBot/TestCBot/bugmw.txt b/src/CBot/tests/TestCBot/scenarios/bugmw.txt index 284ee43..284ee43 100644 --- a/src/CBot/TestCBot/bugmw.txt +++ b/src/CBot/tests/TestCBot/scenarios/bugmw.txt diff --git a/src/CBot/TestCBot/ccc.txt b/src/CBot/tests/TestCBot/scenarios/ccc.txt index dbcd1d5..dbcd1d5 100644 --- a/src/CBot/TestCBot/ccc.txt +++ b/src/CBot/tests/TestCBot/scenarios/ccc.txt diff --git a/src/CBot/TestCBot/enum.txt b/src/CBot/tests/TestCBot/scenarios/enum.txt index a592a7f..a592a7f 100644 --- a/src/CBot/TestCBot/enum.txt +++ b/src/CBot/tests/TestCBot/scenarios/enum.txt diff --git a/src/CBot/TestCBot/fibo.txt b/src/CBot/tests/TestCBot/scenarios/fibo.txt index 88f5357..88f5357 100644 --- a/src/CBot/TestCBot/fibo.txt +++ b/src/CBot/tests/TestCBot/scenarios/fibo.txt diff --git a/src/CBot/TestCBot/file.txt b/src/CBot/tests/TestCBot/scenarios/file.txt index 2a22dd9..2a22dd9 100644 --- a/src/CBot/TestCBot/file.txt +++ b/src/CBot/tests/TestCBot/scenarios/file.txt diff --git a/src/CBot/TestCBot/h.txt b/src/CBot/tests/TestCBot/scenarios/h.txt index c395319..c395319 100644 --- a/src/CBot/TestCBot/h.txt +++ b/src/CBot/tests/TestCBot/scenarios/h.txt diff --git a/src/CBot/TestCBot/include.txt b/src/CBot/tests/TestCBot/scenarios/include.txt index e8f8cc9..e8f8cc9 100644 --- a/src/CBot/TestCBot/include.txt +++ b/src/CBot/tests/TestCBot/scenarios/include.txt diff --git a/src/CBot/TestCBot/intrinsic.txt b/src/CBot/tests/TestCBot/scenarios/intrinsic.txt index f215791..f215791 100644 --- a/src/CBot/TestCBot/intrinsic.txt +++ b/src/CBot/tests/TestCBot/scenarios/intrinsic.txt diff --git a/src/CBot/TestCBot/methode1.txt b/src/CBot/tests/TestCBot/scenarios/methode1.txt index 080bba2..080bba2 100644 --- a/src/CBot/TestCBot/methode1.txt +++ b/src/CBot/tests/TestCBot/scenarios/methode1.txt diff --git a/src/CBot/TestCBot/methode2.txt b/src/CBot/tests/TestCBot/scenarios/methode2.txt index 76ce7f4..76ce7f4 100644 --- a/src/CBot/TestCBot/methode2.txt +++ b/src/CBot/tests/TestCBot/scenarios/methode2.txt diff --git a/src/CBot/TestCBot/mp1.txt b/src/CBot/tests/TestCBot/scenarios/mp1.txt index 599cfc4..599cfc4 100644 --- a/src/CBot/TestCBot/mp1.txt +++ b/src/CBot/tests/TestCBot/scenarios/mp1.txt diff --git a/src/CBot/TestCBot/mp2.txt b/src/CBot/tests/TestCBot/scenarios/mp2.txt index 1c2972c..1c2972c 100644 --- a/src/CBot/TestCBot/mp2.txt +++ b/src/CBot/tests/TestCBot/scenarios/mp2.txt diff --git a/src/CBot/TestCBot/mw.txt b/src/CBot/tests/TestCBot/scenarios/mw.txt index c237670..c237670 100644 --- a/src/CBot/TestCBot/mw.txt +++ b/src/CBot/tests/TestCBot/scenarios/mw.txt diff --git a/src/CBot/TestCBot/null.txt b/src/CBot/tests/TestCBot/scenarios/null.txt index ae76b74..ae76b74 100644 --- a/src/CBot/TestCBot/null.txt +++ b/src/CBot/tests/TestCBot/scenarios/null.txt diff --git a/src/CBot/TestCBot/opnew.txt b/src/CBot/tests/TestCBot/scenarios/opnew.txt index 7d6838c..7d6838c 100644 --- a/src/CBot/TestCBot/opnew.txt +++ b/src/CBot/tests/TestCBot/scenarios/opnew.txt diff --git a/src/CBot/TestCBot/plante.txt b/src/CBot/tests/TestCBot/scenarios/plante.txt index 363461b..363461b 100644 --- a/src/CBot/TestCBot/plante.txt +++ b/src/CBot/tests/TestCBot/scenarios/plante.txt diff --git a/src/CBot/TestCBot/pointer.txt b/src/CBot/tests/TestCBot/scenarios/pointer.txt index 2d4d907..2d4d907 100644 --- a/src/CBot/TestCBot/pointer.txt +++ b/src/CBot/tests/TestCBot/scenarios/pointer.txt diff --git a/src/CBot/TestCBot/postinc.txt b/src/CBot/tests/TestCBot/scenarios/postinc.txt index cdf6ab5..cdf6ab5 100644 --- a/src/CBot/TestCBot/postinc.txt +++ b/src/CBot/tests/TestCBot/scenarios/postinc.txt diff --git a/src/CBot/TestCBot/radar.txt b/src/CBot/tests/TestCBot/scenarios/radar.txt index 09d84a2..09d84a2 100644 --- a/src/CBot/TestCBot/radar.txt +++ b/src/CBot/tests/TestCBot/scenarios/radar.txt diff --git a/src/CBot/TestCBot/solution.txt b/src/CBot/tests/TestCBot/scenarios/solution.txt index f78cf12..f78cf12 100644 --- a/src/CBot/TestCBot/solution.txt +++ b/src/CBot/tests/TestCBot/scenarios/solution.txt diff --git a/src/CBot/TestCBot/test.txt b/src/CBot/tests/TestCBot/scenarios/test.txt index a912415..a912415 100644 --- a/src/CBot/TestCBot/test.txt +++ b/src/CBot/tests/TestCBot/scenarios/test.txt diff --git a/src/CBot/TestCBot/test23.txt b/src/CBot/tests/TestCBot/scenarios/test23.txt index d6e1ddd..d6e1ddd 100644 --- a/src/CBot/TestCBot/test23.txt +++ b/src/CBot/tests/TestCBot/scenarios/test23.txt diff --git a/src/CBot/TestCBot/testmw.txt b/src/CBot/tests/TestCBot/scenarios/testmw.txt index 6570f6d..6570f6d 100644 --- a/src/CBot/TestCBot/testmw.txt +++ b/src/CBot/tests/TestCBot/scenarios/testmw.txt diff --git a/src/CBot/TestCBot/this.txt b/src/CBot/tests/TestCBot/scenarios/this.txt index b8a9e04..b8a9e04 100644 --- a/src/CBot/TestCBot/this.txt +++ b/src/CBot/tests/TestCBot/scenarios/this.txt diff --git a/src/CBot/TestCBot/tt.txt b/src/CBot/tests/TestCBot/scenarios/tt.txt index cd13c9d..cd13c9d 100644 --- a/src/CBot/TestCBot/tt.txt +++ b/src/CBot/tests/TestCBot/scenarios/tt.txt diff --git a/src/CBot/TestCBot/tt2.txt b/src/CBot/tests/TestCBot/scenarios/tt2.txt index ad9dc1d..ad9dc1d 100644 --- a/src/CBot/TestCBot/tt2.txt +++ b/src/CBot/tests/TestCBot/scenarios/tt2.txt diff --git a/src/CBot/TestCBot/vide.txt b/src/CBot/tests/TestCBot/scenarios/vide.txt index e69de29..e69de29 100644 --- a/src/CBot/TestCBot/vide.txt +++ b/src/CBot/tests/TestCBot/scenarios/vide.txt diff --git a/src/CBot/TestCBot/zz.txt b/src/CBot/tests/TestCBot/scenarios/zz.txt index da764ac..da764ac 100644 --- a/src/CBot/TestCBot/zz.txt +++ b/src/CBot/tests/TestCBot/scenarios/zz.txt diff --git a/src/CBot/TestCBot/xTestCBot.clw b/src/CBot/tests/TestCBot/xTestCBot.clw index 5b84c16..5b84c16 100644 --- a/src/CBot/TestCBot/xTestCBot.clw +++ b/src/CBot/tests/TestCBot/xTestCBot.clw diff --git a/src/CBot/old TstCBot/BotConsoleDlg.cpp b/src/CBot/tests/old TstCBot/BotConsoleDlg.cpp index 077f080..077f080 100644 --- a/src/CBot/old TstCBot/BotConsoleDlg.cpp +++ b/src/CBot/tests/old TstCBot/BotConsoleDlg.cpp diff --git a/src/CBot/old TstCBot/BotConsoleDlg.h b/src/CBot/tests/old TstCBot/BotConsoleDlg.h index 9b54ff2..9b54ff2 100644 --- a/src/CBot/old TstCBot/BotConsoleDlg.h +++ b/src/CBot/tests/old TstCBot/BotConsoleDlg.h diff --git a/src/CBot/old TstCBot/BotErrorDlg.cpp b/src/CBot/tests/old TstCBot/BotErrorDlg.cpp index 87d56f0..87d56f0 100644 --- a/src/CBot/old TstCBot/BotErrorDlg.cpp +++ b/src/CBot/tests/old TstCBot/BotErrorDlg.cpp diff --git a/src/CBot/old TstCBot/BotErrorDlg.h b/src/CBot/tests/old TstCBot/BotErrorDlg.h index 522afad..522afad 100644 --- a/src/CBot/old TstCBot/BotErrorDlg.h +++ b/src/CBot/tests/old TstCBot/BotErrorDlg.h diff --git a/src/CBot/old TstCBot/CBotTest.txt b/src/CBot/tests/old TstCBot/CBotTest.txt index ce20e26..ce20e26 100644 --- a/src/CBot/old TstCBot/CBotTest.txt +++ b/src/CBot/tests/old TstCBot/CBotTest.txt diff --git a/src/CBot/old TstCBot/CMyThread.cpp b/src/CBot/tests/old TstCBot/CMyThread.cpp index ca92c77..ca92c77 100644 --- a/src/CBot/old TstCBot/CMyThread.cpp +++ b/src/CBot/tests/old TstCBot/CMyThread.cpp diff --git a/src/CBot/old TstCBot/CMyThread.h b/src/CBot/tests/old TstCBot/CMyThread.h index 1134077..1134077 100644 --- a/src/CBot/old TstCBot/CMyThread.h +++ b/src/CBot/tests/old TstCBot/CMyThread.h diff --git a/src/CBot/old TstCBot/MainFrm.cpp b/src/CBot/tests/old TstCBot/MainFrm.cpp index 6c0962c..6c0962c 100644 --- a/src/CBot/old TstCBot/MainFrm.cpp +++ b/src/CBot/tests/old TstCBot/MainFrm.cpp diff --git a/src/CBot/old TstCBot/MainFrm.h b/src/CBot/tests/old TstCBot/MainFrm.h index 56b9c41..56b9c41 100644 --- a/src/CBot/old TstCBot/MainFrm.h +++ b/src/CBot/tests/old TstCBot/MainFrm.h diff --git a/src/CBot/old TstCBot/ReadMe.txt b/src/CBot/tests/old TstCBot/ReadMe.txt index 67dc05b..67dc05b 100644 --- a/src/CBot/old TstCBot/ReadMe.txt +++ b/src/CBot/tests/old TstCBot/ReadMe.txt diff --git a/src/CBot/old TstCBot/Resource.h b/src/CBot/tests/old TstCBot/Resource.h index 6863fd8..6863fd8 100644 --- a/src/CBot/old TstCBot/Resource.h +++ b/src/CBot/tests/old TstCBot/Resource.h diff --git a/src/CBot/old TstCBot/StdAfx.cpp b/src/CBot/tests/old TstCBot/StdAfx.cpp index ae0ec93..ae0ec93 100644 --- a/src/CBot/old TstCBot/StdAfx.cpp +++ b/src/CBot/tests/old TstCBot/StdAfx.cpp diff --git a/src/CBot/old TstCBot/StdAfx.h b/src/CBot/tests/old TstCBot/StdAfx.h index 7d46ace..7d46ace 100644 --- a/src/CBot/old TstCBot/StdAfx.h +++ b/src/CBot/tests/old TstCBot/StdAfx.h diff --git a/src/CBot/old TstCBot/TstCBot.clw b/src/CBot/tests/old TstCBot/TstCBot.clw index 4c54168..4c54168 100644 --- a/src/CBot/old TstCBot/TstCBot.clw +++ b/src/CBot/tests/old TstCBot/TstCBot.clw diff --git a/src/CBot/old TstCBot/TstCBot.cpp b/src/CBot/tests/old TstCBot/TstCBot.cpp index 8ac4557..8ac4557 100644 --- a/src/CBot/old TstCBot/TstCBot.cpp +++ b/src/CBot/tests/old TstCBot/TstCBot.cpp diff --git a/src/CBot/old TstCBot/TstCBot.dsp b/src/CBot/tests/old TstCBot/TstCBot.dsp index 35e5c0b..35e5c0b 100644 --- a/src/CBot/old TstCBot/TstCBot.dsp +++ b/src/CBot/tests/old TstCBot/TstCBot.dsp diff --git a/src/CBot/old TstCBot/TstCBot.h b/src/CBot/tests/old TstCBot/TstCBot.h index 616db43..616db43 100644 --- a/src/CBot/old TstCBot/TstCBot.h +++ b/src/CBot/tests/old TstCBot/TstCBot.h diff --git a/src/CBot/old TstCBot/TstCBot.rc b/src/CBot/tests/old TstCBot/TstCBot.rc index 9e91c76..9e91c76 100644 --- a/src/CBot/old TstCBot/TstCBot.rc +++ b/src/CBot/tests/old TstCBot/TstCBot.rc diff --git a/src/CBot/old TstCBot/TstCBotDoc.cpp b/src/CBot/tests/old TstCBot/TstCBotDoc.cpp index 7d7e2ef..7d7e2ef 100644 --- a/src/CBot/old TstCBot/TstCBotDoc.cpp +++ b/src/CBot/tests/old TstCBot/TstCBotDoc.cpp diff --git a/src/CBot/old TstCBot/TstCBotDoc.h b/src/CBot/tests/old TstCBot/TstCBotDoc.h index ae1d0f7..ae1d0f7 100644 --- a/src/CBot/old TstCBot/TstCBotDoc.h +++ b/src/CBot/tests/old TstCBot/TstCBotDoc.h diff --git a/src/CBot/old TstCBot/TstCBotView.cpp b/src/CBot/tests/old TstCBot/TstCBotView.cpp index 3ee9094..3ee9094 100644 --- a/src/CBot/old TstCBot/TstCBotView.cpp +++ b/src/CBot/tests/old TstCBot/TstCBotView.cpp diff --git a/src/CBot/old TstCBot/TstCBotView.h b/src/CBot/tests/old TstCBot/TstCBotView.h index d5aede5..d5aede5 100644 --- a/src/CBot/old TstCBot/TstCBotView.h +++ b/src/CBot/tests/old TstCBot/TstCBotView.h diff --git a/src/CBot/old TstCBot/res/TstCBot.ico b/src/CBot/tests/old TstCBot/res/TstCBot.ico Binary files differindex 7eef0bc..7eef0bc 100644 --- a/src/CBot/old TstCBot/res/TstCBot.ico +++ b/src/CBot/tests/old TstCBot/res/TstCBot.ico diff --git a/src/CBot/old TstCBot/res/TstCBot.rc2 b/src/CBot/tests/old TstCBot/res/TstCBot.rc2 index 2186272..2186272 100644 --- a/src/CBot/old TstCBot/res/TstCBot.rc2 +++ b/src/CBot/tests/old TstCBot/res/TstCBot.rc2 diff --git a/src/CBot/old TstCBot/res/TstCBotDoc.ico b/src/CBot/tests/old TstCBot/res/TstCBotDoc.ico Binary files differindex 2a1f1ae..2a1f1ae 100644 --- a/src/CBot/old TstCBot/res/TstCBotDoc.ico +++ b/src/CBot/tests/old TstCBot/res/TstCBotDoc.ico diff --git a/src/CBot/old TstCBot/test complet 1.txt b/src/CBot/tests/old TstCBot/test complet 1.txt index 0fd4fa5..0fd4fa5 100644 --- a/src/CBot/old TstCBot/test complet 1.txt +++ b/src/CBot/tests/old TstCBot/test complet 1.txt diff --git a/src/CBot/old TstCBot/x.txt b/src/CBot/tests/old TstCBot/x.txt index 95856e0..95856e0 100644 --- a/src/CBot/old TstCBot/x.txt +++ b/src/CBot/tests/old TstCBot/x.txt |