369 lines
12 KiB
C++
369 lines
12 KiB
C++
/*
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
|
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
|
*
|
|
* 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://gnu.org/licenses
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "CBot/CBotTypResult.h"
|
|
#include "CBot/CBotEnums.h"
|
|
|
|
#include <vector>
|
|
|
|
namespace CBot
|
|
{
|
|
|
|
class CBotFunction;
|
|
class CBotClass;
|
|
class CBotStack;
|
|
class CBotVar;
|
|
class CBotExternalCallList;
|
|
|
|
/**
|
|
* \brief Class that manages a CBot program. This is the main entry point into the CBot engine.
|
|
*
|
|
* \section Init Engine initialization / destruction
|
|
* To initialize the CBot engine, call CBotProgram::Init(). This function should be only called once.
|
|
*
|
|
* Afterwards, you can start defining custom functions, constants and classes. See:
|
|
* * CBotProgram::AddFunction()
|
|
* * CBotProgram::DefineNum()
|
|
* * CBotClass::Create()
|
|
*
|
|
* Next, compile and run programs.
|
|
* * Compile()
|
|
* * Start()
|
|
* * Run()
|
|
* * Stop()
|
|
*
|
|
* After you are finished, free the memory used by the CBot engine by calling CBotProgram::Free().
|
|
*
|
|
* \section Example Example usage
|
|
* \code
|
|
* // Initialize the engine
|
|
* CBotProgram::Init();
|
|
*
|
|
* // Add some standard functions
|
|
* CBotProgram::AddFunction("message", rMessage, cMessage);
|
|
*
|
|
* // Compile the program
|
|
* std::vector<std::string> externFunctions;
|
|
* CBotProgram* program = new CBotProgram();
|
|
* bool ok = program->Compile(code.c_str(), externFunctions, nullptr);
|
|
* if (!ok)
|
|
* {
|
|
* CBotError error;
|
|
* int cursor1, cursor2;
|
|
* program->GetError(error, cursor1, cursor2);
|
|
* // Handle the error
|
|
* }
|
|
*
|
|
* // Run the program
|
|
* program->Start(externFunctions[0]);
|
|
* while (!program->Run());
|
|
*
|
|
* // Cleanup
|
|
* CBotProgram::Free();
|
|
* \endcode
|
|
*/
|
|
class CBotProgram
|
|
{
|
|
public:
|
|
/**
|
|
* \brief Constructor
|
|
*/
|
|
CBotProgram();
|
|
|
|
/**
|
|
* \brief Constructor
|
|
* \param thisVar Variable to pass to the program as "this"
|
|
*/
|
|
CBotProgram(CBotVar* thisVar);
|
|
|
|
/**
|
|
* \brief Destructor
|
|
*/
|
|
~CBotProgram();
|
|
|
|
/**
|
|
* \brief Initializes the module, should be done once (and only once) at the beginning
|
|
*/
|
|
static void Init();
|
|
|
|
/**
|
|
* \brief Frees the static memory areas
|
|
*/
|
|
static void Free();
|
|
|
|
/**
|
|
* \brief Returns version of the CBot library
|
|
* \return A number representing the current library version
|
|
*/
|
|
static int GetVersion();
|
|
|
|
/**
|
|
* \brief Compile compiles the program given as string
|
|
*
|
|
* Compilation is done in a few steps:
|
|
* 1. Convert the code into "tokens" - see CBotToken::CompileTokens()
|
|
* 2. First pass - getting declarations of all functions an classes for use later
|
|
* 3. Second pass - compiling definitions of all functions and classes
|
|
*
|
|
* \param program Code to compile
|
|
* \param[out] functions Returns the names of functions declared as extern
|
|
* \param pUser Optional pointer to be passed to compile function (see AddFunction())
|
|
* \return true if compilation is successful, false if an compilation error occurs
|
|
* \see GetError() to retrieve the error
|
|
*/
|
|
bool Compile(const std::string& program, std::vector<std::string>& functions, void* pUser = nullptr);
|
|
|
|
/**
|
|
* \brief Returns the last error
|
|
* \return Error code
|
|
* \see GetError(CBotError&, int&, int&) for error location in the code
|
|
*/
|
|
CBotError GetError();
|
|
|
|
/**
|
|
* \brief Returns the last error
|
|
* \param[out] code Error code
|
|
* \param[out] start Starting position in the code string of this error
|
|
* \param[out] end Ending position in the code string of this error
|
|
* \return false if no error has occurred
|
|
*/
|
|
bool GetError(CBotError& code, int& start, int& end);
|
|
|
|
/**
|
|
* \brief Returns the last error
|
|
* \param[out] code Error code
|
|
* \param[out] start Starting position in the code string of this error
|
|
* \param[out] end Ending position in the code string of this error
|
|
* \param[out] pProg Program that caused the error (TODO: This always returns "this"... what?)
|
|
* \return false if no error has occurred
|
|
*/
|
|
bool GetError(CBotError& code, int& start, int& end, CBotProgram*& pProg);
|
|
|
|
/**
|
|
* \brief Starts the program using given function as an entry point. The function must be declared as "extern"
|
|
* \param name Name of function to start
|
|
* \return true if the program was started, false if the function name is not found
|
|
* \see Compile() returns list of extern functions found in the code
|
|
*/
|
|
bool Start(const std::string& name);
|
|
|
|
/**
|
|
* \brief Executes the program
|
|
* \param pUser Custom pointer to be passed to execute function (see AddFunction())
|
|
* \param timer
|
|
* \parblock
|
|
* * timer < 0 do nothing
|
|
* * timer >= 0 call SetTimer(int timer) before executing
|
|
* \endparblock
|
|
* \return true if the program execution finished, false if the program is suspended (you then have to call Run() again)
|
|
*/
|
|
bool Run(void* pUser = nullptr, int timer = -1);
|
|
|
|
/**
|
|
* \brief Gives the current position in the executing program
|
|
* \param[out] functionName Name of the currently executed function
|
|
* \param[out] start Starting position in the code string of currently executed instruction
|
|
* \param[out] end Ending position in the code string of currently executed instruction
|
|
* \return false if it is not running (program completion)
|
|
*/
|
|
bool GetRunPos(std::string& functionName, int& start, int& end);
|
|
|
|
/**
|
|
* \brief Provides the pointer to the variables on the execution stack
|
|
* \param[out] functionName Name of the function that this stack is part of
|
|
* \param level 0 for the last level, -1, -2 etc. for previous ones
|
|
* \return Variables on the given stack level. Process using CBotVar::GetNext(). If the stack level is invalid, returns nullptr.
|
|
*/
|
|
CBotVar* GetStackVars(std::string& functionName, int level);
|
|
|
|
/**
|
|
* \brief Stops execution of the program
|
|
*/
|
|
void Stop();
|
|
|
|
/**
|
|
* \brief Sets the number of steps (parts of instructions) to execute in Run() before suspending the program execution
|
|
* \param n new timer value
|
|
*
|
|
* FIXME: Seems to be currently kind of broken (see issue #410)
|
|
*/
|
|
static void SetTimer(int n);
|
|
|
|
/**
|
|
* \brief Add a function that can be called from CBot
|
|
*
|
|
* To define an external function, proceed as follows:
|
|
*
|
|
* 1. Define a function for compilation
|
|
*
|
|
* This function should take a list of function arguments (types only, no values!) and a user-defined void* pointer (can be passed in Compile()) as parameters, and return CBotTypResult.
|
|
*
|
|
* Usually, name of this function is prefixed with "c".
|
|
*
|
|
* The function should iterate through the provided parameter list and verify that they match.<br>
|
|
* If they don't, then return CBotTypResult with an appropariate error code (see ::CBotError).<br>
|
|
* If they do, return CBotTypResult with the function's return type
|
|
*
|
|
* \code
|
|
* CBotTypResult cMessage(CBotVar* &var, void* user)
|
|
* {
|
|
* if (var == nullptr) return CBotTypResult(CBotErrLowParam); // Not enough parameters
|
|
* if (var->GetType() != CBotTypString) return CBotTypResult(CBotErrBadString); // String expected
|
|
*
|
|
* var = var->GetNext(); // Get the next parameter
|
|
* if (var != nullptr) return CBotTypResult(CBotErrOverParam); // Too many parameters
|
|
*
|
|
* return CBotTypResult(CBotTypFloat); // This function returns float (it may depend on parameters given!)
|
|
* }
|
|
* \endcode
|
|
*
|
|
* 2. Define a function for execution
|
|
*
|
|
* This function should take:
|
|
* * a list of parameters
|
|
* * pointer to a result variable (a variable of type given at compilation time will be provided)
|
|
* * pointer to an exception variable
|
|
* * user-defined pointer (can be passed in Run())
|
|
*
|
|
* This function returns true if execution of this function is finished, or false to suspend the program and call this function again on next Run() cycle.
|
|
*
|
|
* Usually, execution functions are prefixed with "r".
|
|
*
|
|
* \code
|
|
* bool rMessage(CBotVar* var, CBotVar* result, int& exception, void* user)
|
|
* {
|
|
* std::string message = var->GetValString();
|
|
* std::cout << message << std::endl;
|
|
* return true; // Execution finished
|
|
* }
|
|
* \endcode
|
|
*
|
|
* 3. Call AddFunction() to register the function in the CBot engine
|
|
*
|
|
* \code
|
|
* AddFunction("message", rMessage, cMessage);
|
|
* \endcode
|
|
*
|
|
* For more sophisticated examples, see the Colobot source code, mainly the src/script/scriptfunc.cpp file
|
|
*
|
|
* \param name Name of the function
|
|
* \param rExec Execution function
|
|
* \param rCompile Compilation function
|
|
* \return true
|
|
*/
|
|
static bool AddFunction(const std::string& name,
|
|
bool rExec(CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
|
|
CBotTypResult rCompile(CBotVar*& pVar, void* pUser));
|
|
|
|
/**
|
|
* \copydoc CBotToken::DefineNum()
|
|
* \see CBotToken::DefineNum()
|
|
*/
|
|
static bool DefineNum(const std::string& name, long val);
|
|
|
|
/**
|
|
* \brief Save the current execution status into a file
|
|
* \param pf
|
|
* \parblock
|
|
* file handle
|
|
*
|
|
* This file handle must have been opened by this library! Otherwise crashes on Windows
|
|
*
|
|
* TODO: Verify this
|
|
* \endparblock
|
|
* \return true on success, false on write error
|
|
*/
|
|
bool SaveState(FILE* pf);
|
|
|
|
/**
|
|
* \brief Restore the execution state from a file
|
|
*
|
|
* The previous program code must already have been recompiled with Compile() before calling this function
|
|
*
|
|
* \param pf file handle
|
|
* \return true on success, false on read error
|
|
*/
|
|
bool RestoreState(FILE* pf);
|
|
|
|
/**
|
|
* \brief GetPosition 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.
|
|
*
|
|
* TODO: Document this
|
|
*
|
|
* \param name
|
|
* \param start
|
|
* \param stop
|
|
* \param modestart
|
|
* \param modestop
|
|
* \return
|
|
*/
|
|
bool GetPosition(const std::string& name,
|
|
int& start,
|
|
int& stop,
|
|
CBotGet modestart = GetPosExtern,
|
|
CBotGet modestop = GetPosBloc);
|
|
|
|
/**
|
|
* \brief Returns the list of all user-defined functions in this program as instances of CBotFunction
|
|
*
|
|
* This list includes all the functions (not only extern)
|
|
*
|
|
* \return Linked list of CBotFunction instances
|
|
*/
|
|
CBotFunction* GetFunctions();
|
|
|
|
/**
|
|
* \brief true while compiling class
|
|
*
|
|
* TODO: refactor this
|
|
*/
|
|
bool m_bCompileClass;
|
|
|
|
/**
|
|
* \brief Returns static list of all registered external calls
|
|
*/
|
|
static CBotExternalCallList* GetExternalCalls();
|
|
|
|
private:
|
|
//! All external calls
|
|
static CBotExternalCallList* m_externalCalls;
|
|
//! All user-defined functions
|
|
CBotFunction* m_functions = nullptr;
|
|
//! The entry point function
|
|
CBotFunction* m_entryPoint = nullptr;
|
|
//! Classes defined in this program
|
|
CBotClass* m_classes = nullptr;
|
|
//! Execution stack
|
|
CBotStack* m_stack = nullptr;
|
|
//! "this" variable
|
|
CBotVar* m_thisVar = nullptr;
|
|
friend class CBotFunction;
|
|
friend class CBotDebug;
|
|
|
|
CBotError m_error = CBotNoErr;
|
|
int m_errorStart = 0;
|
|
int m_errorEnd = 0;
|
|
};
|
|
|
|
} // namespace CBot
|