mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Merge branch 'master' into exterior
Conflicts: apps/openmw/mwscript/docs/vmformat.txt
This commit is contained in:
commit
1dc805d0d4
54 changed files with 2419 additions and 1627 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,4 @@
|
||||||
build
|
build
|
||||||
*~
|
*~
|
||||||
|
Doxygen
|
||||||
|
prebuilt
|
|
@ -8,6 +8,35 @@ option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
|
||||||
# We probably support older versions than this.
|
# We probably support older versions than this.
|
||||||
cmake_minimum_required(VERSION 2.6)
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Pre-built binaries being used?
|
||||||
|
#
|
||||||
|
IF(EXISTS "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd/ogre_1_7_1")
|
||||||
|
set(PREBUILT_DIR "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd")
|
||||||
|
message (STATUS "OpenMW pre-built binaries found at ${PREBUILT_DIR}.")
|
||||||
|
|
||||||
|
SET(ENV{OGRE_HOME} "${PREBUILT_DIR}/ogre_1_7_1")
|
||||||
|
|
||||||
|
SET(ENV{BOOST_ROOT} "${PREBUILT_DIR}/boost_1_42_0")
|
||||||
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
|
set(ENV{BOOST_INCLUDEDIR} "${BOOST_ROOT}/include")
|
||||||
|
set(ENV{BOOST_LIBRARYDIR} "${BOOST_ROOT}/lib")
|
||||||
|
|
||||||
|
set(ENV{FREETYPE_DIR} "${PREBUILT_DIR}/freetype-2.3.5-1")
|
||||||
|
|
||||||
|
set(USE_MPG123 OFF)
|
||||||
|
set(USE_AUDIERE ON)
|
||||||
|
set(AUDIERE_INCLUDE_DIR "${PREBUILT_DIR}/audiere-1.9.4/include")
|
||||||
|
set(AUDIERE_LIBRARY "${PREBUILT_DIR}/audiere-1.9.4/lib/audiere.lib")
|
||||||
|
|
||||||
|
set(ENV{OPENALDIR} "${PREBUILT_DIR}/OpenAL 1.1 SDK")
|
||||||
|
|
||||||
|
ELSE()
|
||||||
|
message (STATUS "OpenMW pre-built binaries not found. Using standard locations.")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
# Add path for CMake scripts
|
# Add path for CMake scripts
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||||
|
|
||||||
|
@ -166,6 +195,9 @@ if (WIN32)
|
||||||
else (WIN32)
|
else (WIN32)
|
||||||
set(PLATFORM_INCLUDE_DIR "")
|
set(PLATFORM_INCLUDE_DIR "")
|
||||||
endif (WIN32)
|
endif (WIN32)
|
||||||
|
if (MSVC10)
|
||||||
|
set(PLATFORM_INCLUDE_DIR "")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
|
@ -180,10 +212,10 @@ include_directories("."
|
||||||
${CMAKE_HOME_DIRECTORY}/extern/caelum/include
|
${CMAKE_HOME_DIRECTORY}/extern/caelum/include
|
||||||
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/MyGUIEngine/include
|
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/MyGUIEngine/include
|
||||||
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/OgrePlatform/include
|
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/OgrePlatform/include
|
||||||
|
${OPENAL_INCLUDE_DIR}
|
||||||
${LIBDIR}
|
${LIBDIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
|
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
|
||||||
|
|
||||||
add_subdirectory( extern/caelum )
|
add_subdirectory( extern/caelum )
|
||||||
|
@ -215,7 +247,7 @@ endif (APPLE)
|
||||||
|
|
||||||
# Compiler settings
|
# Compiler settings
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
if (CMAKE_COMPILER_IS_GNUCC)
|
||||||
add_definitions (-Wall)
|
add_definitions (-Wall -Werror)
|
||||||
endif (CMAKE_COMPILER_IS_GNUCC)
|
endif (CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
|
||||||
# Apple bundling
|
# Apple bundling
|
||||||
|
|
1322
Docs/Doxyfile
1322
Docs/Doxyfile
File diff suppressed because it is too large
Load diff
|
@ -10,6 +10,7 @@ add_executable(esmtool
|
||||||
${ESMTOOL}
|
${ESMTOOL}
|
||||||
${MISC} ${MISC_HEADER}
|
${MISC} ${MISC_HEADER}
|
||||||
${TO_UTF8}
|
${TO_UTF8}
|
||||||
|
${ESM}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(esmtool
|
target_link_libraries(esmtool
|
||||||
|
|
|
@ -63,6 +63,8 @@ set(GAMESCRIPT
|
||||||
mwscript/skyextensions.cpp
|
mwscript/skyextensions.cpp
|
||||||
mwscript/statsextensions.cpp
|
mwscript/statsextensions.cpp
|
||||||
mwscript/containerextensions.cpp
|
mwscript/containerextensions.cpp
|
||||||
|
mwscript/aiextensions.cpp
|
||||||
|
mwscript/controlextensions.cpp
|
||||||
mwscript/extensions.cpp
|
mwscript/extensions.cpp
|
||||||
mwscript/globalscripts.cpp
|
mwscript/globalscripts.cpp
|
||||||
)
|
)
|
||||||
|
@ -78,6 +80,8 @@ set(GAMESCRIPT_HEADER
|
||||||
mwscript/skyextensions.hpp
|
mwscript/skyextensions.hpp
|
||||||
mwscript/statsextensions.hpp
|
mwscript/statsextensions.hpp
|
||||||
mwscript/containerextensions.hpp
|
mwscript/containerextensions.hpp
|
||||||
|
mwscript/aiextensions.hpp
|
||||||
|
mwscript/controlextensions.hpp
|
||||||
mwscript/extensions.hpp
|
mwscript/extensions.hpp
|
||||||
mwscript/globalscripts.hpp
|
mwscript/globalscripts.hpp
|
||||||
)
|
)
|
||||||
|
@ -204,7 +208,7 @@ target_link_libraries(openmw
|
||||||
${SOUND_INPUT_LIBRARY}
|
${SOUND_INPUT_LIBRARY}
|
||||||
caelum
|
caelum
|
||||||
MyGUIEngine
|
MyGUIEngine
|
||||||
MyGUI.OgrePlatform
|
MyGUIOgrePlatform
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
|
|
@ -109,6 +109,7 @@ OMW::Engine::Engine()
|
||||||
, mUseSound (true)
|
, mUseSound (true)
|
||||||
, mScriptManager (0)
|
, mScriptManager (0)
|
||||||
, mScriptContext (0)
|
, mScriptContext (0)
|
||||||
|
, mGuiManager (0)
|
||||||
{
|
{
|
||||||
MWClass::registerClasses();
|
MWClass::registerClasses();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
#include "../mwrender/cellimp.hpp"
|
#include "../mwrender/cellimp.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
void Door::insertObj (const MWWorld::Ptr& ptr, MWRender::CellRenderImp& cellRender,
|
void Door::insertObj (const MWWorld::Ptr& ptr, MWRender::CellRenderImp& cellRender,
|
||||||
|
@ -50,6 +52,16 @@ namespace MWClass
|
||||||
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
|
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
|
||||||
ptr.get<ESM::Door>();
|
ptr.get<ESM::Door>();
|
||||||
|
|
||||||
|
if (ptr.getCellRef().lockLevel>0)
|
||||||
|
{
|
||||||
|
// TODO check for key
|
||||||
|
// TODO report failure to player (message, sound?). Look up behaviour of original MW.
|
||||||
|
std::cout << "Locked!" << std::endl;
|
||||||
|
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO check trap
|
||||||
|
|
||||||
if (ref->ref.teleport)
|
if (ref->ref.teleport)
|
||||||
{
|
{
|
||||||
// teleport door
|
// teleport door
|
||||||
|
@ -74,6 +86,19 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const
|
||||||
|
{
|
||||||
|
if (lockLevel<0)
|
||||||
|
lockLevel = 0;
|
||||||
|
|
||||||
|
ptr.getCellRef().lockLevel = lockLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Door::unlock (const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
ptr.getCellRef().lockLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Door::getScript (const MWWorld::Ptr& ptr) const
|
std::string Door::getScript (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
|
ESMS::LiveCellRef<ESM::Door, MWWorld::RefData> *ref =
|
||||||
|
|
|
@ -21,6 +21,12 @@ namespace MWClass
|
||||||
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const;
|
||||||
///< Generate action for activation
|
///< Generate action for activation
|
||||||
|
|
||||||
|
virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const;
|
||||||
|
///< Lock object
|
||||||
|
|
||||||
|
virtual void unlock (const MWWorld::Ptr& ptr) const;
|
||||||
|
///< Unlock object
|
||||||
|
|
||||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr
|
///< Return name of the script attached to ptr
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,13 @@ namespace MWGui
|
||||||
class ConsoleInterpreterContext : public MWScript::InterpreterContext
|
class ConsoleInterpreterContext : public MWScript::InterpreterContext
|
||||||
{
|
{
|
||||||
Console& mConsole;
|
Console& mConsole;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment,
|
|
||||||
MWWorld::Ptr reference);
|
|
||||||
|
|
||||||
virtual void messageBox (const std::string& message,
|
public:
|
||||||
const std::vector<std::string>& buttons);
|
|
||||||
|
ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment,
|
||||||
|
MWWorld::Ptr reference);
|
||||||
};
|
};
|
||||||
|
|
||||||
ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console,
|
ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console,
|
||||||
MWWorld::Environment& environment, MWWorld::Ptr reference)
|
MWWorld::Environment& environment, MWWorld::Ptr reference)
|
||||||
: MWScript::InterpreterContext (environment,
|
: MWScript::InterpreterContext (environment,
|
||||||
|
@ -27,30 +24,21 @@ namespace MWGui
|
||||||
mConsole (console)
|
mConsole (console)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void ConsoleInterpreterContext::messageBox (const std::string& message,
|
|
||||||
const std::vector<std::string>& buttons)
|
|
||||||
{
|
|
||||||
if (!buttons.empty())
|
|
||||||
mConsole.printError ("MessageBox doesn't support buttons while in console mode");
|
|
||||||
else
|
|
||||||
mConsole.printOK (message);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Console::compile (const std::string& cmd, Compiler::Output& output)
|
bool Console::compile (const std::string& cmd, Compiler::Output& output)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ErrorHandler::reset();
|
ErrorHandler::reset();
|
||||||
|
|
||||||
std::istringstream input (cmd + '\n');
|
std::istringstream input (cmd + '\n');
|
||||||
|
|
||||||
Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions());
|
Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions());
|
||||||
|
|
||||||
Compiler::LineParser parser (*this, mCompilerContext, output.getLocals(),
|
Compiler::LineParser parser (*this, mCompilerContext, output.getLocals(),
|
||||||
output.getLiterals(), output.getCode(), true);
|
output.getLiterals(), output.getCode(), true);
|
||||||
|
|
||||||
scanner.scan (parser);
|
scanner.scan (parser);
|
||||||
|
|
||||||
return isGood();
|
return isGood();
|
||||||
}
|
}
|
||||||
catch (const Compiler::SourceException& error)
|
catch (const Compiler::SourceException& error)
|
||||||
|
@ -61,7 +49,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
printError (std::string ("An exception has been thrown: ") + error.what());
|
printError (std::string ("An exception has been thrown: ") + error.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +57,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
std::ostringstream error;
|
std::ostringstream error;
|
||||||
error << "column " << loc.mColumn << " (" << loc.mLiteral << "):";
|
error << "column " << loc.mColumn << " (" << loc.mLiteral << "):";
|
||||||
|
|
||||||
printError (error.str());
|
printError (error.str());
|
||||||
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +66,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console::Console(int w, int h, MWWorld::Environment& environment,
|
Console::Console(int w, int h, MWWorld::Environment& environment,
|
||||||
const Compiler::Extensions& extensions)
|
const Compiler::Extensions& extensions)
|
||||||
: Layout("openmw_console_layout.xml"),
|
: Layout("openmw_console_layout.xml"),
|
||||||
|
@ -100,7 +88,7 @@ namespace MWGui
|
||||||
history->setOverflowToTheLeft(true);
|
history->setOverflowToTheLeft(true);
|
||||||
history->setEditStatic(true);
|
history->setEditStatic(true);
|
||||||
history->setVisibleVScroll(true);
|
history->setVisibleVScroll(true);
|
||||||
|
|
||||||
// compiler
|
// compiler
|
||||||
mCompilerContext.setExtensions (&extensions);
|
mCompilerContext.setExtensions (&extensions);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +184,7 @@ namespace MWGui
|
||||||
Compiler::Locals locals;
|
Compiler::Locals locals;
|
||||||
Compiler::Output output (locals);
|
Compiler::Output output (locals);
|
||||||
|
|
||||||
if (compile (cm, output))
|
if (compile (cm + "\n", output))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -205,7 +193,7 @@ namespace MWGui
|
||||||
MWScript::installOpcodes (interpreter);
|
MWScript::installOpcodes (interpreter);
|
||||||
std::vector<Interpreter::Type_Code> code;
|
std::vector<Interpreter::Type_Code> code;
|
||||||
output.getCode (code);
|
output.getCode (code);
|
||||||
interpreter.run (&code[0], code.size());
|
interpreter.run (&code[0], code.size());
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
|
@ -216,4 +204,3 @@ namespace MWGui
|
||||||
command->setCaption("");
|
command->setCaption("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
using namespace MWGui;
|
using namespace MWGui;
|
||||||
|
|
||||||
|
@ -13,8 +15,8 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment
|
||||||
{
|
{
|
||||||
// Get size info from the Gui object
|
// Get size info from the Gui object
|
||||||
assert(gui);
|
assert(gui);
|
||||||
int w = gui->getViewWidth();
|
int w = gui->getViewSize().width;
|
||||||
int h = gui->getViewHeight();
|
int h = gui->getViewSize().height;
|
||||||
|
|
||||||
hud = new HUD(w,h);
|
hud = new HUD(w,h);
|
||||||
menu = new MainMenu(w,h);
|
menu = new MainMenu(w,h);
|
||||||
|
@ -95,3 +97,15 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicS
|
||||||
stats->setValue (id, value);
|
stats->setValue (id, value);
|
||||||
hud->setValue (id, value);
|
hud->setValue (id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::messageBox (const std::string& message, const std::vector<std::string>& buttons)
|
||||||
|
{
|
||||||
|
std::cout << "message box: " << message << std::endl;
|
||||||
|
|
||||||
|
if (!buttons.empty())
|
||||||
|
{
|
||||||
|
std::cout << "buttons: ";
|
||||||
|
std::copy (buttons.begin(), buttons.end(), std::ostream_iterator<std::string> (std::cout, ", "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../mwmechanics/stat.hpp"
|
#include "../mwmechanics/stat.hpp"
|
||||||
|
|
||||||
|
@ -144,6 +145,8 @@ namespace MWGui
|
||||||
|
|
||||||
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
|
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
|
||||||
///< Set value for the given ID.
|
///< Set value for the given ID.
|
||||||
|
|
||||||
|
void messageBox (const std::string& message, const std::vector<std::string>& buttons);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
215
apps/openmw/mwscript/aiextensions.cpp
Normal file
215
apps/openmw/mwscript/aiextensions.cpp
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
|
||||||
|
#include "aiextensions.hpp"
|
||||||
|
|
||||||
|
#include <components/compiler/extensions.hpp>
|
||||||
|
|
||||||
|
#include <components/interpreter/interpreter.hpp>
|
||||||
|
#include <components/interpreter/runtime.hpp>
|
||||||
|
#include <components/interpreter/opcodes.hpp>
|
||||||
|
|
||||||
|
#include "interpretercontext.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace MWScript
|
||||||
|
{
|
||||||
|
namespace Ai
|
||||||
|
{
|
||||||
|
class OpAiTravel : public Interpreter::Opcode1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext& context
|
||||||
|
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getReference();
|
||||||
|
|
||||||
|
Interpreter::Type_Float x = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float y = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float z = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
|
std::cout << "AiTravel: " << x << ", " << y << ", " << z << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpAiTravelExplicit : public Interpreter::Opcode1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext& context
|
||||||
|
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
|
||||||
|
|
||||||
|
Interpreter::Type_Float x = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float y = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float z = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
|
std::cout << "AiTravel: " << x << ", " << y << ", " << z << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpAiEscort : public Interpreter::Opcode1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext& context
|
||||||
|
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getReference();
|
||||||
|
|
||||||
|
std::string actor = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float duration = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float x = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float y = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float z = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
|
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpAiEscortExplicit : public Interpreter::Opcode1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext& context
|
||||||
|
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
|
||||||
|
|
||||||
|
std::string actor = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float duration = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float x = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float y = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
Interpreter::Type_Float z = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
// discard additional arguments (reset), because we have no idea what they mean.
|
||||||
|
for (unsigned int i=0; i<arg0; ++i) runtime.pop();
|
||||||
|
|
||||||
|
std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpGetAiPackageDone : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext& context
|
||||||
|
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getReference();
|
||||||
|
|
||||||
|
Interpreter::Type_Integer value = 0;
|
||||||
|
|
||||||
|
runtime.push (value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpGetAiPackageDoneExplicit : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
MWScript::InterpreterContext& context
|
||||||
|
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
|
||||||
|
|
||||||
|
Interpreter::Type_Integer value = 0;
|
||||||
|
|
||||||
|
runtime.push (value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const int opcodeAiTravel = 0x20000;
|
||||||
|
const int opcodeAiTravelExplicit = 0x20001;
|
||||||
|
const int opcodeAiEscort = 0x20002;
|
||||||
|
const int opcodeAiEscortExplicit = 0x20003;
|
||||||
|
const int opcodeGetAiPackageDone = 0x200007c;
|
||||||
|
const int opcodeGetAiPackageDoneExplicit = 0x200007d;
|
||||||
|
|
||||||
|
void registerExtensions (Compiler::Extensions& extensions)
|
||||||
|
{
|
||||||
|
extensions.registerInstruction ("aitravel", "lll/l", opcodeAiTravel,
|
||||||
|
opcodeAiTravelExplicit);
|
||||||
|
extensions.registerInstruction ("aiescort", "cllll/l", opcodeAiEscort,
|
||||||
|
opcodeAiEscortExplicit);
|
||||||
|
|
||||||
|
extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone,
|
||||||
|
opcodeGetAiPackageDoneExplicit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
interpreter.installSegment3 (opcodeAiTravel, new OpAiTravel);
|
||||||
|
interpreter.installSegment3 (opcodeAiTravelExplicit, new OpAiTravelExplicit);
|
||||||
|
interpreter.installSegment3 (opcodeAiEscort, new OpAiEscort);
|
||||||
|
interpreter.installSegment3 (opcodeAiEscortExplicit, new OpAiEscortExplicit);
|
||||||
|
interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone);
|
||||||
|
interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDoneExplicit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
apps/openmw/mwscript/aiextensions.hpp
Normal file
25
apps/openmw/mwscript/aiextensions.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef GAME_SCRIPT_AIEXTENSIONS_H
|
||||||
|
#define GAME_SCRIPT_AIEXTENSIONS_H
|
||||||
|
|
||||||
|
namespace Compiler
|
||||||
|
{
|
||||||
|
class Extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Interpreter
|
||||||
|
{
|
||||||
|
class Interpreter;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWScript
|
||||||
|
{
|
||||||
|
/// \brief AI-related script functionality
|
||||||
|
namespace Ai
|
||||||
|
{
|
||||||
|
void registerExtensions (Compiler::Extensions& extensions);
|
||||||
|
|
||||||
|
void installOpcodes (Interpreter::Interpreter& interpreter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
70
apps/openmw/mwscript/controlextensions.cpp
Normal file
70
apps/openmw/mwscript/controlextensions.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
|
||||||
|
#include "statsextensions.hpp"
|
||||||
|
|
||||||
|
#include <components/compiler/extensions.hpp>
|
||||||
|
|
||||||
|
#include <components/interpreter/interpreter.hpp>
|
||||||
|
#include <components/interpreter/runtime.hpp>
|
||||||
|
#include <components/interpreter/opcodes.hpp>
|
||||||
|
|
||||||
|
#include "interpretercontext.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace MWScript
|
||||||
|
{
|
||||||
|
namespace Control
|
||||||
|
{
|
||||||
|
class OpSetControl : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
std::string mControl;
|
||||||
|
bool mEnable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
OpSetControl (const std::string& control, bool enable)
|
||||||
|
: mControl (control), mEnable (enable)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
if (mEnable)
|
||||||
|
std::cout << "enable: " << mControl << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << "disable: " << mControl << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const int numberOfControls = 7;
|
||||||
|
|
||||||
|
const int opcodeEnable = 0x200007e;
|
||||||
|
const int opcodeDisable = 0x2000085;
|
||||||
|
|
||||||
|
const char *controls[numberOfControls] =
|
||||||
|
{
|
||||||
|
"playercontrols", "playerfighting", "playerjumping", "playerlooking", "playermagic",
|
||||||
|
"playerviewswitch", "vanitymode"
|
||||||
|
};
|
||||||
|
|
||||||
|
void registerExtensions (Compiler::Extensions& extensions)
|
||||||
|
{
|
||||||
|
std::string enable ("enable");
|
||||||
|
std::string disable ("disable");
|
||||||
|
|
||||||
|
for (int i=0; i<numberOfControls; ++i)
|
||||||
|
{
|
||||||
|
extensions.registerInstruction (enable + controls[i], "", opcodeEnable+i);
|
||||||
|
extensions.registerInstruction (disable + controls[i], "", opcodeDisable+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
for (int i=0; i<numberOfControls; ++i)
|
||||||
|
{
|
||||||
|
interpreter.installSegment5 (opcodeEnable+i, new OpSetControl (controls[i], true));
|
||||||
|
interpreter.installSegment5 (opcodeDisable+i, new OpSetControl (controls[i], false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
apps/openmw/mwscript/controlextensions.hpp
Normal file
25
apps/openmw/mwscript/controlextensions.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef GAME_SCRIPT_CONTROLEXTENSIONS_H
|
||||||
|
#define GAME_SCRIPT_CONTROLEXTENSIONS_H
|
||||||
|
|
||||||
|
namespace Compiler
|
||||||
|
{
|
||||||
|
class Extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Interpreter
|
||||||
|
{
|
||||||
|
class Interpreter;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWScript
|
||||||
|
{
|
||||||
|
/// \brief player controls-related script functionality
|
||||||
|
namespace Control
|
||||||
|
{
|
||||||
|
void registerExtensions (Compiler::Extensions& extensions);
|
||||||
|
|
||||||
|
void installOpcodes (Interpreter::Interpreter& interpreter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -13,8 +13,13 @@ Segment 2:
|
||||||
opcodes 0x200-0x3ff unused
|
opcodes 0x200-0x3ff unused
|
||||||
|
|
||||||
Segment 3:
|
Segment 3:
|
||||||
(not implemented yet)
|
op 0x20000: AiTravel
|
||||||
opcodes 0x200-0x3ff unused
|
op 0x20001: AiTravel, explicit reference
|
||||||
|
op 0x20002: AiEscort
|
||||||
|
op 0x20003: AiEscort, explicit reference
|
||||||
|
op 0x20004: Lock
|
||||||
|
op 0x20005: Lock, explicit reference
|
||||||
|
opcodes 0x20006-0x3ffff unused
|
||||||
|
|
||||||
Segment 4:
|
Segment 4:
|
||||||
(not implemented yet)
|
(not implemented yet)
|
||||||
|
@ -83,5 +88,15 @@ op 0x2000078: GetItemCount
|
||||||
op 0x2000079: GetItemCount, explicit reference
|
op 0x2000079: GetItemCount, explicit reference
|
||||||
op 0x200007a: RemoveItem
|
op 0x200007a: RemoveItem
|
||||||
op 0x200007b: RemoveItem, explicit reference
|
op 0x200007b: RemoveItem, explicit reference
|
||||||
|
<<<<<<< HEAD:apps/openmw/mwscript/docs/vmformat.txt
|
||||||
op 0x200007c: COC
|
op 0x200007c: COC
|
||||||
opcodes 0x200007d-0x3ffffff unused
|
opcodes 0x200007d-0x3ffffff unused
|
||||||
|
=======
|
||||||
|
op 0x200007c: GetAiPackageDone
|
||||||
|
op 0x200007d: GetAiPackageDone, explicit reference
|
||||||
|
op 0x200007e-0x2000084: Enable Controls
|
||||||
|
op 0x2000085-0x200008b: Disable Controls
|
||||||
|
op 0x200008c: Unlock
|
||||||
|
op 0x200008d: Unlock, explicit reference
|
||||||
|
opcodes 0x200008e-0x3ffffff unused
|
||||||
|
>>>>>>> master:apps/openmw/mwscript/docs/vmformat.txt
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "skyextensions.hpp"
|
#include "skyextensions.hpp"
|
||||||
#include "statsextensions.hpp"
|
#include "statsextensions.hpp"
|
||||||
#include "containerextensions.hpp"
|
#include "containerextensions.hpp"
|
||||||
|
#include "aiextensions.hpp"
|
||||||
|
#include "controlextensions.hpp"
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
|
@ -23,6 +25,8 @@ namespace MWScript
|
||||||
Sky::registerExtensions (extensions);
|
Sky::registerExtensions (extensions);
|
||||||
Stats::registerExtensions (extensions);
|
Stats::registerExtensions (extensions);
|
||||||
Container::registerExtensions (extensions);
|
Container::registerExtensions (extensions);
|
||||||
|
Ai::registerExtensions (extensions);
|
||||||
|
Control::registerExtensions (extensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
|
@ -35,5 +39,7 @@ namespace MWScript
|
||||||
Sky::installOpcodes (interpreter);
|
Sky::installOpcodes (interpreter);
|
||||||
Stats::installOpcodes (interpreter);
|
Stats::installOpcodes (interpreter);
|
||||||
Container::installOpcodes (interpreter);
|
Container::installOpcodes (interpreter);
|
||||||
|
Ai::installOpcodes (interpreter);
|
||||||
|
Control::installOpcodes (interpreter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,10 +105,7 @@ namespace MWScript
|
||||||
void InterpreterContext::messageBox (const std::string& message,
|
void InterpreterContext::messageBox (const std::string& message,
|
||||||
const std::vector<std::string>& buttons)
|
const std::vector<std::string>& buttons)
|
||||||
{
|
{
|
||||||
std::cout << "message box: " << message << std::endl;
|
mEnvironment.mWindowManager->messageBox (message, buttons);
|
||||||
|
|
||||||
if (!buttons.empty())
|
|
||||||
std::cerr << "error: message box buttons not supported" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InterpreterContext::menuMode()
|
bool InterpreterContext::menuMode()
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include "interpretercontext.hpp"
|
#include "interpretercontext.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
namespace Misc
|
namespace Misc
|
||||||
|
@ -53,15 +55,104 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OpLock : public Interpreter::Opcode1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
|
{
|
||||||
|
InterpreterContext& context =
|
||||||
|
static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getReference();
|
||||||
|
|
||||||
|
Interpreter::Type_Integer lockLevel = 100;
|
||||||
|
|
||||||
|
if (arg0==1)
|
||||||
|
{
|
||||||
|
lockLevel = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Class::get (ptr).lock (ptr, lockLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpLockExplicit : public Interpreter::Opcode1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||||
|
{
|
||||||
|
InterpreterContext& context =
|
||||||
|
static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
|
||||||
|
|
||||||
|
Interpreter::Type_Integer lockLevel = 100;
|
||||||
|
|
||||||
|
if (arg0==1)
|
||||||
|
{
|
||||||
|
lockLevel = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Class::get (ptr).lock (ptr, lockLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpUnlock : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context =
|
||||||
|
static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getReference();
|
||||||
|
|
||||||
|
MWWorld::Class::get (ptr).unlock (ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpUnlockExplicit : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context =
|
||||||
|
static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
|
runtime.pop();
|
||||||
|
|
||||||
|
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
|
||||||
|
|
||||||
|
MWWorld::Class::get (ptr).unlock (ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const int opcodeXBox = 0x200000c;
|
const int opcodeXBox = 0x200000c;
|
||||||
const int opcodeOnActivate = 0x200000d;
|
const int opcodeOnActivate = 0x200000d;
|
||||||
const int opcodeActivate = 0x2000075;
|
const int opcodeActivate = 0x2000075;
|
||||||
|
const int opcodeLock = 0x20004;
|
||||||
|
const int opcodeLockExplicit = 0x20005;
|
||||||
|
const int opcodeUnlock = 0x200008c;
|
||||||
|
const int opcodeUnlockExplicit = 0x200008d;
|
||||||
|
|
||||||
void registerExtensions (Compiler::Extensions& extensions)
|
void registerExtensions (Compiler::Extensions& extensions)
|
||||||
{
|
{
|
||||||
extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
|
extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
|
||||||
extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate);
|
extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate);
|
||||||
extensions.registerInstruction ("activate", "", opcodeActivate);
|
extensions.registerInstruction ("activate", "", opcodeActivate);
|
||||||
|
extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit);
|
||||||
|
extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
|
@ -69,6 +160,10 @@ namespace MWScript
|
||||||
interpreter.installSegment5 (opcodeXBox, new OpXBox);
|
interpreter.installSegment5 (opcodeXBox, new OpXBox);
|
||||||
interpreter.installSegment5 (opcodeOnActivate, new OpOnActivate);
|
interpreter.installSegment5 (opcodeOnActivate, new OpOnActivate);
|
||||||
interpreter.installSegment5 (opcodeActivate, new OpActivate);
|
interpreter.installSegment5 (opcodeActivate, new OpActivate);
|
||||||
|
interpreter.installSegment3 (opcodeLock, new OpLock);
|
||||||
|
interpreter.installSegment3 (opcodeLockExplicit, new OpLockExplicit);
|
||||||
|
interpreter.installSegment5 (opcodeUnlock, new OpUnlock);
|
||||||
|
interpreter.installSegment5 (opcodeUnlockExplicit, new OpUnlockExplicit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace MWScript
|
||||||
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
|
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
|
||||||
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext)
|
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool ScriptManager::compile (const std::string& name)
|
bool ScriptManager::compile (const std::string& name)
|
||||||
{
|
{
|
||||||
mParser.reset();
|
mParser.reset();
|
||||||
|
@ -32,22 +32,22 @@ namespace MWScript
|
||||||
bool Success = true;
|
bool Success = true;
|
||||||
|
|
||||||
if (const ESM::Script *script = mStore.scripts.find (name))
|
if (const ESM::Script *script = mStore.scripts.find (name))
|
||||||
{
|
{
|
||||||
if (mVerbose)
|
if (mVerbose)
|
||||||
std::cout << "compiling script: " << name << std::endl;
|
std::cout << "compiling script: " << name << std::endl;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::istringstream input (script->scriptText);
|
std::istringstream input (script->scriptText);
|
||||||
|
|
||||||
Compiler::Scanner scanner (mErrorHandler, input, mCompilerContext.getExtensions());
|
Compiler::Scanner scanner (mErrorHandler, input, mCompilerContext.getExtensions());
|
||||||
|
|
||||||
scanner.scan (mParser);
|
scanner.scan (mParser);
|
||||||
|
|
||||||
if (!mErrorHandler.isGood())
|
if (!mErrorHandler.isGood())
|
||||||
Success = false;
|
Success = false;
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (...)
|
||||||
{
|
{
|
||||||
Success = false;
|
Success = false;
|
||||||
}
|
}
|
||||||
|
@ -59,20 +59,20 @@ namespace MWScript
|
||||||
<< script->scriptText
|
<< script->scriptText
|
||||||
<< std::endl << std::endl;
|
<< std::endl << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Success)
|
if (Success)
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code> code;
|
std::vector<Interpreter::Type_Code> code;
|
||||||
mParser.getCode (code);
|
mParser.getCode (code);
|
||||||
mScripts.insert (std::make_pair (name, code));
|
mScripts.insert (std::make_pair (name, code));
|
||||||
|
|
||||||
// TODO sanity check on generated locals
|
// TODO sanity check on generated locals
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
|
void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
|
||||||
|
@ -80,7 +80,7 @@ namespace MWScript
|
||||||
// compile script
|
// compile script
|
||||||
std::map<std::string, std::vector<Interpreter::Type_Code> >::iterator iter =
|
std::map<std::string, std::vector<Interpreter::Type_Code> >::iterator iter =
|
||||||
mScripts.find (name);
|
mScripts.find (name);
|
||||||
|
|
||||||
if (iter==mScripts.end())
|
if (iter==mScripts.end())
|
||||||
{
|
{
|
||||||
if (!compile (name))
|
if (!compile (name))
|
||||||
|
@ -90,28 +90,27 @@ namespace MWScript
|
||||||
mScripts.insert (std::make_pair (name, empty));
|
mScripts.insert (std::make_pair (name, empty));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter = mScripts.find (name);
|
iter = mScripts.find (name);
|
||||||
assert (iter!=mScripts.end());
|
assert (iter!=mScripts.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute script
|
// execute script
|
||||||
if (!iter->second.empty())
|
if (!iter->second.empty())
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Interpreter::Interpreter interpreter (interpreterContext);
|
Interpreter::Interpreter interpreter (interpreterContext);
|
||||||
installOpcodes (interpreter);
|
installOpcodes (interpreter);
|
||||||
interpreter.run (&iter->second[0], iter->second.size());
|
interpreter.run (&iter->second[0], iter->second.size());
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "exeution of script " << name << " failed." << std::endl;
|
std::cerr << "exeution of script " << name << " failed." << std::endl;
|
||||||
|
|
||||||
if (mVerbose)
|
if (mVerbose)
|
||||||
std::cerr << "(" << e.what() << ")" << std::endl;
|
std::cerr << "(" << e.what() << ")" << std::endl;
|
||||||
|
|
||||||
iter->second.clear(); // don't execute again.
|
iter->second.clear(); // don't execute again.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,12 @@ namespace MWSound
|
||||||
root->addFrameListener(&updater);
|
root->addFrameListener(&updater);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~SoundImpl()
|
||||||
|
{
|
||||||
|
Ogre::Root::getSingleton().removeFrameListener(&updater);
|
||||||
|
cameraTracker.unfollowCamera();
|
||||||
|
}
|
||||||
|
|
||||||
std::string toMp3(const std::string &str)
|
std::string toMp3(const std::string &str)
|
||||||
{
|
{
|
||||||
std::string wav = str;
|
std::string wav = str;
|
||||||
|
@ -147,10 +153,10 @@ namespace MWSound
|
||||||
const ESM::Sound *snd = store.sounds.search(soundId);
|
const ESM::Sound *snd = store.sounds.search(soundId);
|
||||||
if(snd == NULL) return "";
|
if(snd == NULL) return "";
|
||||||
|
|
||||||
volume *= snd->data.volume / 255.0;
|
volume *= snd->data.volume / 255.0f;
|
||||||
// These factors are not very fine tuned.
|
// These factors are not very fine tuned.
|
||||||
min = snd->data.minRange * 7;
|
min = snd->data.minRange * 7.0f;
|
||||||
max = snd->data.maxRange * 2000;
|
max = snd->data.maxRange * 2000.0f;
|
||||||
return convertPath(snd->sound);
|
return convertPath(snd->sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace MWWorld
|
||||||
: mCellName (cellName), mPosition (position)
|
: mCellName (cellName), mPosition (position)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void ActionTeleportPlayer::ActionTeleportPlayer::execute (Environment& environment)
|
void ActionTeleportPlayer::execute (Environment& environment)
|
||||||
{
|
{
|
||||||
if (mCellName.empty())
|
if (mCellName.empty())
|
||||||
environment.mWorld->changeToExteriorCell (mPosition);
|
environment.mWorld->changeToExteriorCell (mPosition);
|
||||||
|
|
|
@ -77,6 +77,16 @@ namespace MWWorld
|
||||||
throw std::runtime_error ("class does not support inserting into a container");
|
throw std::runtime_error ("class does not support inserting into a container");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Class::lock (const Ptr& ptr, int lockLevel) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("class does not support locking");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Class::unlock (const Ptr& ptr) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("class does not support unlocking");
|
||||||
|
}
|
||||||
|
|
||||||
std::string Class::getScript (const Ptr& ptr) const
|
std::string Class::getScript (const Ptr& ptr) const
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -98,6 +98,12 @@ namespace MWWorld
|
||||||
///< Insert into a container or throw an exception, if class does not support inserting into
|
///< Insert into a container or throw an exception, if class does not support inserting into
|
||||||
/// a container.
|
/// a container.
|
||||||
|
|
||||||
|
virtual void lock (const Ptr& ptr, int lockLevel) const;
|
||||||
|
///< Lock object (default implementation: throw an exception)
|
||||||
|
|
||||||
|
virtual void unlock (const Ptr& ptr) const;
|
||||||
|
///< Unlock object (default implementation: throw an exception)
|
||||||
|
|
||||||
virtual std::string getScript (const Ptr& ptr) const;
|
virtual std::string getScript (const Ptr& ptr) const;
|
||||||
///< Return name of the script attached to ptr (default implementation: return an empty
|
///< Return name of the script attached to ptr (default implementation: return an empty
|
||||||
/// string).
|
/// string).
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
|
|
||||||
#include <libs/mangle/stream/servers/file_stream.hpp>
|
#include <libs/mangle/stream/servers/file_stream.hpp>
|
||||||
#include <libs/mangle/stream/filters/slice_stream.hpp>
|
#include <libs/mangle/stream/filters/slice_stream.hpp>
|
||||||
#include <libs/mangle/tools/str_exception.hpp>
|
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ using namespace Mangle::Stream;
|
||||||
/// Error handling
|
/// Error handling
|
||||||
void BSAFile::fail(const string &msg)
|
void BSAFile::fail(const string &msg)
|
||||||
{
|
{
|
||||||
throw str_exception("BSA Error: " + msg + "\nArchive: " + filename);
|
throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read header information from the input source
|
/// Read header information from the input source
|
||||||
|
|
|
@ -17,21 +17,21 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
std::pair<Codes, Codes> entry;
|
std::pair<Codes, Codes> entry;
|
||||||
|
|
||||||
if (mState!=IfElseBodyState)
|
if (mState!=IfElseBodyState)
|
||||||
mExprParser.append (entry.first);
|
mExprParser.append (entry.first);
|
||||||
|
|
||||||
std::copy (mCodeBlock.begin(), mCodeBlock.end(),
|
std::copy (mCodeBlock.begin(), mCodeBlock.end(),
|
||||||
std::back_inserter (entry.second));
|
std::back_inserter (entry.second));
|
||||||
|
|
||||||
mIfCode.push_back (entry);
|
mIfCode.push_back (entry);
|
||||||
|
|
||||||
mCodeBlock.clear();
|
mCodeBlock.clear();
|
||||||
|
|
||||||
if (keyword==Scanner::K_endif)
|
if (keyword==Scanner::K_endif)
|
||||||
{
|
{
|
||||||
// store code for if-cascade
|
// store code for if-cascade
|
||||||
Codes codes;
|
Codes codes;
|
||||||
|
|
||||||
for (IfCodes::reverse_iterator iter (mIfCode.rbegin());
|
for (IfCodes::reverse_iterator iter (mIfCode.rbegin());
|
||||||
iter!=mIfCode.rend(); ++iter)
|
iter!=mIfCode.rend(); ++iter)
|
||||||
{
|
{
|
||||||
|
@ -47,17 +47,17 @@ namespace Compiler
|
||||||
std::back_inserter (block));
|
std::back_inserter (block));
|
||||||
Generator::jumpOnZero (block, iter->second.size()+1);
|
Generator::jumpOnZero (block, iter->second.size()+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy (iter->second.begin(), iter->second.end(),
|
std::copy (iter->second.begin(), iter->second.end(),
|
||||||
std::back_inserter (block));
|
std::back_inserter (block));
|
||||||
|
|
||||||
std::swap (codes, block);
|
std::swap (codes, block);
|
||||||
|
|
||||||
std::copy (block.begin(), block.end(), std::back_inserter (codes));
|
std::copy (block.begin(), block.end(), std::back_inserter (codes));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy (codes.begin(), codes.end(), std::back_inserter (mCode));
|
std::copy (codes.begin(), codes.end(), std::back_inserter (mCode));
|
||||||
|
|
||||||
mIfCode.clear();
|
mIfCode.clear();
|
||||||
mState = IfEndifState;
|
mState = IfEndifState;
|
||||||
}
|
}
|
||||||
|
@ -66,36 +66,36 @@ namespace Compiler
|
||||||
mExprParser.reset();
|
mExprParser.reset();
|
||||||
scanner.scan (mExprParser);
|
scanner.scan (mExprParser);
|
||||||
|
|
||||||
mState = IfElseifEndState;
|
mState = IfElseifEndState;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_else)
|
else if (keyword==Scanner::K_else)
|
||||||
{
|
{
|
||||||
mState = IfElseEndState;
|
mState = IfElseEndState;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_if || keyword==Scanner::K_while)
|
else if (keyword==Scanner::K_if || keyword==Scanner::K_while)
|
||||||
{
|
{
|
||||||
// nested
|
// nested
|
||||||
ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals);
|
ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals);
|
||||||
|
|
||||||
if (parser.parseKeyword (keyword, loc, scanner))
|
if (parser.parseKeyword (keyword, loc, scanner))
|
||||||
scanner.scan (parser);
|
scanner.scan (parser);
|
||||||
|
|
||||||
parser.appendCode (mCodeBlock);
|
parser.appendCode (mCodeBlock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mLineParser.reset();
|
mLineParser.reset();
|
||||||
if (mLineParser.parseKeyword (keyword, loc, scanner))
|
if (mLineParser.parseKeyword (keyword, loc, scanner))
|
||||||
scanner.scan (mLineParser);
|
scanner.scan (mLineParser);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,24 +104,24 @@ namespace Compiler
|
||||||
if (keyword==Scanner::K_endwhile)
|
if (keyword==Scanner::K_endwhile)
|
||||||
{
|
{
|
||||||
Codes loop;
|
Codes loop;
|
||||||
|
|
||||||
Codes expr;
|
Codes expr;
|
||||||
mExprParser.append (expr);
|
mExprParser.append (expr);
|
||||||
|
|
||||||
Generator::jump (loop, -mCodeBlock.size()-expr.size());
|
Generator::jump (loop, -mCodeBlock.size()-expr.size());
|
||||||
|
|
||||||
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
|
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
|
||||||
|
|
||||||
Codes skip;
|
Codes skip;
|
||||||
|
|
||||||
Generator::jumpOnZero (skip, mCodeBlock.size()+loop.size()+1);
|
Generator::jumpOnZero (skip, mCodeBlock.size()+loop.size()+1);
|
||||||
|
|
||||||
std::copy (skip.begin(), skip.end(), std::back_inserter (mCode));
|
std::copy (skip.begin(), skip.end(), std::back_inserter (mCode));
|
||||||
|
|
||||||
std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter (mCode));
|
std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter (mCode));
|
||||||
|
|
||||||
Codes loop2;
|
Codes loop2;
|
||||||
|
|
||||||
Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size());
|
Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size());
|
||||||
|
|
||||||
if (loop.size()!=loop2.size())
|
if (loop.size()!=loop2.size())
|
||||||
|
@ -129,31 +129,31 @@ namespace Compiler
|
||||||
"internal compiler error: failed to generate a while loop");
|
"internal compiler error: failed to generate a while loop");
|
||||||
|
|
||||||
std::copy (loop2.begin(), loop2.end(), std::back_inserter (mCode));
|
std::copy (loop2.begin(), loop2.end(), std::back_inserter (mCode));
|
||||||
|
|
||||||
mState = WhileEndwhileState;
|
mState = WhileEndwhileState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_if || keyword==Scanner::K_while)
|
else if (keyword==Scanner::K_if || keyword==Scanner::K_while)
|
||||||
{
|
{
|
||||||
// nested
|
// nested
|
||||||
ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals);
|
ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals);
|
||||||
|
|
||||||
if (parser.parseKeyword (keyword, loc, scanner))
|
if (parser.parseKeyword (keyword, loc, scanner))
|
||||||
scanner.scan (parser);
|
scanner.scan (parser);
|
||||||
|
|
||||||
parser.appendCode (mCodeBlock);
|
parser.appendCode (mCodeBlock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mLineParser.reset();
|
mLineParser.reset();
|
||||||
if (mLineParser.parseKeyword (keyword, loc, scanner))
|
if (mLineParser.parseKeyword (keyword, loc, scanner))
|
||||||
scanner.scan (mLineParser);
|
scanner.scan (mLineParser);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,14 +164,28 @@ namespace Compiler
|
||||||
mExprParser (errorHandler, context, locals, literals),
|
mExprParser (errorHandler, context, locals, literals),
|
||||||
mState (StartState)
|
mState (StartState)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlParser::appendCode (std::vector<Interpreter::Type_Code>& code) const
|
void ControlParser::appendCode (std::vector<Interpreter::Type_Code>& code) const
|
||||||
{
|
{
|
||||||
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ControlParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner)
|
||||||
|
{
|
||||||
|
if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState ||
|
||||||
|
mState==WhileBodyState)
|
||||||
|
{
|
||||||
|
scanner.putbackName (name, loc);
|
||||||
|
mLineParser.reset();
|
||||||
|
scanner.scan (mLineParser);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Parser::parseName (name, loc, scanner);
|
||||||
|
}
|
||||||
|
|
||||||
bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
if (mState==StartState)
|
if (mState==StartState)
|
||||||
|
@ -190,20 +204,20 @@ namespace Compiler
|
||||||
scanner.scan (mExprParser);
|
scanner.scan (mExprParser);
|
||||||
|
|
||||||
mState = WhileEndState;
|
mState = WhileEndState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState)
|
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState)
|
||||||
{
|
{
|
||||||
if (parseIfBody (keyword, loc, scanner))
|
if (parseIfBody (keyword, loc, scanner))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (mState==WhileBodyState)
|
else if (mState==WhileBodyState)
|
||||||
{
|
{
|
||||||
if ( parseWhileBody (keyword, loc, scanner))
|
if ( parseWhileBody (keyword, loc, scanner))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseKeyword (keyword, loc, scanner);
|
return Parser::parseKeyword (keyword, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,24 +232,24 @@ namespace Compiler
|
||||||
case IfElseEndState: mState = IfElseBodyState; return true;
|
case IfElseEndState: mState = IfElseBodyState; return true;
|
||||||
|
|
||||||
case WhileEndState: mState = WhileBodyState; return true;
|
case WhileEndState: mState = WhileBodyState; return true;
|
||||||
|
|
||||||
case IfBodyState:
|
case IfBodyState:
|
||||||
case IfElseifBodyState:
|
case IfElseifBodyState:
|
||||||
case IfElseBodyState:
|
case IfElseBodyState:
|
||||||
case WhileBodyState:
|
case WhileBodyState:
|
||||||
|
|
||||||
return true; // empty line
|
return true; // empty line
|
||||||
|
|
||||||
case IfEndifState:
|
case IfEndifState:
|
||||||
case WhileEndwhileState:
|
case WhileEndwhileState:
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseSpecial (code, loc, scanner);
|
return Parser::parseSpecial (code, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +259,6 @@ namespace Compiler
|
||||||
mCodeBlock.clear();
|
mCodeBlock.clear();
|
||||||
mIfCode.clear();
|
mIfCode.clear();
|
||||||
mState = StartState;
|
mState = StartState;
|
||||||
|
Parser::reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
class Locals;
|
class Locals;
|
||||||
class Literals;
|
class Literals;
|
||||||
|
|
||||||
// Control structure parser
|
// Control structure parser
|
||||||
|
|
||||||
class ControlParser : public Parser
|
class ControlParser : public Parser
|
||||||
{
|
{
|
||||||
enum State
|
enum State
|
||||||
|
@ -28,31 +28,36 @@ namespace Compiler
|
||||||
WhileEndState, WhileBodyState,
|
WhileEndState, WhileBodyState,
|
||||||
WhileEndwhileState
|
WhileEndwhileState
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Interpreter::Type_Code> Codes;
|
typedef std::vector<Interpreter::Type_Code> Codes;
|
||||||
typedef std::vector<std::pair<Codes, Codes> > IfCodes;
|
typedef std::vector<std::pair<Codes, Codes> > IfCodes;
|
||||||
|
|
||||||
Locals& mLocals;
|
Locals& mLocals;
|
||||||
Literals& mLiterals;
|
Literals& mLiterals;
|
||||||
Codes mCode;
|
Codes mCode;
|
||||||
Codes mCodeBlock;
|
Codes mCodeBlock;
|
||||||
IfCodes mIfCode; // condition, body
|
IfCodes mIfCode; // condition, body
|
||||||
LineParser mLineParser;
|
LineParser mLineParser;
|
||||||
ExprParser mExprParser;
|
ExprParser mExprParser;
|
||||||
State mState;
|
State mState;
|
||||||
|
|
||||||
bool parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner);
|
bool parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||||
|
|
||||||
bool parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner);
|
bool parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||||
Literals& literals);
|
Literals& literals);
|
||||||
|
|
||||||
void appendCode (std::vector<Interpreter::Type_Code>& code) const;
|
void appendCode (std::vector<Interpreter::Type_Code>& code) const;
|
||||||
///< store generated code in \æ code.
|
///< store generated code in \æ code.
|
||||||
|
|
||||||
|
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||||
|
Scanner& scanner);
|
||||||
|
///< Handle a name token.
|
||||||
|
/// \return fetch another token?
|
||||||
|
|
||||||
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||||
///< Handle a keyword token.
|
///< Handle a keyword token.
|
||||||
/// \return fetch another token?
|
/// \return fetch another token?
|
||||||
|
@ -67,4 +72,3 @@ namespace Compiler
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -22,33 +22,33 @@ namespace Compiler
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case '(':
|
case '(':
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 'e': // ==
|
case 'e': // ==
|
||||||
case 'n': // !=
|
case 'n': // !=
|
||||||
case 'l': // <
|
case 'l': // <
|
||||||
case 'L': // <=
|
case 'L': // <=
|
||||||
case 'g': // <
|
case 'g': // <
|
||||||
case 'G': // >=
|
case 'G': // >=
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
case '/':
|
case '/':
|
||||||
|
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
|
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ namespace Compiler
|
||||||
assert (Index<static_cast<int> (mOperands.size()));
|
assert (Index<static_cast<int> (mOperands.size()));
|
||||||
return mOperands[mOperands.size()-1-Index];
|
return mOperands[mOperands.size()-1-Index];
|
||||||
}
|
}
|
||||||
|
|
||||||
char ExprParser::getOperator() const
|
char ExprParser::getOperator() const
|
||||||
{
|
{
|
||||||
assert (!mOperators.empty());
|
assert (!mOperators.empty());
|
||||||
|
@ -70,27 +70,27 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
return std::find (mOperators.begin(), mOperators.end(), '(')!=mOperators.end();
|
return std::find (mOperators.begin(), mOperators.end(), '(')!=mOperators.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::popOperator()
|
void ExprParser::popOperator()
|
||||||
{
|
{
|
||||||
assert (!mOperators.empty());
|
assert (!mOperators.empty());
|
||||||
mOperators.resize (mOperators.size()-1);
|
mOperators.resize (mOperators.size()-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::popOperand()
|
void ExprParser::popOperand()
|
||||||
{
|
{
|
||||||
assert (!mOperands.empty());
|
assert (!mOperands.empty());
|
||||||
mOperands.resize (mOperands.size()-1);
|
mOperands.resize (mOperands.size()-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::replaceBinaryOperands()
|
void ExprParser::replaceBinaryOperands()
|
||||||
{
|
{
|
||||||
char t1 = getOperandType (1);
|
char t1 = getOperandType (1);
|
||||||
char t2 = getOperandType();
|
char t2 = getOperandType();
|
||||||
|
|
||||||
popOperand();
|
popOperand();
|
||||||
popOperand();
|
popOperand();
|
||||||
|
|
||||||
if (t1==t2)
|
if (t1==t2)
|
||||||
mOperands.push_back (t1);
|
mOperands.push_back (t1);
|
||||||
else if (t1=='f' || t2=='f')
|
else if (t1=='f' || t2=='f')
|
||||||
|
@ -102,59 +102,59 @@ namespace Compiler
|
||||||
void ExprParser::pop()
|
void ExprParser::pop()
|
||||||
{
|
{
|
||||||
char op = getOperator();
|
char op = getOperator();
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case 'm':
|
case 'm':
|
||||||
|
|
||||||
Generator::negate (mCode, getOperandType());
|
Generator::negate (mCode, getOperandType());
|
||||||
popOperator();
|
popOperator();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
|
|
||||||
Generator::add (mCode, getOperandType (1), getOperandType());
|
Generator::add (mCode, getOperandType (1), getOperandType());
|
||||||
popOperator();
|
popOperator();
|
||||||
replaceBinaryOperands();
|
replaceBinaryOperands();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
|
|
||||||
Generator::sub (mCode, getOperandType (1), getOperandType());
|
Generator::sub (mCode, getOperandType (1), getOperandType());
|
||||||
popOperator();
|
popOperator();
|
||||||
replaceBinaryOperands();
|
replaceBinaryOperands();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
|
|
||||||
Generator::mul (mCode, getOperandType (1), getOperandType());
|
Generator::mul (mCode, getOperandType (1), getOperandType());
|
||||||
popOperator();
|
popOperator();
|
||||||
replaceBinaryOperands();
|
replaceBinaryOperands();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '/':
|
case '/':
|
||||||
|
|
||||||
Generator::div (mCode, getOperandType (1), getOperandType());
|
Generator::div (mCode, getOperandType (1), getOperandType());
|
||||||
popOperator();
|
popOperator();
|
||||||
replaceBinaryOperands();
|
replaceBinaryOperands();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'n':
|
case 'n':
|
||||||
case 'l':
|
case 'l':
|
||||||
case 'L':
|
case 'L':
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
|
|
||||||
Generator::compare (mCode, op, getOperandType (1), getOperandType());
|
Generator::compare (mCode, op, getOperandType (1), getOperandType());
|
||||||
popOperator();
|
popOperator();
|
||||||
popOperand();
|
popOperand();
|
||||||
popOperand();
|
popOperand();
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('l');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
throw std::logic_error ("unknown operator");
|
throw std::logic_error ("unknown operator");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,36 +165,36 @@ namespace Compiler
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('l');
|
||||||
Generator::pushInt (mCode, mLiterals, value);
|
Generator::pushInt (mCode, mLiterals, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::pushFloatLiteral (float value)
|
void ExprParser::pushFloatLiteral (float value)
|
||||||
{
|
{
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
mOperands.push_back ('f');
|
mOperands.push_back ('f');
|
||||||
Generator::pushFloat (mCode, mLiterals, value);
|
Generator::pushFloat (mCode, mLiterals, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::pushBinaryOperator (char c)
|
void ExprParser::pushBinaryOperator (char c)
|
||||||
{
|
{
|
||||||
while (!mOperators.empty() && getPriority (getOperator())>=getPriority (c))
|
while (!mOperators.empty() && getPriority (getOperator())>=getPriority (c))
|
||||||
pop();
|
pop();
|
||||||
|
|
||||||
mOperators.push_back (c);
|
mOperators.push_back (c);
|
||||||
mNextOperand = true;
|
mNextOperand = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::close()
|
void ExprParser::close()
|
||||||
{
|
{
|
||||||
while (getOperator()!='(')
|
while (getOperator()!='(')
|
||||||
pop();
|
pop();
|
||||||
|
|
||||||
popOperator();
|
popOperator();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner)
|
int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner)
|
||||||
{
|
{
|
||||||
parseArguments (arguments, scanner, mCode);
|
return parseArguments (arguments, scanner, mCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||||
Literals& literals, bool argument)
|
Literals& literals, bool argument)
|
||||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
||||||
|
@ -205,11 +205,13 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
if (!mExplicit.empty())
|
if (!mExplicit.empty())
|
||||||
return Parser::parseInt (value, loc, scanner);
|
return Parser::parseInt (value, loc, scanner);
|
||||||
|
|
||||||
mFirst = false;
|
mFirst = false;
|
||||||
|
|
||||||
if (mNextOperand)
|
if (mNextOperand)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
pushIntegerLiteral (value);
|
pushIntegerLiteral (value);
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
return true;
|
return true;
|
||||||
|
@ -228,13 +230,15 @@ namespace Compiler
|
||||||
return Parser::parseFloat (value, loc, scanner);
|
return Parser::parseFloat (value, loc, scanner);
|
||||||
|
|
||||||
mFirst = false;
|
mFirst = false;
|
||||||
|
|
||||||
if (mNextOperand)
|
if (mNextOperand)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
pushFloatLiteral (value);
|
pushFloatLiteral (value);
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// no comma was used between arguments
|
// no comma was used between arguments
|
||||||
|
@ -252,29 +256,31 @@ namespace Compiler
|
||||||
mFirst = false;
|
mFirst = false;
|
||||||
|
|
||||||
if (mNextOperand)
|
if (mNextOperand)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
std::string name2 = toLower (name);
|
std::string name2 = toLower (name);
|
||||||
|
|
||||||
char type = mLocals.getType (name2);
|
char type = mLocals.getType (name2);
|
||||||
|
|
||||||
if (type!=' ')
|
if (type!=' ')
|
||||||
{
|
{
|
||||||
Generator::fetchLocal (mCode, type, mLocals.getIndex (name2));
|
Generator::fetchLocal (mCode, type, mLocals.getIndex (name2));
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
mOperands.push_back (type=='f' ? 'f' : 'l');
|
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
type = getContext().getGlobalType (name2);
|
type = getContext().getGlobalType (name2);
|
||||||
|
|
||||||
if (type!=' ')
|
if (type!=' ')
|
||||||
{
|
{
|
||||||
Generator::fetchGlobal (mCode, mLiterals, type, name2);
|
Generator::fetchGlobal (mCode, mLiterals, type, name2);
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
mOperands.push_back (type=='f' ? 'f' : 'l');
|
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExplicit.empty() && getContext().isId (name))
|
if (mExplicit.empty() && getContext().isId (name))
|
||||||
{
|
{
|
||||||
mExplicit = name;
|
mExplicit = name;
|
||||||
|
@ -287,161 +293,184 @@ namespace Compiler
|
||||||
scanner.putbackName (name, loc);
|
scanner.putbackName (name, loc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseName (name, loc, scanner);
|
return Parser::parseName (name, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
mFirst = false;
|
mFirst = false;
|
||||||
|
|
||||||
if (!mExplicit.empty())
|
if (!mExplicit.empty())
|
||||||
{
|
{
|
||||||
if (mRefOp && mNextOperand)
|
if (mRefOp && mNextOperand)
|
||||||
{
|
{
|
||||||
if (keyword==Scanner::K_getdisabled)
|
if (keyword==Scanner::K_getdisabled)
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
start();
|
||||||
|
|
||||||
|
mTokenLoc = loc;
|
||||||
|
|
||||||
Generator::getDisabled (mCode, mLiterals, mExplicit);
|
Generator::getDisabled (mCode, mLiterals, mExplicit);
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('l');
|
||||||
mExplicit.clear();
|
mExplicit.clear();
|
||||||
mRefOp = false;
|
mRefOp = false;
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_getdistance)
|
else if (keyword==Scanner::K_getdistance)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
parseArguments ("c", scanner);
|
parseArguments ("c", scanner);
|
||||||
|
|
||||||
Generator::getDistance (mCode, mLiterals, mExplicit);
|
Generator::getDistance (mCode, mLiterals, mExplicit);
|
||||||
mOperands.push_back ('f');
|
mOperands.push_back ('f');
|
||||||
mExplicit.clear();
|
mExplicit.clear();
|
||||||
mRefOp = false;
|
mRefOp = false;
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for custom extensions
|
// check for custom extensions
|
||||||
if (const Extensions *extensions = getContext().getExtensions())
|
if (const Extensions *extensions = getContext().getExtensions())
|
||||||
{
|
{
|
||||||
char returnType;
|
char returnType;
|
||||||
std::string argumentType;
|
std::string argumentType;
|
||||||
|
|
||||||
if (extensions->isFunction (keyword, returnType, argumentType, true))
|
if (extensions->isFunction (keyword, returnType, argumentType, true))
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
parseArguments (argumentType, scanner);
|
int optionals = parseArguments (argumentType, scanner);
|
||||||
|
|
||||||
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit);
|
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit,
|
||||||
|
optionals);
|
||||||
mOperands.push_back (returnType);
|
mOperands.push_back (returnType);
|
||||||
mExplicit.clear();
|
mExplicit.clear();
|
||||||
mRefOp = false;
|
mRefOp = false;
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseKeyword (keyword, loc, scanner);
|
return Parser::parseKeyword (keyword, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNextOperand)
|
if (mNextOperand)
|
||||||
{
|
{
|
||||||
if (keyword==Scanner::K_getsquareroot)
|
if (keyword==Scanner::K_getsquareroot)
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
start();
|
||||||
|
|
||||||
|
mTokenLoc = loc;
|
||||||
parseArguments ("f", scanner);
|
parseArguments ("f", scanner);
|
||||||
|
|
||||||
Generator::squareRoot (mCode);
|
Generator::squareRoot (mCode);
|
||||||
mOperands.push_back ('f');
|
mOperands.push_back ('f');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_menumode)
|
else if (keyword==Scanner::K_menumode)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
|
|
||||||
Generator::menuMode (mCode);
|
Generator::menuMode (mCode);
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('l');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_random)
|
else if (keyword==Scanner::K_random)
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
start();
|
||||||
|
|
||||||
|
mTokenLoc = loc;
|
||||||
parseArguments ("l", scanner);
|
parseArguments ("l", scanner);
|
||||||
|
|
||||||
Generator::random (mCode);
|
Generator::random (mCode);
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('l');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_scriptrunning)
|
else if (keyword==Scanner::K_scriptrunning)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
parseArguments ("c", scanner);
|
parseArguments ("c", scanner);
|
||||||
|
|
||||||
Generator::scriptRunning (mCode);
|
Generator::scriptRunning (mCode);
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('l');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_getdistance)
|
else if (keyword==Scanner::K_getdistance)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
parseArguments ("c", scanner);
|
parseArguments ("c", scanner);
|
||||||
|
|
||||||
Generator::getDistance (mCode, mLiterals, "");
|
Generator::getDistance (mCode, mLiterals, "");
|
||||||
mOperands.push_back ('f');
|
mOperands.push_back ('f');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_getsecondspassed)
|
else if (keyword==Scanner::K_getsecondspassed)
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
start();
|
||||||
|
|
||||||
|
mTokenLoc = loc;
|
||||||
|
|
||||||
Generator::getSecondsPassed (mCode);
|
Generator::getSecondsPassed (mCode);
|
||||||
mOperands.push_back ('f');
|
mOperands.push_back ('f');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (keyword==Scanner::K_getdisabled)
|
else if (keyword==Scanner::K_getdisabled)
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
start();
|
||||||
|
|
||||||
|
mTokenLoc = loc;
|
||||||
|
|
||||||
Generator::getDisabled (mCode, mLiterals, "");
|
Generator::getDisabled (mCode, mLiterals, "");
|
||||||
mOperands.push_back ('l');
|
mOperands.push_back ('l');
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check for custom extensions
|
// check for custom extensions
|
||||||
if (const Extensions *extensions = getContext().getExtensions())
|
if (const Extensions *extensions = getContext().getExtensions())
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
|
|
||||||
char returnType;
|
char returnType;
|
||||||
std::string argumentType;
|
std::string argumentType;
|
||||||
|
|
||||||
if (extensions->isFunction (keyword, returnType, argumentType, false))
|
if (extensions->isFunction (keyword, returnType, argumentType, false))
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
parseArguments (argumentType, scanner);
|
int optionals = parseArguments (argumentType, scanner);
|
||||||
|
|
||||||
extensions->generateFunctionCode (keyword, mCode, mLiterals, "");
|
extensions->generateFunctionCode (keyword, mCode, mLiterals, "", optionals);
|
||||||
mOperands.push_back (returnType);
|
mOperands.push_back (returnType);
|
||||||
|
|
||||||
mNextOperand = false;
|
mNextOperand = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +483,7 @@ namespace Compiler
|
||||||
scanner.putbackKeyword (keyword, loc);
|
scanner.putbackKeyword (keyword, loc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseKeyword (keyword, loc, scanner);
|
return Parser::parseKeyword (keyword, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,10 +496,10 @@ namespace Compiler
|
||||||
mRefOp = true;
|
mRefOp = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseSpecial (code, loc, scanner);
|
return Parser::parseSpecial (code, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code==Scanner::S_comma)
|
if (code==Scanner::S_comma)
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
|
@ -481,14 +510,14 @@ namespace Compiler
|
||||||
mFirst = false;
|
mFirst = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// end marker
|
// end marker
|
||||||
scanner.putbackSpecial (code, loc);
|
scanner.putbackSpecial (code, loc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mFirst = false;
|
mFirst = false;
|
||||||
|
|
||||||
if (code==Scanner::S_newline)
|
if (code==Scanner::S_newline)
|
||||||
{
|
{
|
||||||
// end marker
|
// end marker
|
||||||
|
@ -496,7 +525,7 @@ namespace Compiler
|
||||||
scanner.putbackSpecial (code, loc);
|
scanner.putbackSpecial (code, loc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code==Scanner::S_minus && mNextOperand)
|
if (code==Scanner::S_minus && mNextOperand)
|
||||||
{
|
{
|
||||||
// unary
|
// unary
|
||||||
|
@ -504,7 +533,7 @@ namespace Compiler
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code==Scanner::S_open)
|
if (code==Scanner::S_open)
|
||||||
{
|
{
|
||||||
if (mNextOperand)
|
if (mNextOperand)
|
||||||
|
@ -520,7 +549,7 @@ namespace Compiler
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code==Scanner::S_close && !mNextOperand)
|
if (code==Scanner::S_close && !mNextOperand)
|
||||||
{
|
{
|
||||||
if (isOpen())
|
if (isOpen())
|
||||||
|
@ -528,17 +557,17 @@ namespace Compiler
|
||||||
close();
|
close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
scanner.putbackSpecial (code, loc);
|
scanner.putbackSpecial (code, loc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mNextOperand)
|
if (!mNextOperand)
|
||||||
{
|
{
|
||||||
mTokenLoc = loc;
|
mTokenLoc = loc;
|
||||||
char c = 0; // comparison
|
char c = 0; // comparison
|
||||||
|
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case Scanner::S_plus: pushBinaryOperator ('+'); return true;
|
case Scanner::S_plus: pushBinaryOperator ('+'); return true;
|
||||||
|
@ -552,7 +581,7 @@ namespace Compiler
|
||||||
case Scanner::S_cmpGT: c = 'g'; break;
|
case Scanner::S_cmpGT: c = 'g'; break;
|
||||||
case Scanner::S_cmpGE: c = 'G'; break;
|
case Scanner::S_cmpGE: c = 'G'; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c)
|
if (c)
|
||||||
{
|
{
|
||||||
if (mArgument && !isOpen())
|
if (mArgument && !isOpen())
|
||||||
|
@ -562,15 +591,15 @@ namespace Compiler
|
||||||
scanner.putbackSpecial (code, loc);
|
scanner.putbackSpecial (code, loc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pushBinaryOperator (c);
|
pushBinaryOperator (c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseSpecial (code, loc, scanner);
|
return Parser::parseSpecial (code, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::reset()
|
void ExprParser::reset()
|
||||||
{
|
{
|
||||||
mOperands.clear();
|
mOperands.clear();
|
||||||
|
@ -580,8 +609,9 @@ namespace Compiler
|
||||||
mFirst = true;
|
mFirst = true;
|
||||||
mExplicit.clear();
|
mExplicit.clear();
|
||||||
mRefOp = false;
|
mRefOp = false;
|
||||||
|
Parser::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
char ExprParser::append (std::vector<Interpreter::Type_Code>& code)
|
char ExprParser::append (std::vector<Interpreter::Type_Code>& code)
|
||||||
{
|
{
|
||||||
if (mOperands.empty() && mOperators.empty())
|
if (mOperands.empty() && mOperators.empty())
|
||||||
|
@ -589,7 +619,7 @@ namespace Compiler
|
||||||
getErrorHandler().error ("missing expression", mTokenLoc);
|
getErrorHandler().error ("missing expression", mTokenLoc);
|
||||||
return 'l';
|
return 'l';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNextOperand || mOperands.empty())
|
if (mNextOperand || mOperands.empty())
|
||||||
{
|
{
|
||||||
getErrorHandler().error ("syntax error in expression", mTokenLoc);
|
getErrorHandler().error ("syntax error in expression", mTokenLoc);
|
||||||
|
@ -603,62 +633,90 @@ namespace Compiler
|
||||||
|
|
||||||
assert (mOperands.size()==1);
|
assert (mOperands.size()==1);
|
||||||
return mOperands[0];
|
return mOperands[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner,
|
int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner,
|
||||||
std::vector<Interpreter::Type_Code>& code, bool invert)
|
std::vector<Interpreter::Type_Code>& code, bool invert)
|
||||||
{
|
{
|
||||||
|
bool optional = false;
|
||||||
|
bool optionalCount = 0;
|
||||||
|
|
||||||
ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true);
|
ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true);
|
||||||
StringParser stringParser (getErrorHandler(), getContext(), mLiterals);
|
StringParser stringParser (getErrorHandler(), getContext(), mLiterals);
|
||||||
|
|
||||||
std::stack<std::vector<Interpreter::Type_Code> > stack;
|
std::stack<std::vector<Interpreter::Type_Code> > stack;
|
||||||
|
|
||||||
for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end();
|
for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end();
|
||||||
++iter)
|
++iter)
|
||||||
{
|
{
|
||||||
if (*iter=='S' || *iter=='c')
|
if (*iter=='/')
|
||||||
|
{
|
||||||
|
optional = true;
|
||||||
|
}
|
||||||
|
else if (*iter=='S' || *iter=='c')
|
||||||
{
|
{
|
||||||
stringParser.reset();
|
stringParser.reset();
|
||||||
|
|
||||||
|
if (optional)
|
||||||
|
stringParser.setOptional (true);
|
||||||
|
|
||||||
if (*iter=='c') stringParser.smashCase();
|
if (*iter=='c') stringParser.smashCase();
|
||||||
scanner.scan (stringParser);
|
scanner.scan (stringParser);
|
||||||
|
|
||||||
|
if (optional && stringParser.isEmpty())
|
||||||
|
break;
|
||||||
|
|
||||||
if (invert)
|
if (invert)
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code> tmp;
|
std::vector<Interpreter::Type_Code> tmp;
|
||||||
stringParser.append (tmp);
|
stringParser.append (tmp);
|
||||||
|
|
||||||
stack.push (tmp);
|
stack.push (tmp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
stringParser.append (code);
|
stringParser.append (code);
|
||||||
|
|
||||||
|
if (optional)
|
||||||
|
++optionalCount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parser.reset();
|
parser.reset();
|
||||||
|
|
||||||
|
if (optional)
|
||||||
|
parser.setOptional (true);
|
||||||
|
|
||||||
scanner.scan (parser);
|
scanner.scan (parser);
|
||||||
|
|
||||||
|
if (optional && parser.isEmpty())
|
||||||
|
break;
|
||||||
|
|
||||||
std::vector<Interpreter::Type_Code> tmp;
|
std::vector<Interpreter::Type_Code> tmp;
|
||||||
|
|
||||||
char type = parser.append (tmp);
|
char type = parser.append (tmp);
|
||||||
|
|
||||||
if (type!=*iter)
|
if (type!=*iter)
|
||||||
Generator::convert (tmp, type, *iter);
|
Generator::convert (tmp, type, *iter);
|
||||||
|
|
||||||
if (invert)
|
if (invert)
|
||||||
stack.push (tmp);
|
stack.push (tmp);
|
||||||
else
|
else
|
||||||
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
|
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
|
||||||
|
|
||||||
|
if (optional)
|
||||||
|
++optionalCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!stack.empty())
|
while (!stack.empty())
|
||||||
{
|
{
|
||||||
std::vector<Interpreter::Type_Code>& tmp = stack.top();
|
std::vector<Interpreter::Type_Code>& tmp = stack.top();
|
||||||
|
|
||||||
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
|
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
|
||||||
|
|
||||||
stack.pop();
|
stack.pop();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return optionalCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Compiler
|
||||||
|
|
||||||
class ExprParser : public Parser
|
class ExprParser : public Parser
|
||||||
{
|
{
|
||||||
Locals& mLocals;
|
Locals& mLocals;
|
||||||
Literals& mLiterals;
|
Literals& mLiterals;
|
||||||
std::vector<char> mOperands;
|
std::vector<char> mOperands;
|
||||||
std::vector<char> mOperators;
|
std::vector<char> mOperators;
|
||||||
|
@ -26,35 +26,35 @@ namespace Compiler
|
||||||
bool mArgument;
|
bool mArgument;
|
||||||
std::string mExplicit;
|
std::string mExplicit;
|
||||||
bool mRefOp;
|
bool mRefOp;
|
||||||
|
|
||||||
int getPriority (char op) const;
|
int getPriority (char op) const;
|
||||||
|
|
||||||
char getOperandType (int Index = 0) const;
|
char getOperandType (int Index = 0) const;
|
||||||
|
|
||||||
char getOperator() const;
|
char getOperator() const;
|
||||||
|
|
||||||
bool isOpen() const;
|
bool isOpen() const;
|
||||||
|
|
||||||
void popOperator();
|
void popOperator();
|
||||||
|
|
||||||
void popOperand();
|
void popOperand();
|
||||||
|
|
||||||
void replaceBinaryOperands();
|
void replaceBinaryOperands();
|
||||||
|
|
||||||
void pop();
|
void pop();
|
||||||
|
|
||||||
void pushIntegerLiteral (int value);
|
void pushIntegerLiteral (int value);
|
||||||
|
|
||||||
void pushFloatLiteral (float value);
|
void pushFloatLiteral (float value);
|
||||||
|
|
||||||
void pushBinaryOperator (char c);
|
void pushBinaryOperator (char c);
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
void parseArguments (const std::string& arguments, Scanner& scanner);
|
int parseArguments (const std::string& arguments, Scanner& scanner);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||||
Literals& literals, bool argument = false);
|
Literals& literals, bool argument = false);
|
||||||
///< constructor
|
///< constructor
|
||||||
|
@ -84,20 +84,22 @@ namespace Compiler
|
||||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||||
///< Handle a special character token.
|
///< Handle a special character token.
|
||||||
/// \return fetch another token?
|
/// \return fetch another token?
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
///< Reset parser to clean state.
|
///< Reset parser to clean state.
|
||||||
|
|
||||||
char append (std::vector<Interpreter::Type_Code>& code);
|
char append (std::vector<Interpreter::Type_Code>& code);
|
||||||
///< Generate code for parsed expression.
|
///< Generate code for parsed expression.
|
||||||
/// \return Type ('l': integer, 'f': float)
|
/// \return Type ('l': integer, 'f': float)
|
||||||
|
|
||||||
void parseArguments (const std::string& arguments, Scanner& scanner,
|
int parseArguments (const std::string& arguments, Scanner& scanner,
|
||||||
std::vector<Interpreter::Type_Code>& code, bool invert = false);
|
std::vector<Interpreter::Type_Code>& code, bool invert = false);
|
||||||
///< Parse sequence of arguments specified by \a arguments.
|
///< Parse sequence of arguments specified by \a arguments.
|
||||||
/// \param arguments Each character represents one arguments ('l': integer,
|
/// \param arguments Each character represents one arguments ('l': integer,
|
||||||
/// 'f': float, 'S': string, 'c': string (case smashed))
|
/// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
|
||||||
|
/// optional)
|
||||||
/// \param invert Store arguments in reverted order.
|
/// \param invert Store arguments in reverted order.
|
||||||
|
/// \return number of optional arguments
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,119 +14,197 @@ namespace Compiler
|
||||||
int Extensions::searchKeyword (const std::string& keyword) const
|
int Extensions::searchKeyword (const std::string& keyword) const
|
||||||
{
|
{
|
||||||
std::map<std::string, int>::const_iterator iter = mKeywords.find (keyword);
|
std::map<std::string, int>::const_iterator iter = mKeywords.find (keyword);
|
||||||
|
|
||||||
if (iter==mKeywords.end())
|
if (iter==mKeywords.end())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType,
|
bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType,
|
||||||
bool explicitReference) const
|
bool explicitReference) const
|
||||||
{
|
{
|
||||||
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
||||||
|
|
||||||
if (iter==mFunctions.end())
|
if (iter==mFunctions.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (explicitReference && iter->second.mCodeExplicit==-1)
|
if (explicitReference && iter->second.mCodeExplicit==-1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
returnType = iter->second.mReturn;
|
returnType = iter->second.mReturn;
|
||||||
argumentType = iter->second.mArguments;
|
argumentType = iter->second.mArguments;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Extensions::isInstruction (int keyword, std::string& argumentType,
|
bool Extensions::isInstruction (int keyword, std::string& argumentType,
|
||||||
bool explicitReference) const
|
bool explicitReference) const
|
||||||
{
|
{
|
||||||
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
||||||
|
|
||||||
if (iter==mInstructions.end())
|
if (iter==mInstructions.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (explicitReference && iter->second.mCodeExplicit==-1)
|
if (explicitReference && iter->second.mCodeExplicit==-1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
argumentType = iter->second.mArguments;
|
argumentType = iter->second.mArguments;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Extensions::registerFunction (const std::string& keyword, char returnType,
|
void Extensions::registerFunction (const std::string& keyword, char returnType,
|
||||||
const std::string& argumentType, int segment5code, int segment5codeExplicit)
|
const std::string& argumentType, int code, int codeExplicit)
|
||||||
{
|
{
|
||||||
assert (segment5code>=33554432 && segment5code<=67108863);
|
|
||||||
|
|
||||||
int code = mNextKeywordIndex--;
|
|
||||||
|
|
||||||
mKeywords.insert (std::make_pair (keyword, code));
|
|
||||||
|
|
||||||
Function function;
|
Function function;
|
||||||
|
|
||||||
|
if (argumentType.find ('/')==std::string::npos)
|
||||||
|
{
|
||||||
|
function.mSegment = 5;
|
||||||
|
assert (code>=33554432 && code<=67108863);
|
||||||
|
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
function.mSegment = 3;
|
||||||
|
assert (code>=0x20000 && code<=0x2ffff);
|
||||||
|
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
int keywordIndex = mNextKeywordIndex--;
|
||||||
|
|
||||||
|
mKeywords.insert (std::make_pair (keyword, keywordIndex));
|
||||||
|
|
||||||
function.mReturn = returnType;
|
function.mReturn = returnType;
|
||||||
function.mArguments = argumentType;
|
function.mArguments = argumentType;
|
||||||
function.mCode = segment5code;
|
function.mCode = code;
|
||||||
function.mCodeExplicit = segment5codeExplicit;
|
function.mCodeExplicit = codeExplicit;
|
||||||
|
|
||||||
mFunctions.insert (std::make_pair (code, function));
|
mFunctions.insert (std::make_pair (keywordIndex, function));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Extensions::registerInstruction (const std::string& keyword,
|
void Extensions::registerInstruction (const std::string& keyword,
|
||||||
const std::string& argumentType, int segment5code, int segment5codeExplicit)
|
const std::string& argumentType, int code, int codeExplicit)
|
||||||
{
|
{
|
||||||
assert (segment5code>=33554432 && segment5code<=67108863);
|
|
||||||
|
|
||||||
int code = mNextKeywordIndex--;
|
|
||||||
|
|
||||||
mKeywords.insert (std::make_pair (keyword, code));
|
|
||||||
|
|
||||||
Instruction instruction;
|
Instruction instruction;
|
||||||
|
|
||||||
|
if (argumentType.find ('/')==std::string::npos)
|
||||||
|
{
|
||||||
|
instruction.mSegment = 5;
|
||||||
|
assert (code>=33554432 && code<=67108863);
|
||||||
|
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instruction.mSegment = 3;
|
||||||
|
assert (code>=0x20000 && code<=0x2ffff);
|
||||||
|
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
int keywordIndex = mNextKeywordIndex--;
|
||||||
|
|
||||||
|
mKeywords.insert (std::make_pair (keyword, keywordIndex));
|
||||||
|
|
||||||
instruction.mArguments = argumentType;
|
instruction.mArguments = argumentType;
|
||||||
instruction.mCode = segment5code;
|
instruction.mCode = code;
|
||||||
instruction.mCodeExplicit = segment5codeExplicit;
|
instruction.mCodeExplicit = codeExplicit;
|
||||||
|
|
||||||
mInstructions.insert (std::make_pair (code, instruction));
|
mInstructions.insert (std::make_pair (keywordIndex, instruction));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Extensions::generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
void Extensions::generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
||||||
Literals& literals, const std::string& id) const
|
Literals& literals, const std::string& id, int optionalArguments) const
|
||||||
{
|
{
|
||||||
|
assert (optionalArguments>=0);
|
||||||
|
|
||||||
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
||||||
|
|
||||||
if (iter==mFunctions.end())
|
if (iter==mFunctions.end())
|
||||||
throw std::logic_error ("unknown custom function keyword");
|
throw std::logic_error ("unknown custom function keyword");
|
||||||
|
|
||||||
|
if (optionalArguments && iter->second.mSegment!=3)
|
||||||
|
throw std::logic_error ("functions with optional arguments must be placed into segment 3");
|
||||||
|
|
||||||
if (!id.empty())
|
if (!id.empty())
|
||||||
{
|
{
|
||||||
if (iter->second.mCodeExplicit==-1)
|
if (iter->second.mCodeExplicit==-1)
|
||||||
throw std::logic_error ("explicit references not supported");
|
throw std::logic_error ("explicit references not supported");
|
||||||
|
|
||||||
int index = literals.addString (id);
|
int index = literals.addString (id);
|
||||||
Generator::pushInt (code, literals, index);
|
Generator::pushInt (code, literals, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iter->second.mSegment)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
|
||||||
|
if (optionalArguments>=256)
|
||||||
|
throw std::logic_error ("number of optional arguments is too large for segment 3");
|
||||||
|
|
||||||
|
code.push_back (Generator::segment3 (
|
||||||
|
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
|
||||||
|
optionalArguments));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
|
||||||
|
code.push_back (Generator::segment5 (
|
||||||
|
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
throw std::logic_error ("unsupported code segment");
|
||||||
}
|
}
|
||||||
|
|
||||||
code.push_back (Generator::segment5 (
|
|
||||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Extensions::generateInstructionCode (int keyword,
|
void Extensions::generateInstructionCode (int keyword,
|
||||||
std::vector<Interpreter::Type_Code>& code, Literals& literals, const std::string& id)
|
std::vector<Interpreter::Type_Code>& code, Literals& literals, const std::string& id,
|
||||||
const
|
int optionalArguments) const
|
||||||
{
|
{
|
||||||
|
assert (optionalArguments>=0);
|
||||||
|
|
||||||
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
||||||
|
|
||||||
if (iter==mInstructions.end())
|
if (iter==mInstructions.end())
|
||||||
throw std::logic_error ("unknown custom instruction keyword");
|
throw std::logic_error ("unknown custom instruction keyword");
|
||||||
|
|
||||||
|
if (optionalArguments && iter->second.mSegment!=3)
|
||||||
|
throw std::logic_error ("instructions with optional arguments must be placed into segment 3");
|
||||||
|
|
||||||
if (!id.empty())
|
if (!id.empty())
|
||||||
{
|
{
|
||||||
if (iter->second.mCodeExplicit==-1)
|
if (iter->second.mCodeExplicit==-1)
|
||||||
throw std::logic_error ("explicit references not supported");
|
throw std::logic_error ("explicit references not supported");
|
||||||
|
|
||||||
int index = literals.addString (id);
|
int index = literals.addString (id);
|
||||||
Generator::pushInt (code, literals, index);
|
Generator::pushInt (code, literals, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
code.push_back (Generator::segment5 (
|
switch (iter->second.mSegment)
|
||||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
{
|
||||||
}
|
case 3:
|
||||||
|
|
||||||
|
if (optionalArguments>=256)
|
||||||
|
throw std::logic_error ("number of optional arguments is too large for segment 3");
|
||||||
|
|
||||||
|
code.push_back (Generator::segment3 (
|
||||||
|
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
|
||||||
|
optionalArguments));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
|
||||||
|
code.push_back (Generator::segment5 (
|
||||||
|
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
throw std::logic_error ("unsupported code segment");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
{
|
{
|
||||||
class Literals;
|
class Literals;
|
||||||
|
|
||||||
/// \brief Collection of compiler extensions
|
/// \brief Collection of compiler extensions
|
||||||
|
|
||||||
class Extensions
|
class Extensions
|
||||||
{
|
{
|
||||||
struct Function
|
struct Function
|
||||||
|
@ -21,29 +21,31 @@ namespace Compiler
|
||||||
std::string mArguments;
|
std::string mArguments;
|
||||||
int mCode;
|
int mCode;
|
||||||
int mCodeExplicit;
|
int mCodeExplicit;
|
||||||
|
int mSegment;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Instruction
|
struct Instruction
|
||||||
{
|
{
|
||||||
std::string mArguments;
|
std::string mArguments;
|
||||||
int mCode;
|
int mCode;
|
||||||
int mCodeExplicit;
|
int mCodeExplicit;
|
||||||
|
int mSegment;
|
||||||
};
|
};
|
||||||
|
|
||||||
int mNextKeywordIndex;
|
int mNextKeywordIndex;
|
||||||
std::map<std::string, int> mKeywords;
|
std::map<std::string, int> mKeywords;
|
||||||
std::map<int, Function> mFunctions;
|
std::map<int, Function> mFunctions;
|
||||||
std::map<int, Instruction> mInstructions;
|
std::map<int, Instruction> mInstructions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Extensions();
|
Extensions();
|
||||||
|
|
||||||
int searchKeyword (const std::string& keyword) const;
|
int searchKeyword (const std::string& keyword) const;
|
||||||
///< Return extension keyword code, that is assigned to the string \a keyword.
|
///< Return extension keyword code, that is assigned to the string \a keyword.
|
||||||
/// - if no match is found 0 is returned.
|
/// - if no match is found 0 is returned.
|
||||||
/// - keyword must be all lower case.
|
/// - keyword must be all lower case.
|
||||||
|
|
||||||
bool isFunction (int keyword, char& returnType, std::string& argumentType,
|
bool isFunction (int keyword, char& returnType, std::string& argumentType,
|
||||||
bool explicitReference) const;
|
bool explicitReference) const;
|
||||||
///< Is this keyword registered with a function? If yes, return return and argument
|
///< Is this keyword registered with a function? If yes, return return and argument
|
||||||
|
@ -52,32 +54,31 @@ namespace Compiler
|
||||||
bool isInstruction (int keyword, std::string& argumentType,
|
bool isInstruction (int keyword, std::string& argumentType,
|
||||||
bool explicitReference) const;
|
bool explicitReference) const;
|
||||||
///< Is this keyword registered with a function? If yes, return argument types.
|
///< Is this keyword registered with a function? If yes, return argument types.
|
||||||
|
|
||||||
void registerFunction (const std::string& keyword, char returnType,
|
void registerFunction (const std::string& keyword, char returnType,
|
||||||
const std::string& argumentType, int segment5code, int segment5codeExplicit = -1);
|
const std::string& argumentType, int code, int codeExplicit = -1);
|
||||||
///< Register a custom function
|
///< Register a custom function
|
||||||
/// - keyword must be all lower case.
|
/// - keyword must be all lower case.
|
||||||
/// - keyword must be unique
|
/// - keyword must be unique
|
||||||
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
|
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
|
||||||
/// \note Currently only segment 5 opcodes are supported.
|
/// \note Currently only segment 3 and segment 5 opcodes are supported.
|
||||||
|
|
||||||
void registerInstruction (const std::string& keyword,
|
void registerInstruction (const std::string& keyword,
|
||||||
const std::string& argumentType, int segment5code, int segment5codeExplicit = -1);
|
const std::string& argumentType, int code, int codeExplicit = -1);
|
||||||
///< Register a custom instruction
|
///< Register a custom instruction
|
||||||
/// - keyword must be all lower case.
|
/// - keyword must be all lower case.
|
||||||
/// - keyword must be unique
|
/// - keyword must be unique
|
||||||
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
|
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
|
||||||
/// \note Currently only segment 5 opcodes are supported.
|
/// \note Currently only segment 3 and segment 5 opcodes are supported.
|
||||||
|
|
||||||
void generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
void generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
||||||
Literals& literals, const std::string& id) const;
|
Literals& literals, const std::string& id, int optionalArguments) const;
|
||||||
///< Append code for function to \a code.
|
///< Append code for function to \a code.
|
||||||
|
|
||||||
void generateInstructionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
void generateInstructionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
||||||
Literals& literals, const std::string& id) const;
|
Literals& literals, const std::string& id, int optionalArguments) const;
|
||||||
///< Append code for function to \a code.
|
///< Append code for function to \a code.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
{
|
{
|
||||||
FileParser::FileParser (ErrorHandler& errorHandler, Context& context)
|
FileParser::FileParser (ErrorHandler& errorHandler, Context& context)
|
||||||
: Parser (errorHandler, context),
|
: Parser (errorHandler, context),
|
||||||
mScriptParser (errorHandler, context, mLocals, true),
|
mScriptParser (errorHandler, context, mLocals, true),
|
||||||
mState (BeginState)
|
mState (BeginState)
|
||||||
{}
|
{}
|
||||||
|
@ -17,12 +17,12 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
return mName;
|
return mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileParser::getCode (std::vector<Interpreter::Type_Code>& code) const
|
void FileParser::getCode (std::vector<Interpreter::Type_Code>& code) const
|
||||||
{
|
{
|
||||||
mScriptParser.getCode (code);
|
mScriptParser.getCode (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Locals& FileParser::getLocals() const
|
const Locals& FileParser::getLocals() const
|
||||||
{
|
{
|
||||||
return mLocals;
|
return mLocals;
|
||||||
|
@ -37,17 +37,17 @@ namespace Compiler
|
||||||
mState = BeginCompleteState;
|
mState = BeginCompleteState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==EndNameState)
|
if (mState==EndNameState)
|
||||||
{
|
{
|
||||||
// optional repeated name after end statement
|
// optional repeated name after end statement
|
||||||
if (mName!=name)
|
if (mName!=name)
|
||||||
reportWarning ("Names for script " + mName + " do not match", loc);
|
reportWarning ("Names for script " + mName + " do not match", loc);
|
||||||
|
|
||||||
mState = EndCompleteState;
|
mState = EndCompleteState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseName (name, loc, scanner);
|
return Parser::parseName (name, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace Compiler
|
||||||
mState = NameState;
|
mState = NameState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==NameState)
|
if (mState==NameState)
|
||||||
{
|
{
|
||||||
// keywords can be used as script names too. Thank you Morrowind for another
|
// keywords can be used as script names too. Thank you Morrowind for another
|
||||||
|
@ -67,7 +67,7 @@ namespace Compiler
|
||||||
mState = BeginCompleteState;
|
mState = BeginCompleteState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseKeyword (keyword, loc, scanner);
|
return Parser::parseKeyword (keyword, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,25 +80,25 @@ namespace Compiler
|
||||||
// ignore empty lines
|
// ignore empty lines
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==BeginCompleteState)
|
if (mState==BeginCompleteState)
|
||||||
{
|
{
|
||||||
// parse the script body
|
// parse the script body
|
||||||
mScriptParser.reset();
|
mScriptParser.reset();
|
||||||
|
|
||||||
scanner.scan (mScriptParser);
|
scanner.scan (mScriptParser);
|
||||||
|
|
||||||
mState = EndNameState;
|
mState = EndNameState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==EndCompleteState || mState==EndNameState)
|
if (mState==EndCompleteState || mState==EndNameState)
|
||||||
{
|
{
|
||||||
// we are done here -> ignore the rest of the script
|
// we are done here -> ignore the rest of the script
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseSpecial (code, loc, scanner);
|
return Parser::parseSpecial (code, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +107,12 @@ namespace Compiler
|
||||||
if (mState!=EndNameState && mState!=EndCompleteState)
|
if (mState!=EndNameState && mState!=EndCompleteState)
|
||||||
Parser::parseEOF (scanner);
|
Parser::parseEOF (scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileParser::reset()
|
void FileParser::reset()
|
||||||
{
|
{
|
||||||
mState = BeginState;
|
mState = BeginState;
|
||||||
mName.clear();
|
mName.clear();
|
||||||
mScriptParser.reset();
|
mScriptParser.reset();
|
||||||
|
Parser::reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,46 +9,46 @@
|
||||||
#include "literals.hpp"
|
#include "literals.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void opPushInt (Compiler::Generator::CodeContainer& code, int value)
|
void opPushInt (Compiler::Generator::CodeContainer& code, int value)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment0 (0, value));
|
code.push_back (Compiler::Generator::segment0 (0, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchIntLiteral (Compiler::Generator::CodeContainer& code)
|
void opFetchIntLiteral (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (4));
|
code.push_back (Compiler::Generator::segment5 (4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchFloatLiteral (Compiler::Generator::CodeContainer& code)
|
void opFetchFloatLiteral (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (5));
|
code.push_back (Compiler::Generator::segment5 (5));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opIntToFloat (Compiler::Generator::CodeContainer& code)
|
void opIntToFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (3));
|
code.push_back (Compiler::Generator::segment5 (3));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFloatToInt (Compiler::Generator::CodeContainer& code)
|
void opFloatToInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (6));
|
code.push_back (Compiler::Generator::segment5 (6));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStoreLocalShort (Compiler::Generator::CodeContainer& code)
|
void opStoreLocalShort (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (0));
|
code.push_back (Compiler::Generator::segment5 (0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStoreLocalLong (Compiler::Generator::CodeContainer& code)
|
void opStoreLocalLong (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (1));
|
code.push_back (Compiler::Generator::segment5 (1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStoreLocalFloat (Compiler::Generator::CodeContainer& code)
|
void opStoreLocalFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (2));
|
code.push_back (Compiler::Generator::segment5 (2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opNegateInt (Compiler::Generator::CodeContainer& code)
|
void opNegateInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
|
@ -99,46 +99,46 @@ namespace
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (16));
|
code.push_back (Compiler::Generator::segment5 (16));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opIntToFloat1 (Compiler::Generator::CodeContainer& code)
|
void opIntToFloat1 (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (17));
|
code.push_back (Compiler::Generator::segment5 (17));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFloatToInt1 (Compiler::Generator::CodeContainer& code)
|
void opFloatToInt1 (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (18));
|
code.push_back (Compiler::Generator::segment5 (18));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSquareRoot (Compiler::Generator::CodeContainer& code)
|
void opSquareRoot (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (19));
|
code.push_back (Compiler::Generator::segment5 (19));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opReturn (Compiler::Generator::CodeContainer& code)
|
void opReturn (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (20));
|
code.push_back (Compiler::Generator::segment5 (20));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opMessageBox (Compiler::Generator::CodeContainer& code, int buttons)
|
void opMessageBox (Compiler::Generator::CodeContainer& code, int buttons)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment3 (0, buttons));
|
code.push_back (Compiler::Generator::segment3 (0, buttons));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchLocalShort (Compiler::Generator::CodeContainer& code)
|
void opFetchLocalShort (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (21));
|
code.push_back (Compiler::Generator::segment5 (21));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchLocalLong (Compiler::Generator::CodeContainer& code)
|
void opFetchLocalLong (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (22));
|
code.push_back (Compiler::Generator::segment5 (22));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchLocalFloat (Compiler::Generator::CodeContainer& code)
|
void opFetchLocalFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (23));
|
code.push_back (Compiler::Generator::segment5 (23));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opJumpForward (Compiler::Generator::CodeContainer& code, int offset)
|
void opJumpForward (Compiler::Generator::CodeContainer& code, int offset)
|
||||||
{
|
{
|
||||||
|
@ -149,176 +149,176 @@ namespace
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment0 (2, offset));
|
code.push_back (Compiler::Generator::segment0 (2, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSkipOnZero (Compiler::Generator::CodeContainer& code)
|
void opSkipOnZero (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (24));
|
code.push_back (Compiler::Generator::segment5 (24));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opSkipOnNonZero (Compiler::Generator::CodeContainer& code)
|
void opSkipOnNonZero (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (25));
|
code.push_back (Compiler::Generator::segment5 (25));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opEqualInt (Compiler::Generator::CodeContainer& code)
|
void opEqualInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (26));
|
code.push_back (Compiler::Generator::segment5 (26));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opNonEqualInt (Compiler::Generator::CodeContainer& code)
|
void opNonEqualInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (27));
|
code.push_back (Compiler::Generator::segment5 (27));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opLessThanInt (Compiler::Generator::CodeContainer& code)
|
void opLessThanInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (28));
|
code.push_back (Compiler::Generator::segment5 (28));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opLessOrEqualInt (Compiler::Generator::CodeContainer& code)
|
void opLessOrEqualInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (29));
|
code.push_back (Compiler::Generator::segment5 (29));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGreaterThanInt (Compiler::Generator::CodeContainer& code)
|
void opGreaterThanInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (30));
|
code.push_back (Compiler::Generator::segment5 (30));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGreaterOrEqualInt (Compiler::Generator::CodeContainer& code)
|
void opGreaterOrEqualInt (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (31));
|
code.push_back (Compiler::Generator::segment5 (31));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opEqualFloat (Compiler::Generator::CodeContainer& code)
|
void opEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (32));
|
code.push_back (Compiler::Generator::segment5 (32));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opNonEqualFloat (Compiler::Generator::CodeContainer& code)
|
void opNonEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (33));
|
code.push_back (Compiler::Generator::segment5 (33));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opLessThanFloat (Compiler::Generator::CodeContainer& code)
|
void opLessThanFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (34));
|
code.push_back (Compiler::Generator::segment5 (34));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opLessOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
void opLessOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (35));
|
code.push_back (Compiler::Generator::segment5 (35));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGreaterThanFloat (Compiler::Generator::CodeContainer& code)
|
void opGreaterThanFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (36));
|
code.push_back (Compiler::Generator::segment5 (36));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGreaterOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
void opGreaterOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (37));
|
code.push_back (Compiler::Generator::segment5 (37));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opMenuMode (Compiler::Generator::CodeContainer& code)
|
void opMenuMode (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (38));
|
code.push_back (Compiler::Generator::segment5 (38));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStoreGlobalShort (Compiler::Generator::CodeContainer& code)
|
void opStoreGlobalShort (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (39));
|
code.push_back (Compiler::Generator::segment5 (39));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStoreGlobalLong (Compiler::Generator::CodeContainer& code)
|
void opStoreGlobalLong (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (40));
|
code.push_back (Compiler::Generator::segment5 (40));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStoreGlobalFloat (Compiler::Generator::CodeContainer& code)
|
void opStoreGlobalFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (41));
|
code.push_back (Compiler::Generator::segment5 (41));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchGlobalShort (Compiler::Generator::CodeContainer& code)
|
void opFetchGlobalShort (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (42));
|
code.push_back (Compiler::Generator::segment5 (42));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchGlobalLong (Compiler::Generator::CodeContainer& code)
|
void opFetchGlobalLong (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (43));
|
code.push_back (Compiler::Generator::segment5 (43));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opFetchGlobalFloat (Compiler::Generator::CodeContainer& code)
|
void opFetchGlobalFloat (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (44));
|
code.push_back (Compiler::Generator::segment5 (44));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opRandom (Compiler::Generator::CodeContainer& code)
|
void opRandom (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (45));
|
code.push_back (Compiler::Generator::segment5 (45));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opScriptRunning (Compiler::Generator::CodeContainer& code)
|
void opScriptRunning (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (46));
|
code.push_back (Compiler::Generator::segment5 (46));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStartScript (Compiler::Generator::CodeContainer& code)
|
void opStartScript (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (47));
|
code.push_back (Compiler::Generator::segment5 (47));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opStopScript (Compiler::Generator::CodeContainer& code)
|
void opStopScript (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (48));
|
code.push_back (Compiler::Generator::segment5 (48));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGetDistance (Compiler::Generator::CodeContainer& code)
|
void opGetDistance (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (49));
|
code.push_back (Compiler::Generator::segment5 (49));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGetSecondsPassed (Compiler::Generator::CodeContainer& code)
|
void opGetSecondsPassed (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (50));
|
code.push_back (Compiler::Generator::segment5 (50));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opEnable (Compiler::Generator::CodeContainer& code)
|
void opEnable (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (51));
|
code.push_back (Compiler::Generator::segment5 (51));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opDisable (Compiler::Generator::CodeContainer& code)
|
void opDisable (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (52));
|
code.push_back (Compiler::Generator::segment5 (52));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGetDisabled (Compiler::Generator::CodeContainer& code)
|
void opGetDisabled (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (53));
|
code.push_back (Compiler::Generator::segment5 (53));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opEnableExplicit (Compiler::Generator::CodeContainer& code)
|
void opEnableExplicit (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (54));
|
code.push_back (Compiler::Generator::segment5 (54));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opDisableExplicit (Compiler::Generator::CodeContainer& code)
|
void opDisableExplicit (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (55));
|
code.push_back (Compiler::Generator::segment5 (55));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGetDisabledExplicit (Compiler::Generator::CodeContainer& code)
|
void opGetDisabledExplicit (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (56));
|
code.push_back (Compiler::Generator::segment5 (56));
|
||||||
}
|
}
|
||||||
|
|
||||||
void opGetDistanceExplicit (Compiler::Generator::CodeContainer& code)
|
void opGetDistanceExplicit (Compiler::Generator::CodeContainer& code)
|
||||||
{
|
{
|
||||||
code.push_back (Compiler::Generator::segment5 (57));
|
code.push_back (Compiler::Generator::segment5 (57));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
|
@ -327,31 +327,31 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
void pushInt (CodeContainer& code, Literals& literals, int value)
|
void pushInt (CodeContainer& code, Literals& literals, int value)
|
||||||
{
|
{
|
||||||
int index = literals.addInteger (value);
|
int index = literals.addInteger (value);
|
||||||
opPushInt (code, index);
|
opPushInt (code, index);
|
||||||
opFetchIntLiteral (code);
|
opFetchIntLiteral (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushFloat (CodeContainer& code, Literals& literals, float value)
|
void pushFloat (CodeContainer& code, Literals& literals, float value)
|
||||||
{
|
{
|
||||||
int index = literals.addFloat (value);
|
int index = literals.addFloat (value);
|
||||||
opPushInt (code, index);
|
opPushInt (code, index);
|
||||||
opFetchFloatLiteral (code);
|
opFetchFloatLiteral (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushString (CodeContainer& code, Literals& literals, const std::string& value)
|
void pushString (CodeContainer& code, Literals& literals, const std::string& value)
|
||||||
{
|
{
|
||||||
int index = literals.addString (value);
|
int index = literals.addString (value);
|
||||||
opPushInt (code, index);
|
opPushInt (code, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assignToLocal (CodeContainer& code, char localType,
|
void assignToLocal (CodeContainer& code, char localType,
|
||||||
int localIndex, const CodeContainer& value, char valueType)
|
int localIndex, const CodeContainer& value, char valueType)
|
||||||
{
|
{
|
||||||
opPushInt (code, localIndex);
|
opPushInt (code, localIndex);
|
||||||
|
|
||||||
std::copy (value.begin(), value.end(), std::back_inserter (code));
|
std::copy (value.begin(), value.end(), std::back_inserter (code));
|
||||||
|
|
||||||
if (localType!=valueType)
|
if (localType!=valueType)
|
||||||
{
|
{
|
||||||
if (localType=='f' && valueType=='l')
|
if (localType=='f' && valueType=='l')
|
||||||
|
@ -363,26 +363,26 @@ namespace Compiler
|
||||||
opFloatToInt (code);
|
opFloatToInt (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (localType)
|
switch (localType)
|
||||||
{
|
{
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
opStoreLocalFloat (code);
|
opStoreLocalFloat (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
|
|
||||||
opStoreLocalShort (code);
|
opStoreLocalShort (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
||||||
opStoreLocalLong (code);
|
opStoreLocalLong (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,21 +392,21 @@ namespace Compiler
|
||||||
switch (valueType)
|
switch (valueType)
|
||||||
{
|
{
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
||||||
opNegateInt (code);
|
opNegateInt (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
opNegateFloat (code);
|
opNegateFloat (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add (CodeContainer& code, char valueType1, char valueType2)
|
void add (CodeContainer& code, char valueType1, char valueType2)
|
||||||
{
|
{
|
||||||
if (valueType1=='l' && valueType2=='l')
|
if (valueType1=='l' && valueType2=='l')
|
||||||
|
@ -420,7 +420,7 @@ namespace Compiler
|
||||||
|
|
||||||
if (valueType2=='l')
|
if (valueType2=='l')
|
||||||
opIntToFloat (code);
|
opIntToFloat (code);
|
||||||
|
|
||||||
opAddFloat (code);
|
opAddFloat (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,11 +438,11 @@ namespace Compiler
|
||||||
|
|
||||||
if (valueType2=='l')
|
if (valueType2=='l')
|
||||||
opIntToFloat (code);
|
opIntToFloat (code);
|
||||||
|
|
||||||
opSubFloat (code);
|
opSubFloat (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mul (CodeContainer& code, char valueType1, char valueType2)
|
void mul (CodeContainer& code, char valueType1, char valueType2)
|
||||||
{
|
{
|
||||||
if (valueType1=='l' && valueType2=='l')
|
if (valueType1=='l' && valueType2=='l')
|
||||||
|
@ -456,11 +456,11 @@ namespace Compiler
|
||||||
|
|
||||||
if (valueType2=='l')
|
if (valueType2=='l')
|
||||||
opIntToFloat (code);
|
opIntToFloat (code);
|
||||||
|
|
||||||
opMulFloat (code);
|
opMulFloat (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void div (CodeContainer& code, char valueType1, char valueType2)
|
void div (CodeContainer& code, char valueType1, char valueType2)
|
||||||
{
|
{
|
||||||
if (valueType1=='l' && valueType2=='l')
|
if (valueType1=='l' && valueType2=='l')
|
||||||
|
@ -474,11 +474,11 @@ namespace Compiler
|
||||||
|
|
||||||
if (valueType2=='l')
|
if (valueType2=='l')
|
||||||
opIntToFloat (code);
|
opIntToFloat (code);
|
||||||
|
|
||||||
opDivFloat (code);
|
opDivFloat (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void convert (CodeContainer& code, char fromType, char toType)
|
void convert (CodeContainer& code, char fromType, char toType)
|
||||||
{
|
{
|
||||||
if (fromType!=toType)
|
if (fromType!=toType)
|
||||||
|
@ -491,28 +491,31 @@ namespace Compiler
|
||||||
throw std::logic_error ("illegal type conversion");
|
throw std::logic_error ("illegal type conversion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void squareRoot (CodeContainer& code)
|
void squareRoot (CodeContainer& code)
|
||||||
{
|
{
|
||||||
opSquareRoot (code);
|
opSquareRoot (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit (CodeContainer& code)
|
void exit (CodeContainer& code)
|
||||||
{
|
{
|
||||||
opReturn (code);
|
opReturn (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void message (CodeContainer& code, Literals& literals, const std::string& message,
|
void message (CodeContainer& code, Literals& literals, const std::string& message,
|
||||||
int buttons)
|
int buttons)
|
||||||
{
|
{
|
||||||
assert (buttons==0);
|
assert (buttons>=0);
|
||||||
|
|
||||||
|
if (buttons>=256)
|
||||||
|
throw std::runtime_error ("A message box can't have more than 255 buttons");
|
||||||
|
|
||||||
int index = literals.addString (message);
|
int index = literals.addString (message);
|
||||||
|
|
||||||
opPushInt (code, index);
|
opPushInt (code, index);
|
||||||
opMessageBox (code, buttons);
|
opMessageBox (code, buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchLocal (CodeContainer& code, char localType, int localIndex)
|
void fetchLocal (CodeContainer& code, char localType, int localIndex)
|
||||||
{
|
{
|
||||||
opPushInt (code, localIndex);
|
opPushInt (code, localIndex);
|
||||||
|
@ -520,26 +523,26 @@ namespace Compiler
|
||||||
switch (localType)
|
switch (localType)
|
||||||
{
|
{
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
opFetchLocalFloat (code);
|
opFetchLocalFloat (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
|
|
||||||
opFetchLocalShort (code);
|
opFetchLocalShort (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
||||||
opFetchLocalLong (code);
|
opFetchLocalLong (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void jump (CodeContainer& code, int offset)
|
void jump (CodeContainer& code, int offset)
|
||||||
{
|
{
|
||||||
if (offset>0)
|
if (offset>0)
|
||||||
|
@ -549,27 +552,27 @@ namespace Compiler
|
||||||
else
|
else
|
||||||
throw std::logic_error ("inifite loop");
|
throw std::logic_error ("inifite loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
void jumpOnZero (CodeContainer& code, int offset)
|
void jumpOnZero (CodeContainer& code, int offset)
|
||||||
{
|
{
|
||||||
opSkipOnNonZero (code);
|
opSkipOnNonZero (code);
|
||||||
|
|
||||||
if (offset<0)
|
if (offset<0)
|
||||||
--offset; // compensate for skip instruction
|
--offset; // compensate for skip instruction
|
||||||
|
|
||||||
jump (code, offset);
|
jump (code, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void jumpOnNonZero (CodeContainer& code, int offset)
|
void jumpOnNonZero (CodeContainer& code, int offset)
|
||||||
{
|
{
|
||||||
opSkipOnZero (code);
|
opSkipOnZero (code);
|
||||||
|
|
||||||
if (offset<0)
|
if (offset<0)
|
||||||
--offset; // compensate for skip instruction
|
--offset; // compensate for skip instruction
|
||||||
|
|
||||||
jump (code, offset);
|
jump (code, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compare (CodeContainer& code, char op, char valueType1, char valueType2)
|
void compare (CodeContainer& code, char op, char valueType1, char valueType2)
|
||||||
{
|
{
|
||||||
if (valueType1=='l' && valueType2=='l')
|
if (valueType1=='l' && valueType2=='l')
|
||||||
|
@ -582,9 +585,9 @@ namespace Compiler
|
||||||
case 'L': opLessOrEqualInt (code); break;
|
case 'L': opLessOrEqualInt (code); break;
|
||||||
case 'g': opGreaterThanInt (code); break;
|
case 'g': opGreaterThanInt (code); break;
|
||||||
case 'G': opGreaterOrEqualInt (code); break;
|
case 'G': opGreaterOrEqualInt (code); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -595,7 +598,7 @@ namespace Compiler
|
||||||
|
|
||||||
if (valueType2=='l')
|
if (valueType2=='l')
|
||||||
opIntToFloat (code);
|
opIntToFloat (code);
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case 'e': opEqualFloat (code); break;
|
case 'e': opEqualFloat (code); break;
|
||||||
|
@ -604,28 +607,28 @@ namespace Compiler
|
||||||
case 'L': opLessOrEqualFloat (code); break;
|
case 'L': opLessOrEqualFloat (code); break;
|
||||||
case 'g': opGreaterThanFloat (code); break;
|
case 'g': opGreaterThanFloat (code); break;
|
||||||
case 'G': opGreaterOrEqualFloat (code); break;
|
case 'G': opGreaterOrEqualFloat (code); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuMode (CodeContainer& code)
|
void menuMode (CodeContainer& code)
|
||||||
{
|
{
|
||||||
opMenuMode (code);
|
opMenuMode (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||||
const std::string& name, const CodeContainer& value, char valueType)
|
const std::string& name, const CodeContainer& value, char valueType)
|
||||||
{
|
{
|
||||||
int index = literals.addString (name);
|
int index = literals.addString (name);
|
||||||
|
|
||||||
opPushInt (code, index);
|
opPushInt (code, index);
|
||||||
|
|
||||||
std::copy (value.begin(), value.end(), std::back_inserter (code));
|
std::copy (value.begin(), value.end(), std::back_inserter (code));
|
||||||
|
|
||||||
if (localType!=valueType)
|
if (localType!=valueType)
|
||||||
{
|
{
|
||||||
if (localType=='f' && valueType=='l')
|
if (localType=='f' && valueType=='l')
|
||||||
|
@ -637,30 +640,30 @@ namespace Compiler
|
||||||
opFloatToInt (code);
|
opFloatToInt (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (localType)
|
switch (localType)
|
||||||
{
|
{
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
opStoreGlobalFloat (code);
|
opStoreGlobalFloat (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
|
|
||||||
opStoreGlobalShort (code);
|
opStoreGlobalShort (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
||||||
opStoreGlobalLong (code);
|
opStoreGlobalLong (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchGlobal (CodeContainer& code, Literals& literals, char localType,
|
void fetchGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||||
const std::string& name)
|
const std::string& name)
|
||||||
{
|
{
|
||||||
|
@ -671,36 +674,36 @@ namespace Compiler
|
||||||
switch (localType)
|
switch (localType)
|
||||||
{
|
{
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
opFetchGlobalFloat (code);
|
opFetchGlobalFloat (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
|
|
||||||
opFetchGlobalShort (code);
|
opFetchGlobalShort (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
||||||
opFetchGlobalLong (code);
|
opFetchGlobalLong (code);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void random (CodeContainer& code)
|
void random (CodeContainer& code)
|
||||||
{
|
{
|
||||||
opRandom (code);
|
opRandom (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scriptRunning (CodeContainer& code)
|
void scriptRunning (CodeContainer& code)
|
||||||
{
|
{
|
||||||
opScriptRunning (code);
|
opScriptRunning (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startScript (CodeContainer& code)
|
void startScript (CodeContainer& code)
|
||||||
{
|
{
|
||||||
opStartScript (code);
|
opStartScript (code);
|
||||||
|
@ -714,7 +717,7 @@ namespace Compiler
|
||||||
void getDistance (CodeContainer& code, Literals& literals, const std::string id)
|
void getDistance (CodeContainer& code, Literals& literals, const std::string id)
|
||||||
{
|
{
|
||||||
if (id.empty())
|
if (id.empty())
|
||||||
{
|
{
|
||||||
opGetDistance (code);
|
opGetDistance (code);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -722,14 +725,14 @@ namespace Compiler
|
||||||
int index = literals.addString (id);
|
int index = literals.addString (id);
|
||||||
opPushInt (code, index);
|
opPushInt (code, index);
|
||||||
opGetDistanceExplicit (code);
|
opGetDistanceExplicit (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getSecondsPassed (CodeContainer& code)
|
void getSecondsPassed (CodeContainer& code)
|
||||||
{
|
{
|
||||||
opGetSecondsPassed (code);
|
opGetSecondsPassed (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getDisabled (CodeContainer& code, Literals& literals, const std::string id)
|
void getDisabled (CodeContainer& code, Literals& literals, const std::string id)
|
||||||
{
|
{
|
||||||
if (id.empty())
|
if (id.empty())
|
||||||
|
@ -743,11 +746,11 @@ namespace Compiler
|
||||||
opGetDisabledExplicit (code);
|
opGetDisabledExplicit (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void enable (CodeContainer& code, Literals& literals, const std::string id)
|
void enable (CodeContainer& code, Literals& literals, const std::string id)
|
||||||
{
|
{
|
||||||
if (id.empty())
|
if (id.empty())
|
||||||
{
|
{
|
||||||
opEnable (code);
|
opEnable (code);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -755,13 +758,13 @@ namespace Compiler
|
||||||
int index = literals.addString (id);
|
int index = literals.addString (id);
|
||||||
opPushInt (code, index);
|
opPushInt (code, index);
|
||||||
opEnableExplicit (code);
|
opEnableExplicit (code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable (CodeContainer& code, Literals& literals, const std::string id)
|
void disable (CodeContainer& code, Literals& literals, const std::string id)
|
||||||
{
|
{
|
||||||
if (id.empty())
|
if (id.empty())
|
||||||
{
|
{
|
||||||
opDisable (code);
|
opDisable (code);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -773,4 +776,3 @@ namespace Compiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ namespace Compiler
|
||||||
|
|
||||||
inline Interpreter::Type_Code segment3 (unsigned int c, unsigned int arg0)
|
inline Interpreter::Type_Code segment3 (unsigned int c, unsigned int arg0)
|
||||||
{
|
{
|
||||||
assert (c<1024);
|
assert (c<262144);
|
||||||
return 0xc0000000 | (c<<20) | (arg0 & 0xffff);
|
return 0xc0000000 | (c<<8) | (arg0 & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Interpreter::Type_Code segment4 (unsigned int c, unsigned int arg0,
|
inline Interpreter::Type_Code segment4 (unsigned int c, unsigned int arg0,
|
||||||
|
@ -52,72 +52,71 @@ namespace Compiler
|
||||||
assert (c<67108864);
|
assert (c<67108864);
|
||||||
return 0xc8000000 | c;
|
return 0xc8000000 | c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushInt (CodeContainer& code, Literals& literals, int value);
|
void pushInt (CodeContainer& code, Literals& literals, int value);
|
||||||
|
|
||||||
void pushFloat (CodeContainer& code, Literals& literals, float value);
|
void pushFloat (CodeContainer& code, Literals& literals, float value);
|
||||||
|
|
||||||
void pushString (CodeContainer& code, Literals& literals, const std::string& value);
|
void pushString (CodeContainer& code, Literals& literals, const std::string& value);
|
||||||
|
|
||||||
void assignToLocal (CodeContainer& code, char localType,
|
void assignToLocal (CodeContainer& code, char localType,
|
||||||
int localIndex, const CodeContainer& value, char valueType);
|
int localIndex, const CodeContainer& value, char valueType);
|
||||||
|
|
||||||
void negate (CodeContainer& code, char valueType);
|
void negate (CodeContainer& code, char valueType);
|
||||||
|
|
||||||
void add (CodeContainer& code, char valueType1, char valueType2);
|
void add (CodeContainer& code, char valueType1, char valueType2);
|
||||||
|
|
||||||
void sub (CodeContainer& code, char valueType1, char valueType2);
|
void sub (CodeContainer& code, char valueType1, char valueType2);
|
||||||
|
|
||||||
void mul (CodeContainer& code, char valueType1, char valueType2);
|
void mul (CodeContainer& code, char valueType1, char valueType2);
|
||||||
|
|
||||||
void div (CodeContainer& code, char valueType1, char valueType2);
|
void div (CodeContainer& code, char valueType1, char valueType2);
|
||||||
|
|
||||||
void convert (CodeContainer& code, char fromType, char toType);
|
void convert (CodeContainer& code, char fromType, char toType);
|
||||||
|
|
||||||
void squareRoot (CodeContainer& code);
|
void squareRoot (CodeContainer& code);
|
||||||
|
|
||||||
void exit (CodeContainer& code);
|
void exit (CodeContainer& code);
|
||||||
|
|
||||||
void message (CodeContainer& code, Literals& literals, const std::string& message,
|
void message (CodeContainer& code, Literals& literals, const std::string& message,
|
||||||
int buttons);
|
int buttons);
|
||||||
|
|
||||||
void fetchLocal (CodeContainer& code, char localType, int localIndex);
|
void fetchLocal (CodeContainer& code, char localType, int localIndex);
|
||||||
|
|
||||||
void jump (CodeContainer& code, int offset);
|
void jump (CodeContainer& code, int offset);
|
||||||
|
|
||||||
void jumpOnZero (CodeContainer& code, int offset);
|
void jumpOnZero (CodeContainer& code, int offset);
|
||||||
|
|
||||||
void jumpOnNonZero (CodeContainer& code, int offset);
|
void jumpOnNonZero (CodeContainer& code, int offset);
|
||||||
|
|
||||||
void compare (CodeContainer& code, char op, char valueType1, char valueType2);
|
void compare (CodeContainer& code, char op, char valueType1, char valueType2);
|
||||||
|
|
||||||
void menuMode (CodeContainer& code);
|
void menuMode (CodeContainer& code);
|
||||||
|
|
||||||
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||||
const std::string& name, const CodeContainer& value, char valueType);
|
const std::string& name, const CodeContainer& value, char valueType);
|
||||||
|
|
||||||
void fetchGlobal (CodeContainer& code, Literals& literals, char localType,
|
void fetchGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||||
const std::string& name);
|
const std::string& name);
|
||||||
|
|
||||||
void random (CodeContainer& code);
|
void random (CodeContainer& code);
|
||||||
|
|
||||||
void scriptRunning (CodeContainer& code);
|
void scriptRunning (CodeContainer& code);
|
||||||
|
|
||||||
void startScript (CodeContainer& code);
|
void startScript (CodeContainer& code);
|
||||||
|
|
||||||
void stopScript (CodeContainer& code);
|
void stopScript (CodeContainer& code);
|
||||||
|
|
||||||
void getDistance (CodeContainer& code, Literals& literals, const std::string id);
|
void getDistance (CodeContainer& code, Literals& literals, const std::string id);
|
||||||
|
|
||||||
void getSecondsPassed (CodeContainer& code);
|
void getSecondsPassed (CodeContainer& code);
|
||||||
|
|
||||||
void getDisabled (CodeContainer& code, Literals& literals, const std::string id);
|
void getDisabled (CodeContainer& code, Literals& literals, const std::string id);
|
||||||
|
|
||||||
void enable (CodeContainer& code, Literals& literals, const std::string id);
|
void enable (CodeContainer& code, Literals& literals, const std::string id);
|
||||||
|
|
||||||
void disable (CodeContainer& code, Literals& literals, const std::string id);
|
void disable (CodeContainer& code, Literals& literals, const std::string id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -14,32 +14,32 @@ namespace Compiler
|
||||||
void LineParser::parseExpression (Scanner& scanner, const TokenLoc& loc)
|
void LineParser::parseExpression (Scanner& scanner, const TokenLoc& loc)
|
||||||
{
|
{
|
||||||
mExprParser.reset();
|
mExprParser.reset();
|
||||||
|
|
||||||
if (!mExplicit.empty())
|
if (!mExplicit.empty())
|
||||||
{
|
{
|
||||||
mExprParser.parseName (mExplicit, loc, scanner);
|
mExprParser.parseName (mExplicit, loc, scanner);
|
||||||
mExprParser.parseSpecial (Scanner::S_ref, loc, scanner);
|
mExprParser.parseSpecial (Scanner::S_ref, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner.scan (mExprParser);
|
scanner.scan (mExprParser);
|
||||||
|
|
||||||
char type = mExprParser.append (mCode);
|
char type = mExprParser.append (mCode);
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
||||||
Generator::message (mCode, mLiterals, "%g", 0);
|
Generator::message (mCode, mLiterals, "%g", 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
||||||
Generator::message (mCode, mLiterals, "%f", 0);
|
Generator::message (mCode, mLiterals, "%f", 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
throw std::runtime_error ("unknown expression result type");
|
throw std::runtime_error ("unknown expression result type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,14 +52,14 @@ namespace Compiler
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
if (mAllowExpression && mState==BeginState)
|
if (mAllowExpression && mState==BeginState)
|
||||||
{
|
{
|
||||||
scanner.putbackInt (value, loc);
|
scanner.putbackInt (value, loc);
|
||||||
parseExpression (scanner, loc);
|
parseExpression (scanner, loc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseInt (value, loc, scanner);
|
return Parser::parseInt (value, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ namespace Compiler
|
||||||
parseExpression (scanner, loc);
|
parseExpression (scanner, loc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseFloat (value, loc, scanner);
|
return Parser::parseFloat (value, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +87,11 @@ namespace Compiler
|
||||||
scanner.scan (skip);
|
scanner.scan (skip);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name2 = toLower (name);
|
std::string name2 = toLower (name);
|
||||||
|
|
||||||
char type = mLocals.getType (name2);
|
char type = mLocals.getType (name2);
|
||||||
|
|
||||||
if (type!=' ')
|
if (type!=' ')
|
||||||
{
|
{
|
||||||
getErrorHandler().error ("can't re-declare local variable", loc);
|
getErrorHandler().error ("can't re-declare local variable", loc);
|
||||||
|
@ -99,14 +99,14 @@ namespace Compiler
|
||||||
scanner.scan (skip);
|
scanner.scan (skip);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'),
|
mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'),
|
||||||
name2);
|
name2);
|
||||||
|
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==SetState)
|
if (mState==SetState)
|
||||||
{
|
{
|
||||||
std::string name2 = toLower (name);
|
std::string name2 = toLower (name);
|
||||||
|
@ -119,7 +119,7 @@ namespace Compiler
|
||||||
mState = SetLocalVarState;
|
mState = SetLocalVarState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
type = getContext().getGlobalType (name2);
|
type = getContext().getGlobalType (name2);
|
||||||
if (type!=' ')
|
if (type!=' ')
|
||||||
{
|
{
|
||||||
|
@ -127,18 +127,18 @@ namespace Compiler
|
||||||
mType = type;
|
mType = type;
|
||||||
mState = SetGlobalVarState;
|
mState = SetGlobalVarState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getErrorHandler().error ("unknown variable", loc);
|
getErrorHandler().error ("unknown variable", loc);
|
||||||
SkipParser skip (getErrorHandler(), getContext());
|
SkipParser skip (getErrorHandler(), getContext());
|
||||||
scanner.scan (skip);
|
scanner.scan (skip);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==MessageState || mState==MessageCommaState)
|
if (mState==MessageState || mState==MessageCommaState)
|
||||||
{
|
{
|
||||||
std::string arguments;
|
std::string arguments;
|
||||||
|
|
||||||
for (std::size_t i=0; i<name.size(); ++i)
|
for (std::size_t i=0; i<name.size(); ++i)
|
||||||
{
|
{
|
||||||
if (name[i]=='%')
|
if (name[i]=='%')
|
||||||
|
@ -167,46 +167,52 @@ namespace Compiler
|
||||||
mExprParser.reset();
|
mExprParser.reset();
|
||||||
mExprParser.parseArguments (arguments, scanner, mCode, true);
|
mExprParser.parseArguments (arguments, scanner, mCode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for now skip buttons
|
|
||||||
SkipParser skip (getErrorHandler(), getContext());
|
|
||||||
scanner.scan (skip);
|
|
||||||
|
|
||||||
Generator::message (mCode, mLiterals, name, 0);
|
mName = name;
|
||||||
mState = EndState;
|
mButtons = 0;
|
||||||
return false;
|
|
||||||
|
mState = MessageButtonState;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==BeginState && mAllowExpression)
|
if (mState==MessageButtonState || mState==MessageButtonCommaState)
|
||||||
{
|
{
|
||||||
std::string name2 = toLower (name);
|
Generator::pushString (mCode, mLiterals, name);
|
||||||
|
mState = MessageButtonState;
|
||||||
char type = mLocals.getType (name2);
|
++mButtons;
|
||||||
|
return true;
|
||||||
if (type!=' ')
|
|
||||||
{
|
|
||||||
scanner.putbackName (name, loc);
|
|
||||||
parseExpression (scanner, loc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
type = getContext().getGlobalType (name2);
|
|
||||||
|
|
||||||
if (type!=' ')
|
|
||||||
{
|
|
||||||
scanner.putbackName (name, loc);
|
|
||||||
parseExpression (scanner, loc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==BeginState && getContext().isId (name))
|
if (mState==BeginState && getContext().isId (name))
|
||||||
{
|
{
|
||||||
mState = PotentialExplicitState;
|
mState = PotentialExplicitState;
|
||||||
mExplicit = toLower (name);
|
mExplicit = toLower (name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mState==BeginState && mAllowExpression)
|
||||||
|
{
|
||||||
|
std::string name2 = toLower (name);
|
||||||
|
|
||||||
|
char type = mLocals.getType (name2);
|
||||||
|
|
||||||
|
if (type!=' ')
|
||||||
|
{
|
||||||
|
scanner.putbackName (name, loc);
|
||||||
|
parseExpression (scanner, loc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = getContext().getGlobalType (name2);
|
||||||
|
|
||||||
|
if (type!=' ')
|
||||||
|
{
|
||||||
|
scanner.putbackName (name, loc);
|
||||||
|
parseExpression (scanner, loc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Parser::parseName (name, loc, scanner);
|
return Parser::parseName (name, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,60 +221,60 @@ namespace Compiler
|
||||||
if (mState==BeginState || mState==ExplicitState)
|
if (mState==BeginState || mState==ExplicitState)
|
||||||
{
|
{
|
||||||
switch (keyword)
|
switch (keyword)
|
||||||
{
|
{
|
||||||
case Scanner::K_enable:
|
case Scanner::K_enable:
|
||||||
|
|
||||||
Generator::enable (mCode, mLiterals, mExplicit);
|
Generator::enable (mCode, mLiterals, mExplicit);
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Scanner::K_disable:
|
case Scanner::K_disable:
|
||||||
|
|
||||||
Generator::disable (mCode, mLiterals, mExplicit);
|
Generator::disable (mCode, mLiterals, mExplicit);
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for custom extensions
|
// check for custom extensions
|
||||||
if (const Extensions *extensions = getContext().getExtensions())
|
if (const Extensions *extensions = getContext().getExtensions())
|
||||||
{
|
{
|
||||||
std::string argumentType;
|
std::string argumentType;
|
||||||
|
|
||||||
if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState))
|
if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState))
|
||||||
{
|
{
|
||||||
mExprParser.parseArguments (argumentType, scanner, mCode, true);
|
int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true);
|
||||||
|
|
||||||
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit);
|
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAllowExpression)
|
if (mAllowExpression)
|
||||||
{
|
{
|
||||||
if (keyword==Scanner::K_getdisabled || keyword==Scanner::K_getdistance)
|
if (keyword==Scanner::K_getdisabled || keyword==Scanner::K_getdistance)
|
||||||
{
|
{
|
||||||
scanner.putbackKeyword (keyword, loc);
|
scanner.putbackKeyword (keyword, loc);
|
||||||
parseExpression (scanner, loc);
|
parseExpression (scanner, loc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const Extensions *extensions = getContext().getExtensions())
|
if (const Extensions *extensions = getContext().getExtensions())
|
||||||
{
|
{
|
||||||
char returnType;
|
char returnType;
|
||||||
std::string argumentType;
|
std::string argumentType;
|
||||||
|
|
||||||
if (extensions->isFunction (keyword, returnType, argumentType,
|
if (extensions->isFunction (keyword, returnType, argumentType,
|
||||||
!mExplicit.empty()))
|
!mExplicit.empty()))
|
||||||
{
|
{
|
||||||
scanner.putbackKeyword (keyword, loc);
|
scanner.putbackKeyword (keyword, loc);
|
||||||
parseExpression (scanner, loc);
|
parseExpression (scanner, loc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mState==BeginState)
|
if (mState==BeginState)
|
||||||
{
|
{
|
||||||
switch (keyword)
|
switch (keyword)
|
||||||
|
@ -278,39 +284,39 @@ namespace Compiler
|
||||||
case Scanner::K_float: mState = FloatState; return true;
|
case Scanner::K_float: mState = FloatState; return true;
|
||||||
case Scanner::K_set: mState = SetState; return true;
|
case Scanner::K_set: mState = SetState; return true;
|
||||||
case Scanner::K_messagebox: mState = MessageState; return true;
|
case Scanner::K_messagebox: mState = MessageState; return true;
|
||||||
|
|
||||||
case Scanner::K_return:
|
case Scanner::K_return:
|
||||||
|
|
||||||
Generator::exit (mCode);
|
Generator::exit (mCode);
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Scanner::K_startscript:
|
case Scanner::K_startscript:
|
||||||
|
|
||||||
mExprParser.parseArguments ("c", scanner, mCode, true);
|
mExprParser.parseArguments ("c", scanner, mCode, true);
|
||||||
Generator::startScript (mCode);
|
Generator::startScript (mCode);
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Scanner::K_stopscript:
|
case Scanner::K_stopscript:
|
||||||
|
|
||||||
mExprParser.parseArguments ("c", scanner, mCode, true);
|
mExprParser.parseArguments ("c", scanner, mCode, true);
|
||||||
Generator::stopScript (mCode);
|
Generator::stopScript (mCode);
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mState==SetLocalVarState && keyword==Scanner::K_to)
|
else if (mState==SetLocalVarState && keyword==Scanner::K_to)
|
||||||
{
|
{
|
||||||
mExprParser.reset();
|
mExprParser.reset();
|
||||||
scanner.scan (mExprParser);
|
scanner.scan (mExprParser);
|
||||||
|
|
||||||
std::vector<Interpreter::Type_Code> code;
|
std::vector<Interpreter::Type_Code> code;
|
||||||
char type = mExprParser.append (code);
|
char type = mExprParser.append (code);
|
||||||
|
|
||||||
Generator::assignToLocal (mCode, mLocals.getType (mName),
|
Generator::assignToLocal (mCode, mLocals.getType (mName),
|
||||||
mLocals.getIndex (mName), code, type);
|
mLocals.getIndex (mName), code, type);
|
||||||
|
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -318,16 +324,16 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
mExprParser.reset();
|
mExprParser.reset();
|
||||||
scanner.scan (mExprParser);
|
scanner.scan (mExprParser);
|
||||||
|
|
||||||
std::vector<Interpreter::Type_Code> code;
|
std::vector<Interpreter::Type_Code> code;
|
||||||
char type = mExprParser.append (code);
|
char type = mExprParser.append (code);
|
||||||
|
|
||||||
Generator::assignToGlobal (mCode, mLiterals, mType, mName, code, type);
|
Generator::assignToGlobal (mCode, mLiterals, mType, mName, code, type);
|
||||||
|
|
||||||
mState = EndState;
|
mState = EndState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAllowExpression)
|
if (mAllowExpression)
|
||||||
{
|
{
|
||||||
if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode ||
|
if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode ||
|
||||||
|
@ -336,10 +342,10 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
scanner.putbackKeyword (keyword, loc);
|
scanner.putbackKeyword (keyword, loc);
|
||||||
parseExpression (scanner, loc);
|
parseExpression (scanner, loc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseKeyword (keyword, loc, scanner);
|
return Parser::parseKeyword (keyword, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,30 +353,42 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
if (code==Scanner::S_newline && (mState==EndState || mState==BeginState))
|
if (code==Scanner::S_newline && (mState==EndState || mState==BeginState))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (code==Scanner::S_comma && mState==MessageState)
|
if (code==Scanner::S_comma && mState==MessageState)
|
||||||
{
|
{
|
||||||
mState = MessageCommaState;
|
mState = MessageCommaState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code==Scanner::S_ref && mState==PotentialExplicitState)
|
if (code==Scanner::S_ref && mState==PotentialExplicitState)
|
||||||
{
|
{
|
||||||
mState = ExplicitState;
|
mState = ExplicitState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (code==Scanner::S_newline && mState==MessageButtonState)
|
||||||
|
{
|
||||||
|
Generator::message (mCode, mLiterals, mName, mButtons);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code==Scanner::S_comma && mState==MessageButtonState)
|
||||||
|
{
|
||||||
|
mState = MessageButtonCommaState;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mAllowExpression && mState==BeginState &&
|
if (mAllowExpression && mState==BeginState &&
|
||||||
(code==Scanner::S_open || code==Scanner::S_minus))
|
(code==Scanner::S_open || code==Scanner::S_minus))
|
||||||
{
|
{
|
||||||
scanner.putbackSpecial (code, loc);
|
scanner.putbackSpecial (code, loc);
|
||||||
parseExpression (scanner, loc);
|
parseExpression (scanner, loc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseSpecial (code, loc, scanner);
|
return Parser::parseSpecial (code, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineParser::reset()
|
void LineParser::reset()
|
||||||
{
|
{
|
||||||
mState = BeginState;
|
mState = BeginState;
|
||||||
|
@ -378,4 +396,3 @@ namespace Compiler
|
||||||
mExplicit.clear();
|
mExplicit.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
class Locals;
|
class Locals;
|
||||||
class Literals;
|
class Literals;
|
||||||
|
|
||||||
/// \brief Line parser, to be used in console scripts and as part of ScriptParser
|
/// \brief Line parser, to be used in console scripts and as part of ScriptParser
|
||||||
|
|
||||||
class LineParser : public Parser
|
class LineParser : public Parser
|
||||||
{
|
{
|
||||||
enum State
|
enum State
|
||||||
|
@ -22,31 +22,32 @@ namespace Compiler
|
||||||
BeginState,
|
BeginState,
|
||||||
ShortState, LongState, FloatState,
|
ShortState, LongState, FloatState,
|
||||||
SetState, SetLocalVarState, SetGlobalVarState,
|
SetState, SetLocalVarState, SetGlobalVarState,
|
||||||
MessageState, MessageCommaState,
|
MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,
|
||||||
EndState,
|
EndState,
|
||||||
PotentialExplicitState, ExplicitState
|
PotentialExplicitState, ExplicitState
|
||||||
};
|
};
|
||||||
|
|
||||||
Locals& mLocals;
|
Locals& mLocals;
|
||||||
Literals& mLiterals;
|
Literals& mLiterals;
|
||||||
std::vector<Interpreter::Type_Code>& mCode;
|
std::vector<Interpreter::Type_Code>& mCode;
|
||||||
State mState;
|
State mState;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
int mButtons;
|
||||||
std::string mExplicit;
|
std::string mExplicit;
|
||||||
char mType;
|
char mType;
|
||||||
ExprParser mExprParser;
|
ExprParser mExprParser;
|
||||||
bool mAllowExpression;
|
bool mAllowExpression;
|
||||||
|
|
||||||
void parseExpression (Scanner& scanner, const TokenLoc& loc);
|
void parseExpression (Scanner& scanner, const TokenLoc& loc);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||||
Literals& literals, std::vector<Interpreter::Type_Code>& code,
|
Literals& literals, std::vector<Interpreter::Type_Code>& code,
|
||||||
bool allowExpression = false);
|
bool allowExpression = false);
|
||||||
///< \param allowExpression Allow lines consisting of a naked expression
|
///< \param allowExpression Allow lines consisting of a naked expression
|
||||||
/// (result is send to the messagebox interface)
|
/// (result is send to the messagebox interface)
|
||||||
|
|
||||||
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
||||||
///< Handle an int token.
|
///< Handle an int token.
|
||||||
/// \return fetch another token?
|
/// \return fetch another token?
|
||||||
|
@ -67,9 +68,9 @@ namespace Compiler
|
||||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||||
///< Handle a special character token.
|
///< Handle a special character token.
|
||||||
/// \return fetch another token?
|
/// \return fetch another token?
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
///< Reset parser to clean state.
|
///< Reset parser to clean state.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,15 +57,15 @@ namespace Compiler
|
||||||
std::string Parser::toLower (const std::string& name)
|
std::string Parser::toLower (const std::string& name)
|
||||||
{
|
{
|
||||||
std::string lowerCase;
|
std::string lowerCase;
|
||||||
|
|
||||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||||
(int(*)(int)) std::tolower);
|
(int(*)(int)) std::tolower);
|
||||||
|
|
||||||
return lowerCase;
|
return lowerCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::Parser (ErrorHandler& errorHandler, Context& context)
|
Parser::Parser (ErrorHandler& errorHandler, Context& context)
|
||||||
: mErrorHandler (errorHandler), mContext (context)
|
: mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
|
@ -79,7 +79,9 @@ namespace Compiler
|
||||||
|
|
||||||
bool Parser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
bool Parser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
reportSeriousError ("Unexpected numeric value", loc);
|
if (!(mOptional && mEmpty))
|
||||||
|
reportSeriousError ("Unexpected numeric value", loc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +92,9 @@ namespace Compiler
|
||||||
|
|
||||||
bool Parser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
|
bool Parser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
reportSeriousError ("Unexpected floating point value", loc);
|
if (!(mOptional && mEmpty))
|
||||||
|
reportSeriousError ("Unexpected floating point value", loc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +106,9 @@ namespace Compiler
|
||||||
bool Parser::parseName (const std::string& name, const TokenLoc& loc,
|
bool Parser::parseName (const std::string& name, const TokenLoc& loc,
|
||||||
Scanner& scanner)
|
Scanner& scanner)
|
||||||
{
|
{
|
||||||
reportSeriousError ("Unexpected name", loc);
|
if (!(mOptional && mEmpty))
|
||||||
|
reportSeriousError ("Unexpected name", loc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +119,9 @@ namespace Compiler
|
||||||
|
|
||||||
bool Parser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
bool Parser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
reportSeriousError ("Unexpected keyword", loc);
|
if (!(mOptional && mEmpty))
|
||||||
|
reportSeriousError ("Unexpected keyword", loc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +132,9 @@ namespace Compiler
|
||||||
|
|
||||||
bool Parser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
bool Parser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||||
{
|
{
|
||||||
reportSeriousError ("Unexpected special token", loc);
|
if (!(mOptional && mEmpty))
|
||||||
|
reportSeriousError ("Unexpected special token", loc);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,5 +146,25 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
reportEOF();
|
reportEOF();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
void Parser::reset()
|
||||||
|
{
|
||||||
|
mOptional = false;
|
||||||
|
mEmpty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::setOptional (bool optional)
|
||||||
|
{
|
||||||
|
mOptional = optional;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::start()
|
||||||
|
{
|
||||||
|
mEmpty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Parser::isEmpty() const
|
||||||
|
{
|
||||||
|
return mEmpty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
ErrorHandler& mErrorHandler;
|
ErrorHandler& mErrorHandler;
|
||||||
Context& mContext;
|
Context& mContext;
|
||||||
|
bool mOptional;
|
||||||
|
bool mEmpty;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -47,7 +49,7 @@ namespace Compiler
|
||||||
///< constructor
|
///< constructor
|
||||||
|
|
||||||
virtual ~Parser();
|
virtual ~Parser();
|
||||||
///< destructor
|
///< destructor
|
||||||
|
|
||||||
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
||||||
///< Handle an int token.
|
///< Handle an int token.
|
||||||
|
@ -84,6 +86,19 @@ namespace Compiler
|
||||||
///< Handle EOF token.
|
///< Handle EOF token.
|
||||||
///
|
///
|
||||||
/// - Default-implementation: Report an error.
|
/// - Default-implementation: Report an error.
|
||||||
|
|
||||||
|
virtual void reset();
|
||||||
|
///< Reset parser to clean state.
|
||||||
|
|
||||||
|
void setOptional (bool optional);
|
||||||
|
///< Optional mode: If nothign has been parsed yet and an unexpected token is delivered, stop
|
||||||
|
/// parsing without raising an exception (after a reset the parser is in non-optional mode).
|
||||||
|
|
||||||
|
void start();
|
||||||
|
///< Mark parser as non-empty (at least one token has been parser).
|
||||||
|
|
||||||
|
bool isEmpty() const;
|
||||||
|
///< Has anything been parsed?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Compiler
|
||||||
StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals)
|
StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals)
|
||||||
: Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false)
|
: Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringParser::parseName (const std::string& name, const TokenLoc& loc,
|
bool StringParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||||
|
@ -20,14 +20,15 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
if (mState==StartState || mState==CommaState)
|
if (mState==StartState || mState==CommaState)
|
||||||
{
|
{
|
||||||
|
start();
|
||||||
if (mSmashCase)
|
if (mSmashCase)
|
||||||
Generator::pushString (mCode, mLiterals, toLower (name));
|
Generator::pushString (mCode, mLiterals, toLower (name));
|
||||||
else
|
else
|
||||||
Generator::pushString (mCode, mLiterals, name);
|
Generator::pushString (mCode, mLiterals, name);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseName (name, loc, scanner);
|
return Parser::parseName (name, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +39,10 @@ namespace Compiler
|
||||||
mState = CommaState;
|
mState = CommaState;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parser::parseSpecial (code, loc, scanner);
|
return Parser::parseSpecial (code, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringParser::append (std::vector<Interpreter::Type_Code>& code)
|
void StringParser::append (std::vector<Interpreter::Type_Code>& code)
|
||||||
{
|
{
|
||||||
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
||||||
|
@ -52,11 +53,11 @@ namespace Compiler
|
||||||
mState = StartState;
|
mState = StartState;
|
||||||
mCode.clear();
|
mCode.clear();
|
||||||
mSmashCase = false;
|
mSmashCase = false;
|
||||||
|
Parser::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringParser::smashCase()
|
void StringParser::smashCase()
|
||||||
{
|
{
|
||||||
mSmashCase = true;
|
mSmashCase = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,28 +3,18 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <libs/platform/stdint.h>
|
#include <libs/platform/stdint.h>
|
||||||
|
#include <libs/platform/string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string.h>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <libs/mangle/stream/stream.hpp>
|
#include <libs/mangle/stream/stream.hpp>
|
||||||
#include <libs/mangle/stream/servers/file_stream.hpp>
|
#include <libs/mangle/stream/servers/file_stream.hpp>
|
||||||
#include <libs/mangle/tools/str_exception.hpp>
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
// need our own implementation of strnlen
|
|
||||||
static size_t strnlen(const char *s, size_t n)
|
|
||||||
{
|
|
||||||
const char *p = (const char *)memchr(s, 0, n);
|
|
||||||
return(p ? p-s : n);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ESM {
|
namespace ESM {
|
||||||
|
|
||||||
enum Version
|
enum Version
|
||||||
|
@ -626,7 +616,7 @@ public:
|
||||||
ss << "\n Subrecord: " << c.subName.toString();
|
ss << "\n Subrecord: " << c.subName.toString();
|
||||||
if(esm != NULL)
|
if(esm != NULL)
|
||||||
ss << "\n Offset: 0x" << hex << esm->tell();
|
ss << "\n Offset: 0x" << hex << esm->tell();
|
||||||
throw str_exception(ss.str());
|
throw std::runtime_error(ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -45,4 +45,113 @@ namespace ESM
|
||||||
|
|
||||||
esm.skipRecord();
|
esm.skipRecord();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DialInfo::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
id = esm.getHNString("INAM");
|
||||||
|
prev = esm.getHNString("PNAM");
|
||||||
|
next = esm.getHNString("NNAM");
|
||||||
|
|
||||||
|
// Not present if deleted
|
||||||
|
if(esm.isNextSub("DATA"))
|
||||||
|
esm.getHT(data, 12);
|
||||||
|
|
||||||
|
// What follows is somewhat spaghetti-ish, but it's worth if for
|
||||||
|
// an extra speedup. INFO is by far the most common record type.
|
||||||
|
|
||||||
|
// subName is a reference to the original, so it changes whenever
|
||||||
|
// a new sub name is read. esm.isEmptyOrGetName() will get the
|
||||||
|
// next name for us, or return true if there are no more records.
|
||||||
|
esm.getSubName();
|
||||||
|
const NAME &subName = esm.retSubName();
|
||||||
|
|
||||||
|
if(subName.val == REC_ONAM)
|
||||||
|
{
|
||||||
|
actor = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
if(subName.val == REC_RNAM)
|
||||||
|
{
|
||||||
|
race = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
if(subName.val == REC_CNAM)
|
||||||
|
{
|
||||||
|
clas = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
factionLess = false;
|
||||||
|
if(subName.val == REC_FNAM)
|
||||||
|
{
|
||||||
|
npcFaction = esm.getHString();
|
||||||
|
if(npcFaction == "FFFF") factionLess = true;
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
if(subName.val == REC_ANAM)
|
||||||
|
{
|
||||||
|
cell = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
if(subName.val == REC_DNAM)
|
||||||
|
{
|
||||||
|
pcFaction = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
if(subName.val == REC_SNAM)
|
||||||
|
{
|
||||||
|
sound = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
if(subName.val == REC_NAME)
|
||||||
|
{
|
||||||
|
response = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(subName.val == REC_SCVR)
|
||||||
|
{
|
||||||
|
SelectStruct ss;
|
||||||
|
|
||||||
|
ss.selectRule = esm.getHString();
|
||||||
|
esm.isEmptyOrGetName();
|
||||||
|
|
||||||
|
if(subName.val == REC_INTV)
|
||||||
|
{
|
||||||
|
ss.type = VT_Int;
|
||||||
|
esm.getHT(ss.i);
|
||||||
|
}
|
||||||
|
else if(subName.val == REC_FLTV)
|
||||||
|
{
|
||||||
|
ss.type = VT_Float;
|
||||||
|
esm.getHT(ss.f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esm.fail("INFO.SCVR must precede INTV or FLTV, not "
|
||||||
|
+ subName.toString());
|
||||||
|
|
||||||
|
selects.push_back(ss);
|
||||||
|
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(subName.val == REC_BNAM)
|
||||||
|
{
|
||||||
|
resultScript = esm.getHString();
|
||||||
|
if(esm.isEmptyOrGetName()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
questStatus = QS_None;
|
||||||
|
|
||||||
|
if (subName.val == REC_QSTN) questStatus = QS_Name;
|
||||||
|
else if(subName.val == REC_QSTF) questStatus = QS_Finished;
|
||||||
|
else if(subName.val == REC_QSTR) questStatus = QS_Restart;
|
||||||
|
else if(subName.val == REC_DELE) questStatus = QS_Deleted;
|
||||||
|
else
|
||||||
|
esm.fail("Don't know what to do with " + subName.toString() + " in INFO " + id);
|
||||||
|
|
||||||
|
if(questStatus != QS_None)
|
||||||
|
// Skip rest of record
|
||||||
|
esm.skipRecord();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,114 +96,7 @@ struct DialInfo
|
||||||
REC_DELE = 0x454c4544
|
REC_DELE = 0x454c4544
|
||||||
};
|
};
|
||||||
|
|
||||||
void load(ESMReader &esm)
|
void load(ESMReader &esm);
|
||||||
{
|
|
||||||
id = esm.getHNString("INAM");
|
|
||||||
prev = esm.getHNString("PNAM");
|
|
||||||
next = esm.getHNString("NNAM");
|
|
||||||
|
|
||||||
// Not present if deleted
|
|
||||||
if(esm.isNextSub("DATA"))
|
|
||||||
esm.getHT(data, 12);
|
|
||||||
|
|
||||||
// What follows is somewhat spaghetti-ish, but it's worth if for
|
|
||||||
// an extra speedup. INFO is by far the most common record type.
|
|
||||||
|
|
||||||
// subName is a reference to the original, so it changes whenever
|
|
||||||
// a new sub name is read. esm.isEmptyOrGetName() will get the
|
|
||||||
// next name for us, or return true if there are no more records.
|
|
||||||
esm.getSubName();
|
|
||||||
const NAME &subName = esm.retSubName();
|
|
||||||
|
|
||||||
if(subName.val == REC_ONAM)
|
|
||||||
{
|
|
||||||
actor = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_RNAM)
|
|
||||||
{
|
|
||||||
race = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_CNAM)
|
|
||||||
{
|
|
||||||
clas = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
factionLess = false;
|
|
||||||
if(subName.val == REC_FNAM)
|
|
||||||
{
|
|
||||||
npcFaction = esm.getHString();
|
|
||||||
if(npcFaction == "FFFF") factionLess = true;
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_ANAM)
|
|
||||||
{
|
|
||||||
cell = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_DNAM)
|
|
||||||
{
|
|
||||||
pcFaction = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_SNAM)
|
|
||||||
{
|
|
||||||
sound = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
if(subName.val == REC_NAME)
|
|
||||||
{
|
|
||||||
response = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(subName.val == REC_SCVR)
|
|
||||||
{
|
|
||||||
SelectStruct ss;
|
|
||||||
|
|
||||||
ss.selectRule = esm.getHString();
|
|
||||||
esm.isEmptyOrGetName();
|
|
||||||
|
|
||||||
if(subName.val == REC_INTV)
|
|
||||||
{
|
|
||||||
ss.type = VT_Int;
|
|
||||||
esm.getHT(ss.i);
|
|
||||||
}
|
|
||||||
else if(subName.val == REC_FLTV)
|
|
||||||
{
|
|
||||||
ss.type = VT_Float;
|
|
||||||
esm.getHT(ss.f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
esm.fail("INFO.SCVR must precede INTV or FLTV, not "
|
|
||||||
+ subName.toString());
|
|
||||||
|
|
||||||
selects.push_back(ss);
|
|
||||||
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(subName.val == REC_BNAM)
|
|
||||||
{
|
|
||||||
resultScript = esm.getHString();
|
|
||||||
if(esm.isEmptyOrGetName()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
questStatus = QS_None;
|
|
||||||
int skip = 1;
|
|
||||||
|
|
||||||
if (subName.val == REC_QSTN) questStatus = QS_Name;
|
|
||||||
else if(subName.val == REC_QSTF) questStatus = QS_Finished;
|
|
||||||
else if(subName.val == REC_QSTR) questStatus = QS_Restart;
|
|
||||||
else if(subName.val == REC_DELE) {questStatus = QS_Deleted; skip = 4;}
|
|
||||||
else
|
|
||||||
esm.fail("Don't know what to do with " + subName.toString() + " in INFO " + id);
|
|
||||||
|
|
||||||
if(questStatus != QS_None)
|
|
||||||
esm.skip(skip);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -13,11 +13,10 @@
|
||||||
#include "store.hpp"
|
#include "store.hpp"
|
||||||
#include "components/esm/records.hpp"
|
#include "components/esm/records.hpp"
|
||||||
#include "components/esm/loadcell.hpp"
|
#include "components/esm/loadcell.hpp"
|
||||||
#include <libs/mangle/tools/str_exception.hpp>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "libs/mangle/tools/str_exception.hpp"
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace ESMS
|
namespace ESMS
|
||||||
{
|
{
|
||||||
|
@ -55,7 +54,7 @@ namespace ESMS
|
||||||
{
|
{
|
||||||
const X* obj = recList.find(ref.refID);
|
const X* obj = recList.find(ref.refID);
|
||||||
if(obj == NULL)
|
if(obj == NULL)
|
||||||
throw str_exception("Error resolving cell reference " + ref.refID);
|
throw std::runtime_error("Error resolving cell reference " + ref.refID);
|
||||||
|
|
||||||
LiveRef lr;
|
LiveRef lr;
|
||||||
lr.ref = ref;
|
lr.ref = ref;
|
||||||
|
@ -116,7 +115,7 @@ namespace ESMS
|
||||||
cell = store.cells.findInt(name);
|
cell = store.cells.findInt(name);
|
||||||
|
|
||||||
if(cell == NULL)
|
if(cell == NULL)
|
||||||
throw str_exception("Cell not found - " + name);
|
throw std::runtime_error("Cell not found - " + name);
|
||||||
|
|
||||||
loadRefs(store, esm);
|
loadRefs(store, esm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ Code bit-patterns:
|
||||||
00ccccccAAAAAAAAAAAAAAAAAAAAAAAA segment 0: 64 opcodes, 1 24-bit argument
|
00ccccccAAAAAAAAAAAAAAAAAAAAAAAA segment 0: 64 opcodes, 1 24-bit argument
|
||||||
01ccccccAAAAAAAAAAAABBBBBBBBBBBB segment 1: 64 opcodes, 2 12-bit arguments
|
01ccccccAAAAAAAAAAAABBBBBBBBBBBB segment 1: 64 opcodes, 2 12-bit arguments
|
||||||
10ccccccccccAAAAAAAAAAAAAAAAAAAA segment 2: 1024 opcodes, 1 20-bit argument
|
10ccccccccccAAAAAAAAAAAAAAAAAAAA segment 2: 1024 opcodes, 1 20-bit argument
|
||||||
110000ccccccccccAAAAAAAAAAAAAAAA segment 3: 1024 opcodes, 1 16-bit argument
|
110000ccccccccccccccccccAAAAAAAA segment 3: 262144 opcodes, 1 8-bit argument
|
||||||
110001ccccccccccAAAAAAAABBBBBBBB segment 4: 1024 opcodes, 2 8-bit arguments
|
110001ccccccccccAAAAAAAABBBBBBBB segment 4: 1024 opcodes, 2 8-bit arguments
|
||||||
110010cccccccccccccccccccccccccc segment 5: 67108864 opcodes, no arguments
|
110010cccccccccccccccccccccccccc segment 5: 67108864 opcodes, no arguments
|
||||||
other bit-patterns reserved
|
other bit-patterns reserved
|
||||||
|
@ -31,8 +31,8 @@ B: argument 1
|
||||||
|
|
||||||
Segment 0:
|
Segment 0:
|
||||||
op 0: push arg0
|
op 0: push arg0
|
||||||
op 1: move pv ahead by arg0
|
op 1: move pc ahead by arg0
|
||||||
op 2: move pv back by arg0
|
op 2: move pc back by arg0
|
||||||
opcodes 3-31 unused
|
opcodes 3-31 unused
|
||||||
opcodes 32-63 reserved for extensions
|
opcodes 32-63 reserved for extensions
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@ op 0: show message box with message string literal index in stack[0];
|
||||||
additional arguments (if any) in stack[arg0+n]..stack[arg0+1];
|
additional arguments (if any) in stack[arg0+n]..stack[arg0+1];
|
||||||
n is determined according to the message string
|
n is determined according to the message string
|
||||||
all arguments are removed from stack
|
all arguments are removed from stack
|
||||||
opcodes 1-511 unused
|
opcodes 1-131071 unused
|
||||||
opcodes 512-1023 reserved for extensions
|
opcodes 131072-262143 reserved for extensions
|
||||||
|
|
||||||
Segment 4:
|
Segment 4:
|
||||||
opcodes 0-511 unused
|
opcodes 0-511 unused
|
||||||
|
@ -119,4 +119,3 @@ op 57: explicit reference = stack[0]; pop;
|
||||||
replace stack[0] with distance between explicit reference and a reference of ID stack[0]
|
replace stack[0] with distance between explicit reference and a reference of ID stack[0]
|
||||||
opcodes 58-33554431 unused
|
opcodes 58-33554431 unused
|
||||||
opcodes 33554432-67108863 reserved for extensions
|
opcodes 33554432-67108863 reserved for extensions
|
||||||
|
|
||||||
|
|
|
@ -13,131 +13,131 @@ namespace Interpreter
|
||||||
void Interpreter::execute (Type_Code code)
|
void Interpreter::execute (Type_Code code)
|
||||||
{
|
{
|
||||||
unsigned int segSpec = code>>30;
|
unsigned int segSpec = code>>30;
|
||||||
|
|
||||||
switch (segSpec)
|
switch (segSpec)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
int opcode = code>>24;
|
int opcode = code>>24;
|
||||||
unsigned int arg0 = code & 0xffffff;
|
unsigned int arg0 = code & 0xffffff;
|
||||||
|
|
||||||
std::map<int, Opcode1 *>::iterator iter = mSegment0.find (opcode);
|
std::map<int, Opcode1 *>::iterator iter = mSegment0.find (opcode);
|
||||||
|
|
||||||
if (iter==mSegment0.end())
|
if (iter==mSegment0.end())
|
||||||
abortUnknownCode (0, opcode);
|
abortUnknownCode (0, opcode);
|
||||||
|
|
||||||
iter->second->execute (mRuntime, arg0);
|
iter->second->execute (mRuntime, arg0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
int opcode = (code>>24) & 0x3f;
|
int opcode = (code>>24) & 0x3f;
|
||||||
unsigned int arg0 = (code>>16) & 0xfff;
|
unsigned int arg0 = (code>>16) & 0xfff;
|
||||||
unsigned int arg1 = code & 0xfff;
|
unsigned int arg1 = code & 0xfff;
|
||||||
|
|
||||||
std::map<int, Opcode2 *>::iterator iter = mSegment1.find (opcode);
|
std::map<int, Opcode2 *>::iterator iter = mSegment1.find (opcode);
|
||||||
|
|
||||||
if (iter==mSegment1.end())
|
if (iter==mSegment1.end())
|
||||||
abortUnknownCode (1, opcode);
|
abortUnknownCode (1, opcode);
|
||||||
|
|
||||||
iter->second->execute (mRuntime, arg0, arg1);
|
iter->second->execute (mRuntime, arg0, arg1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
int opcode = (code>>20) & 0x3ff;
|
int opcode = (code>>20) & 0x3ff;
|
||||||
unsigned int arg0 = code & 0xfffff;
|
unsigned int arg0 = code & 0xfffff;
|
||||||
|
|
||||||
std::map<int, Opcode1 *>::iterator iter = mSegment2.find (opcode);
|
std::map<int, Opcode1 *>::iterator iter = mSegment2.find (opcode);
|
||||||
|
|
||||||
if (iter==mSegment2.end())
|
if (iter==mSegment2.end())
|
||||||
abortUnknownCode (2, opcode);
|
abortUnknownCode (2, opcode);
|
||||||
|
|
||||||
iter->second->execute (mRuntime, arg0);
|
iter->second->execute (mRuntime, arg0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
segSpec = code>>26;
|
segSpec = code>>26;
|
||||||
|
|
||||||
switch (segSpec)
|
switch (segSpec)
|
||||||
{
|
{
|
||||||
case 0x30:
|
case 0x30:
|
||||||
{
|
{
|
||||||
int opcode = (code>>16) & 0x3ff;
|
int opcode = (code>>8) & 0x3ffff;
|
||||||
unsigned int arg0 = code & 0xffff;
|
unsigned int arg0 = code & 0xff;
|
||||||
|
|
||||||
std::map<int, Opcode1 *>::iterator iter = mSegment3.find (opcode);
|
std::map<int, Opcode1 *>::iterator iter = mSegment3.find (opcode);
|
||||||
|
|
||||||
if (iter==mSegment3.end())
|
if (iter==mSegment3.end())
|
||||||
abortUnknownCode (3, opcode);
|
abortUnknownCode (3, opcode);
|
||||||
|
|
||||||
iter->second->execute (mRuntime, arg0);
|
iter->second->execute (mRuntime, arg0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x31:
|
case 0x31:
|
||||||
{
|
{
|
||||||
int opcode = (code>>16) & 0x3ff;
|
int opcode = (code>>16) & 0x3ff;
|
||||||
unsigned int arg0 = (code>>8) & 0xff;
|
unsigned int arg0 = (code>>8) & 0xff;
|
||||||
unsigned int arg1 = code & 0xff;
|
unsigned int arg1 = code & 0xff;
|
||||||
|
|
||||||
std::map<int, Opcode2 *>::iterator iter = mSegment4.find (opcode);
|
std::map<int, Opcode2 *>::iterator iter = mSegment4.find (opcode);
|
||||||
|
|
||||||
if (iter==mSegment4.end())
|
if (iter==mSegment4.end())
|
||||||
abortUnknownCode (4, opcode);
|
abortUnknownCode (4, opcode);
|
||||||
|
|
||||||
iter->second->execute (mRuntime, arg0, arg1);
|
iter->second->execute (mRuntime, arg0, arg1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x32:
|
case 0x32:
|
||||||
{
|
{
|
||||||
int opcode = code & 0x3ffffff;
|
int opcode = code & 0x3ffffff;
|
||||||
|
|
||||||
std::map<int, Opcode0 *>::iterator iter = mSegment5.find (opcode);
|
std::map<int, Opcode0 *>::iterator iter = mSegment5.find (opcode);
|
||||||
|
|
||||||
if (iter==mSegment5.end())
|
if (iter==mSegment5.end())
|
||||||
abortUnknownCode (5, opcode);
|
abortUnknownCode (5, opcode);
|
||||||
|
|
||||||
iter->second->execute (mRuntime);
|
iter->second->execute (mRuntime);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abortUnknownSegment (code);
|
abortUnknownSegment (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::abortUnknownCode (int segment, int opcode)
|
void Interpreter::abortUnknownCode (int segment, int opcode)
|
||||||
{
|
{
|
||||||
std::ostringstream error;
|
std::ostringstream error;
|
||||||
|
|
||||||
error << "unknown opcode " << opcode << " in segment " << segment;
|
error << "unknown opcode " << opcode << " in segment " << segment;
|
||||||
|
|
||||||
throw std::runtime_error (error.str());
|
throw std::runtime_error (error.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::abortUnknownSegment (Type_Code code)
|
void Interpreter::abortUnknownSegment (Type_Code code)
|
||||||
{
|
{
|
||||||
std::ostringstream error;
|
std::ostringstream error;
|
||||||
|
|
||||||
error << "opcode outside of the allocated segment range: " << code;
|
error << "opcode outside of the allocated segment range: " << code;
|
||||||
|
|
||||||
throw std::runtime_error (error.str());
|
throw std::runtime_error (error.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter::Interpreter (Context& context)
|
Interpreter::Interpreter (Context& context)
|
||||||
: mRuntime (context)
|
: mRuntime (context)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Interpreter::~Interpreter()
|
Interpreter::~Interpreter()
|
||||||
{
|
{
|
||||||
for (std::map<int, Opcode1 *>::iterator iter (mSegment0.begin());
|
for (std::map<int, Opcode1 *>::iterator iter (mSegment0.begin());
|
||||||
|
@ -159,12 +159,12 @@ namespace Interpreter
|
||||||
for (std::map<int, Opcode2 *>::iterator iter (mSegment4.begin());
|
for (std::map<int, Opcode2 *>::iterator iter (mSegment4.begin());
|
||||||
iter!=mSegment4.end(); ++iter)
|
iter!=mSegment4.end(); ++iter)
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
|
|
||||||
for (std::map<int, Opcode0 *>::iterator iter (mSegment5.begin());
|
for (std::map<int, Opcode0 *>::iterator iter (mSegment5.begin());
|
||||||
iter!=mSegment5.end(); ++iter)
|
iter!=mSegment5.end(); ++iter)
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::installSegment0 (int code, Opcode1 *opcode)
|
void Interpreter::installSegment0 (int code, Opcode1 *opcode)
|
||||||
{
|
{
|
||||||
mSegment0.insert (std::make_pair (code, opcode));
|
mSegment0.insert (std::make_pair (code, opcode));
|
||||||
|
@ -194,24 +194,24 @@ namespace Interpreter
|
||||||
{
|
{
|
||||||
mSegment5.insert (std::make_pair (code, opcode));
|
mSegment5.insert (std::make_pair (code, opcode));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::run (const Type_Code *code, int codeSize)
|
void Interpreter::run (const Type_Code *code, int codeSize)
|
||||||
{
|
{
|
||||||
assert (codeSize>=4);
|
assert (codeSize>=4);
|
||||||
|
|
||||||
mRuntime.configure (code, codeSize);
|
mRuntime.configure (code, codeSize);
|
||||||
|
|
||||||
int opcodes = static_cast<int> (code[0]);
|
int opcodes = static_cast<int> (code[0]);
|
||||||
|
|
||||||
const Type_Code *codeBlock = code + 4;
|
const Type_Code *codeBlock = code + 4;
|
||||||
|
|
||||||
while (mRuntime.getPC()>=0 && mRuntime.getPC()<opcodes)
|
while (mRuntime.getPC()>=0 && mRuntime.getPC()<opcodes)
|
||||||
{
|
{
|
||||||
Type_Code code = codeBlock[mRuntime.getPC()];
|
Type_Code code = codeBlock[mRuntime.getPC()];
|
||||||
mRuntime.setPC (mRuntime.getPC()+1);
|
mRuntime.setPC (mRuntime.getPC()+1);
|
||||||
execute (code);
|
execute (code);
|
||||||
}
|
}
|
||||||
|
|
||||||
mRuntime.clear();
|
mRuntime.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
#include "runtime.hpp"
|
#include "runtime.hpp"
|
||||||
|
@ -15,24 +16,33 @@ namespace Interpreter
|
||||||
class OpMessageBox : public Opcode1
|
class OpMessageBox : public Opcode1
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime, unsigned int arg0)
|
virtual void execute (Runtime& runtime, unsigned int arg0)
|
||||||
{
|
{
|
||||||
if (arg0!=0)
|
// message
|
||||||
throw std::logic_error ("message box buttons not implemented yet");
|
|
||||||
|
|
||||||
// message
|
|
||||||
int index = runtime[0].mInteger;
|
int index = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
std::string message = runtime.getStringLiteral (index);
|
std::string message = runtime.getStringLiteral (index);
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
std::vector<std::string> buttons;
|
||||||
|
|
||||||
|
for (std::size_t i=0; i<arg0; ++i)
|
||||||
|
{
|
||||||
|
int index = runtime[0].mInteger;
|
||||||
|
runtime.pop();
|
||||||
|
buttons.push_back (runtime.getStringLiteral (index));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::reverse (buttons.begin(), buttons.end());
|
||||||
|
|
||||||
// additional parameters
|
// additional parameters
|
||||||
std::string formattedMessage;
|
std::string formattedMessage;
|
||||||
|
|
||||||
for (std::size_t i=0; i<message.size(); ++i)
|
for (std::size_t i=0; i<message.size(); ++i)
|
||||||
{
|
{
|
||||||
char c = message[i];
|
char c = message[i];
|
||||||
|
|
||||||
if (c!='%')
|
if (c!='%')
|
||||||
formattedMessage += c;
|
formattedMessage += c;
|
||||||
else
|
else
|
||||||
|
@ -41,7 +51,7 @@ namespace Interpreter
|
||||||
if (i<message.size())
|
if (i<message.size())
|
||||||
{
|
{
|
||||||
c = message[i];
|
c = message[i];
|
||||||
|
|
||||||
if (c=='S' || c=='s')
|
if (c=='S' || c=='s')
|
||||||
{
|
{
|
||||||
int index = runtime[0].mInteger;
|
int index = runtime[0].mInteger;
|
||||||
|
@ -52,7 +62,7 @@ namespace Interpreter
|
||||||
{
|
{
|
||||||
Type_Integer value = runtime[0].mInteger;
|
Type_Integer value = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << value;
|
out << value;
|
||||||
formattedMessage += out.str();
|
formattedMessage += out.str();
|
||||||
|
@ -63,10 +73,10 @@ namespace Interpreter
|
||||||
{
|
{
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
float value = runtime[0].mFloat;
|
float value = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << value;
|
out << value;
|
||||||
formattedMessage += out.str();
|
formattedMessage += out.str();
|
||||||
|
@ -75,135 +85,131 @@ namespace Interpreter
|
||||||
formattedMessage += "%";
|
formattedMessage += "%";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
formattedMessage += "%";
|
formattedMessage += "%";
|
||||||
formattedMessage += c;
|
formattedMessage += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// buttons (not implemented)
|
|
||||||
std::vector<std::string> buttons;
|
|
||||||
|
|
||||||
runtime.getContext().messageBox (formattedMessage, buttons);
|
runtime.getContext().messageBox (formattedMessage, buttons);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpMenuMode : public Opcode0
|
class OpMenuMode : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
runtime.push (runtime.getContext().menuMode());
|
runtime.push (runtime.getContext().menuMode());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpRandom : public Opcode0
|
class OpRandom : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
double r = static_cast<double> (std::rand()) / RAND_MAX; // [0, 1)
|
double r = static_cast<double> (std::rand()) / RAND_MAX; // [0, 1)
|
||||||
|
|
||||||
Type_Integer limit = runtime[0].mInteger;
|
Type_Integer limit = runtime[0].mInteger;
|
||||||
|
|
||||||
if (limit<0)
|
if (limit<0)
|
||||||
throw std::runtime_error (
|
throw std::runtime_error (
|
||||||
"random: argument out of range (Don't be so negative!)");
|
"random: argument out of range (Don't be so negative!)");
|
||||||
|
|
||||||
Type_Integer value = static_cast<Type_Integer> (r*limit); // [o, limit)
|
Type_Integer value = static_cast<Type_Integer> (r*limit); // [o, limit)
|
||||||
|
|
||||||
runtime[0].mInteger = value;
|
runtime[0].mInteger = value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpGetSecondsPassed : public Opcode0
|
class OpGetSecondsPassed : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
Type_Float duration = runtime.getContext().getSecondsPassed();
|
Type_Float duration = runtime.getContext().getSecondsPassed();
|
||||||
|
|
||||||
runtime.push (duration);
|
runtime.push (duration);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpEnable : public Opcode0
|
class OpEnable : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
runtime.getContext().enable();
|
runtime.getContext().enable();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpDisable : public Opcode0
|
class OpDisable : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
runtime.getContext().disable();
|
runtime.getContext().disable();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpGetDisabled : public Opcode0
|
class OpGetDisabled : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
runtime.push (runtime.getContext().isDisabled());
|
runtime.push (runtime.getContext().isDisabled());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpEnableExplicit : public Opcode0
|
class OpEnableExplicit : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
int index = runtime[0].mInteger;
|
int index = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
std::string id = runtime.getStringLiteral (index);
|
std::string id = runtime.getStringLiteral (index);
|
||||||
|
|
||||||
runtime.getContext().enable (id);
|
runtime.getContext().enable (id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpDisableExplicit : public Opcode0
|
class OpDisableExplicit : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
int index = runtime[0].mInteger;
|
int index = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
std::string id = runtime.getStringLiteral (index);
|
std::string id = runtime.getStringLiteral (index);
|
||||||
|
|
||||||
runtime.getContext().disable (id);
|
runtime.getContext().disable (id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpGetDisabledExplicit : public Opcode0
|
class OpGetDisabledExplicit : public Opcode0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void execute (Runtime& runtime)
|
virtual void execute (Runtime& runtime)
|
||||||
{
|
{
|
||||||
int index = runtime[0].mInteger;
|
int index = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
std::string id = runtime.getStringLiteral (index);
|
std::string id = runtime.getStringLiteral (index);
|
||||||
|
|
||||||
runtime.push (runtime.getContext().isDisabled (id));
|
runtime.push (runtime.getContext().isDisabled (id));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
// A simple array implementation containing a pointer and a
|
// A simple array implementation containing a pointer and a
|
||||||
// length. Used for holding slices into a data buffer.
|
// length. Used for holding slices into a data buffer.
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct SliceArray
|
struct SliceArray
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,9 +26,9 @@
|
||||||
|
|
||||||
#include <libs/mangle/stream/stream.hpp>
|
#include <libs/mangle/stream/stream.hpp>
|
||||||
#include <libs/mangle/stream/filters/buffer_stream.hpp>
|
#include <libs/mangle/stream/filters/buffer_stream.hpp>
|
||||||
#include <libs/mangle/tools/str_exception.hpp>
|
|
||||||
#include <components/misc/slice_array.hpp>
|
#include <components/misc/slice_array.hpp>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -69,7 +69,7 @@ class NIFFile
|
||||||
{
|
{
|
||||||
std::string err = "NIFFile Error: " + msg;
|
std::string err = "NIFFile Error: " + msg;
|
||||||
err += "\nFile: " + filename;
|
err += "\nFile: " + filename;
|
||||||
throw str_exception(err);
|
throw std::runtime_error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a NIF stream. The name is used for error messages.
|
/// Open a NIF stream. The name is used for error messages.
|
||||||
|
|
|
@ -767,14 +767,20 @@ void NIFLoader::handleNode(Nif::Node *node, int flags,
|
||||||
|
|
||||||
if (!skel.isNull()) //if there is a skeleton
|
if (!skel.isNull()) //if there is a skeleton
|
||||||
{
|
{
|
||||||
bone = skel->createBone(node->name.toString());
|
std::string name = node->name.toString();
|
||||||
|
// Quick-n-dirty workaround for the fact that several
|
||||||
|
// bones may have the same name.
|
||||||
|
if(!skel->hasBone(name))
|
||||||
|
{
|
||||||
|
bone = skel->createBone(name);
|
||||||
|
|
||||||
if (parentBone)
|
if (parentBone)
|
||||||
parentBone->addChild(bone);
|
parentBone->addChild(bone);
|
||||||
|
|
||||||
bone->setInheritOrientation(true);
|
bone->setInheritOrientation(true);
|
||||||
bone->setPosition(convertVector3(node->trafo->pos));
|
bone->setPosition(convertVector3(node->trafo->pos));
|
||||||
bone->setOrientation(convertRotation(node->trafo->rotation));
|
bone->setOrientation(convertRotation(node->trafo->rotation));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,6 @@ include_directories(
|
||||||
${OGRE_INCLUDE_DIR}
|
${OGRE_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
include(MyGUI.OgrePlatform.list)
|
include(MyGUI.OgrePlatform.list)
|
||||||
add_library(MyGUI.OgrePlatform ${HEADER_FILES} ${SOURCE_FILES})
|
add_library(MyGUIOgrePlatform ${HEADER_FILES} ${SOURCE_FILES})
|
||||||
target_link_libraries(MyGUI.OgrePlatform ${OGRE_LIBRARIES})
|
target_link_libraries(MyGUIOgrePlatform ${OGRE_LIBRARIES})
|
||||||
link_directories(${OGRE_LIB_DIR})
|
link_directories(${OGRE_LIB_DIR})
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3324f6494c021e3dc69cd76ace5ff25a52e4bcce
|
Subproject commit b08c2f78dc24f05f67a998114880200518602690
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2e2f8e9725fd1a27a82d0ad5c6c0e296e715eb60
|
Subproject commit 377e7d71ceea5a1ca166b8df9a03a5b68df83bc5
|
|
@ -2,6 +2,12 @@
|
||||||
#ifndef _STDINT_WRAPPER_H
|
#ifndef _STDINT_WRAPPER_H
|
||||||
#define _STDINT_WRAPPER_H
|
#define _STDINT_WRAPPER_H
|
||||||
|
|
||||||
|
#if (_MSC_VER >= 1600)
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
|
|
||||||
// Pull the boost names into the global namespace for convenience
|
// Pull the boost names into the global namespace for convenience
|
||||||
|
@ -11,3 +17,5 @@ using boost::int64_t;
|
||||||
using boost::uint64_t;
|
using boost::uint64_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
14
libs/platform/string.h
Normal file
14
libs/platform/string.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Wrapper for string.h on Mac
|
||||||
|
#ifndef _STRING_WRAPPER_H
|
||||||
|
#define _STRING_WRAPPER_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// need our own implementation of strnlen
|
||||||
|
static size_t strnlen(const char *s, size_t n)
|
||||||
|
{
|
||||||
|
const char *p = (const char *)memchr(s, 0, n);
|
||||||
|
return(p ? p-s : n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
Loading…
Reference in a new issue