diff --git a/Media/CompilerEngine-Dark.rtf b/Media/CompilerEngine-Dark.rtf
new file mode 100644
index 0000000..e455e4b
Binary files /dev/null and b/Media/CompilerEngine-Dark.rtf differ
diff --git a/Media/CompilerEngine.rtf b/Media/CompilerEngine.rtf
new file mode 100644
index 0000000..a4e371d
Binary files /dev/null and b/Media/CompilerEngine.rtf differ
diff --git a/Media/icons-svg/HelpTableOfContents.svg b/Media/icons-svg/HelpTableOfContents.svg
new file mode 100644
index 0000000..50f00ed
--- /dev/null
+++ b/Media/icons-svg/HelpTableOfContents.svg
@@ -0,0 +1,15 @@
+
diff --git a/NWScript-Npp/NWScript-Npp.vcxproj b/NWScript-Npp/NWScript-Npp.vcxproj
index fbc11af..1fbbdaf 100644
--- a/NWScript-Npp/NWScript-Npp.vcxproj
+++ b/NWScript-Npp/NWScript-Npp.vcxproj
@@ -122,7 +122,7 @@
Level3
NOMINMAX;PCRE2_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_WIN32;_DEBUG;_USRDLL;DLL_EXPORTS;%(PreprocessorDefinitions)
$(ProjectDir)..\src\;$(ProjectDir)..\src\Lexers;$(ProjectDir)..\src\Lexers\Lexlib;$(ProjectDir)..\src\Lexers\Scintilla;$(ProjectDir)..\src\Plugin Controls;$(ProjectDir)..\src\Plugin Interface;$(ProjectDir)..\src\Notepad Controls;$(ProjectDir)..\src\Utils;$(SolutionDir)lib\NscLib\Exports;$(SolutionDir)lib\lunasvg\include;$(ProjectDir)..\src\DarkMode
- stdcpplatest
+ stdcpp20
NoListing
Use
pch.h
@@ -148,7 +148,7 @@
true
NOMINMAX;PCRE2_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_WIN32;NDEBUG;_USRDLL;DLL_EXPORTS;%(PreprocessorDefinitions)
$(ProjectDir)..\src\;$(ProjectDir)..\src\Lexers;$(ProjectDir)..\src\Lexers\Lexlib;$(ProjectDir)..\src\Lexers\Scintilla;$(ProjectDir)..\src\Plugin Controls;$(ProjectDir)..\src\Plugin Interface;$(ProjectDir)..\src\Notepad Controls;$(ProjectDir)..\src\Utils;$(SolutionDir)lib\NscLib\Exports;$(SolutionDir)lib\lunasvg\include;$(ProjectDir)..\src\DarkMode
- stdcpplatest
+ stdcpp20
NoListing
Use
pch.h
@@ -200,7 +200,7 @@
Level3
NOMINMAX;PCRE2_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN64;_WIN64;WIN32;_WIN32;NDEBUG;_USRDLL;DLL_EXPORTS;%(PreprocessorDefinitions)
$(ProjectDir)..\src\;$(ProjectDir)..\src\Lexers;$(ProjectDir)..\src\Lexers\Lexlib;$(ProjectDir)..\src\Lexers\Scintilla;$(ProjectDir)..\src\Plugin Controls;$(ProjectDir)..\src\Plugin Interface;$(ProjectDir)..\src\Notepad Controls;$(ProjectDir)..\src\Utils;$(SolutionDir)lib\NscLib\Exports;$(SolutionDir)lib\lunasvg\include;$(ProjectDir)..\src\DarkMode
- stdcpplatest
+ stdcpp20
NoListing
Use
pch.h
@@ -246,6 +246,12 @@
+
+
+
+
+
+
@@ -265,6 +271,8 @@
+
+
@@ -284,7 +292,6 @@
-
@@ -328,6 +335,48 @@
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
@@ -347,6 +396,8 @@
+
+
..\src;%(AdditionalIncludeDirectories)
@@ -378,13 +429,14 @@
NotUsing
-
+
+
@@ -398,6 +450,7 @@
+
@@ -435,6 +488,7 @@
+
diff --git a/NWScript-Npp/NWScript-Npp.vcxproj.filters b/NWScript-Npp/NWScript-Npp.vcxproj.filters
index ace6252..e29b57f 100644
--- a/NWScript-Npp/NWScript-Npp.vcxproj.filters
+++ b/NWScript-Npp/NWScript-Npp.vcxproj.filters
@@ -38,6 +38,9 @@
{1d74ff3e-534a-469a-a3f1-7c3af1bf8e5e}
+
+ {7df729ef-c3bd-47b9-939f-b92d5bb8c0cf}
+
@@ -126,9 +129,6 @@
Utils
-
- Plugin Dialogs
-
Resource Files
@@ -158,7 +158,6 @@
Utils
-
Plugin Dialogs
@@ -211,6 +210,31 @@
DarkMode
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+
+ Plugin Dialogs
+
+
+ Plugin Dialogs
+
@@ -244,9 +268,6 @@
Utils
-
- Plugin Dialogs
-
Plugin Dialogs
@@ -264,7 +285,6 @@
Plugin Dialogs
-
Plugin Dialogs
@@ -305,6 +325,34 @@
DarkMode
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+ Native Compiler
+
+
+
+ Plugin Dialogs
+
+
+ Plugin Dialogs
+
@@ -324,94 +372,103 @@
Media
-
- Resource Files
-
-
- Resource Files
-
Resource Files
- Resource Files
+ Media
+
+
+ Media
+
+
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
+
+
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
+
+
+ Media
+
+
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
+
+
+ Media
+
+
+ Media
+
+
+ Media
+
+
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
+ Media
- Resource Files
-
-
- Resource Files
-
-
- Resource Files
-
-
- Resource Files
-
-
- Resource Files
+ Media
-
- Resource Files
+
+ Media
-
- Resource Files
+
+ Media
-
+
Resource Files
@@ -427,17 +484,17 @@
Media
-
- Resource Files
-
- Resource Files
+ Media
- Resource Files
+ Media
+
+
+ Media
- Resource Files
+ Media
@@ -447,5 +504,8 @@
Custom Lexers\Lexilla
+
+ Native Compiler
+
\ No newline at end of file
diff --git a/src/Common.cpp b/src/Common.cpp
index 40c0a1a..72b9cdd 100644
--- a/src/Common.cpp
+++ b/src/Common.cpp
@@ -152,6 +152,14 @@ namespace NWScriptPluginCommons {
return output;
}
+ // Makes a string to lower case
+ std::string toLowerCase(const std::string& str)
+ {
+ std::string result = str;
+ std::transform(result.begin(), result.end(), result.begin(), ::tolower);
+ return result;
+ }
+
// Opens a file dialog
bool openFileDialog(HWND hOwnerWnd, std::vector& outSelectedFiles, const TCHAR* sFilters,
const generic_string& lastOpenedFolder, bool multiFile)
@@ -897,6 +905,28 @@ namespace NWScriptPluginCommons {
return true;
}
+ char* fileToNullTermBuffer(const generic_string& filePath, size_t* pBufferSize)
+ {
+ std::ifstream file(filePath, std::ios::binary | std::ios::ate);
+
+ if (!file.is_open())
+ return nullptr;
+
+ std::streampos fileSize = file.tellg();
+ *pBufferSize = fileSize;
+
+ char* buffer = new char[*pBufferSize + 1];
+
+ file.seekg(0, std::ios::beg);
+ file.read(buffer, fileSize);
+ file.close();
+
+ buffer[fileSize] = 0;
+
+ *pBufferSize = fileSize;
+ return buffer;
+ }
+
// Saves a string buffer into a raw file
bool bufferToFile(const generic_string& filePath, const std::string& sContents)
{
@@ -912,6 +942,16 @@ namespace NWScriptPluginCommons {
return true;
}
+ // Removes the file extension from name
+ std::string removeFileExtension(const std::string& filename)
+ {
+ size_t lastDotPos = filename.find_last_of(".");
+ if (lastDotPos != std::string::npos) {
+ return filename.substr(0, lastDotPos);
+ }
+ return filename;
+ }
+
// Writes a pseudo-batch file to store Notepad++ executable to be called by ShellExecute
// with a delay (So it can restart seeamlessly).
bool writePseudoBatchExecute(const generic_string& path, const generic_string& executePath)
diff --git a/src/Common.h b/src/Common.h
index 11251ff..0a26efc 100644
--- a/src/Common.h
+++ b/src/Common.h
@@ -114,6 +114,9 @@ namespace NWScriptPluginCommons {
// Returns a new string replacing all input string %VARIABLES% variables with the associated string map(%VARIABLE%, %VALUE%)
std::wstring replaceStringsW(const std::wstring& input, std::map& replaceStrings);
+ // Makes a string to lower case
+ std::string toLowerCase(const std::string& str);
+
// Opens a file dialog
bool openFileDialog(HWND hOwnerWnd, std::vector& outSelectedFiles,
const TCHAR* sFilters = TEXT("All files (*.*)\0*.*"),
@@ -183,9 +186,15 @@ namespace NWScriptPluginCommons {
// Loads a raw file into a string buffer
bool fileToBuffer(const generic_string& filePath, std::string& sContents);
+ // Loads a raw file into a char* buffer. pBufferSize returns the number of read bytes
+ char* fileToNullTermBuffer(const generic_string& filePath, size_t* pBufferSize);
+
// Saves a string buffer into a raw file
bool bufferToFile(const generic_string& filePath, const std::string& sContents);
+ // Removes the file extension from name
+ std::string removeFileExtension(const std::string& filename);
+
// Checks for a path's write permission.
// returns false if not successful (eg: file/path doesn't exist), else returns true and fills outFilePermission enums
bool checkWritePermission(const generic_string& sPath, PathWritePermission& outPathPermission);
diff --git a/src/NWScriptCompiler.cpp b/src/NWScriptCompiler.cpp
index b6d5da1..c4770b7 100644
--- a/src/NWScriptCompiler.cpp
+++ b/src/NWScriptCompiler.cpp
@@ -15,6 +15,7 @@
#include "VersionInfoEx.h"
using namespace NWScriptPlugin;
+
typedef NWScriptLogger::LogType LogType;
#define DEPENDENCYHEADER " \
@@ -35,6 +36,136 @@ typedef jpcre2::select pcre2;
static pcre2::Regex assemblyLine(FORMATDISASMREGEX, PCRE2_MULTILINE, jpcre2::JIT_COMPILE);
static pcre2::Regex dependencyParse(DEPENDENCYPARSEREGEX, 0, jpcre2::JIT_COMPILE);
+// This new global resource manager pointer is required for new compiler.
+// It will only point to the compiler's instance ResourceManager
+// Since it needs a global resource, we also make a global pointer to the script compiler itself
+static ResourceManager* g_ResourceManager = nullptr;
+static NWScriptCompiler* g_NWScriptCompilerV2 = nullptr;
+
+static std::map CompileErrorTlk = {
+ {560, "Error: Unexpected character"},
+ {561, "Error: Fatal compiler error"},
+ {562, "Error: Program compound statement at start"},
+ {563, "Error: Unexpected end compound statement"},
+ {564, "Error: After compound statement at end"},
+ {565, "Error: Parsing variable list"},
+ {566, "Error: Unknown state in compiler"},
+ {567, "Error: Invalid declaration type"},
+ {568, "Error: No left bracket on expression"},
+ {569, "Error: No right bracket on expression"},
+ {570, "Error: Bad start of statement"},
+ {571, "Error: No left bracket on arg list"},
+ {572, "Error: No right bracket on arg list"},
+ {573, "Error: No semicolon after expression"},
+ {574, "Error: Parsing assignment statement"},
+ {575, "Error: Bad lvalue"},
+ {576, "Error: Bad constant type"},
+ {577, "Error: Identifier list full"},
+ {578, "Error: Non integer id for integer constant"},
+ {579, "Error: Non float id for float constant"},
+ {580, "Error: Non string id for string constant"},
+ {581, "Error: Variable already used within scope"},
+ {582, "Error: Variable defined without type"},
+ {583, "Error: Incorrect variable state left on stack"},
+ {584, "Error: Non integer expression where integer required"},
+ {585, "Error: Void expression where non void required"},
+ {586, "Error: Invalid parameters for assignment"},
+ {587, "Error: Declaration does not match parameters"},
+ {588, "Error: Logical operation has invalid operands"},
+ {589, "Error: Equality test has invalid operands"},
+ {590, "Error: Comparison test has invalid operands"},
+ {591, "Error: Shift operation has invalid operands"},
+ {592, "Error: Arithmetic operation has invalid operands"},
+ {593, "Error: Unknown operation in semantic check"},
+ {594, "Error: Script too large"},
+ {595, "Error: Return statement has no parameters"},
+ {596, "Error: No while after do keyword"},
+ {597, "Error: Function definition missing name"},
+ {598, "Error: Function definition missing parameter list"},
+ {599, "Error: Malformed parameter list"},
+ {600, "Error: Bad type specifier"},
+ {601, "Error: No semicolon after structure"},
+ {602, "Error: Ellipsis in identifier"},
+ {603, "Error: File not found"},
+ {604, "Error: Include recursive"},
+ {605, "Error: Include too many levels"},
+ {606, "Error: Parsing return statement"},
+ {607, "Error: Parsing identifier list"},
+ {608, "Error: Parsing function declaration"},
+ {609, "Error: Duplicate function implementation"},
+ {610, "Error: Token too long"},
+ {611, "Error: Undefined structure"},
+ {612, "Error: Left of structure part not structure"},
+ {613, "Error: Right of structure part not field in structure"},
+ {614, "Error: Undefined field in structure"},
+ {615, "Error: Structure redefined"},
+ {616, "Error: Variable used twice in same structure"},
+ {617, "Error: Function implementation and definition differ"},
+ {618, "Error: Mismatched types"},
+ {619, "Error: Integer not at top of stack"},
+ {620, "Error: Return type and function type mismatched"},
+ {621, "Error: Not all control paths return a value"},
+ {622, "Error: Undefined identifier"},
+ {623, "Error: No function main in script"},
+ {624, "Error: Function main must have void return value"},
+ {625, "Error: Function main must have no parameters"},
+ {626, "Error: Non void function cannot be a statement"},
+ {627, "Error: Bad variable name"},
+ {628, "Error: Non optional parameter cannot follow optional parameter"},
+ {629, "Error: Type does not have an optional parameter"},
+ {630, "Error: Non constant in function declaration"},
+ {631, "Error: Parsing constant vector"},
+ {1594, "Error: Operand must be an integer lvalue"},
+ {1595, "Error: Conditional requires second expression"},
+ {1596, "Error: Conditional must have matching return types"},
+ {1597, "Error: Multiple default statements within switch"},
+ {1598, "Error: Multiple case constant statements within switch"},
+ {1599, "Error: Case parameter not a constant integer"},
+ {1600, "Error: Switch must evaluate to an integer"},
+ {1601, "Error: No colon after default label"},
+ {1602, "Error: No colon after case label"},
+ {1603, "Error: No semicolon after statement"},
+ {4834, "Error: Break outside of loop or case statement"},
+ {4835, "Error: Too many parameters on function"},
+ {4836, "Error: Unable to open file for writing"},
+ {4855, "Error: Unterminated string constant"},
+ {5182, "Error: No function intsc in script"},
+ {5183, "Error: Function intsc must have void return value"},
+ {5184, "Error: Function intsc must have no parameters"},
+ {6804, "Error: Jumping over declaration statements case disallowed"},
+ {6805, "Error: Jumping over declaration statements default disallowed"},
+ {6823, "Error: Else without corresponding if"},
+ {3741, "Error: Invalid type for const keyword"},
+ {3742, "Error: Const keyword cannot be used on non global variables"},
+ {3752, "Error: Invalid value assigned to constant"},
+ {9081, "Error: Switch condition cannot be followed by a null statement"},
+ {9082, "Error: While condition cannot be followed by a null statement"},
+ {9083, "Error: For statement cannot be followed by a null statement"},
+ {9155, "Error: Cannot include this file twice"},
+ {10407, "If condition cannot be followed by a null statement"},
+ {40104, "Else cannot be followed by a null statement"}
+};
+
+// Now we define some plugin-exclusive compiler message codes
+#define NSC2001_RESOURCE_MANAGER_INITIALIZE_FAIL "NSC2001"
+#define NSC2002_OPEN_FILE_FAIL "NSC2002"
+#define NSC2003_RESERVED "NSC2003"
+#define NSC2004_UNKNOWN_COMPILE_ERROR "NSC2004"
+#define NSC2005_COULD_NOT_WRITE_COMPILED_FILE "NSC2005"
+#define NSC2006_COULD_NOT_GENERATE_SYMBOL_FILE "NSC2006"
+#define NSC2007_DISASSEMBLY_COMPILER_INIT_FAIL "NSC2007"
+#define NSC2008_COULD_NOT_WRITE_DISASSEMBLY_FILE "NSC2008"
+#define NSC2009_COULD_NOT_WRITE_DEPENDENCY_FILE "NSC2009"
+#define NSC2010_CANT_COMPILE_NWSCRIPT_NSS "NSC2010"
+#define NSC2011_INCLUDE_FILE_IGNORED "NSC2010"
+
+
+NWScriptCompiler::NWScriptCompiler() :
+ _resourceManager(nullptr), _settings(nullptr), _compilerLegacy(nullptr)
+{
+ g_NWScriptCompilerV2 = this;
+}
+
bool NWScriptCompiler::initialize() {
// Critical path, initialize resources
@@ -44,7 +175,7 @@ bool NWScriptCompiler::initialize() {
}
catch (std::runtime_error& e)
{
- _logger.log("Failed to initialize the resources manager: " + std::string(e.what()), LogType::Critical, "NSC2001");
+ _logger.log("Failed to initialize the resources manager: " + std::string(e.what()), LogType::Critical, NSC2001_RESOURCE_MANAGER_INITIALIZE_FAIL);
return false;
}
@@ -53,6 +184,33 @@ bool NWScriptCompiler::initialize() {
return true;
}
+void NWScriptCompiler::reset() {
+ _resourceManager = nullptr;
+ _compilerNative = nullptr;
+ _compilerLegacy = nullptr;
+ _includePaths.clear();
+ _fetchPreprocessorOnly = false;
+ _makeDependencyView = false;
+ _sourcePath = "";
+ _destDir = "";
+ setMode(0);
+ _processingEndCallback = nullptr;
+ clearLog();
+
+ // Free memory from Resource Cache
+ for (auto& entry : _ResourceCache)
+ {
+ if (entry.second.Allocated && entry.second.Contents)
+ {
+ delete[] entry.second.Contents;
+ entry.second.Contents = nullptr;
+ entry.second.Allocated = false;
+ }
+ }
+
+ _ResourceCache.clear();
+}
+
bool NWScriptCompiler::loadScriptResources()
{
ResourceManager::ModuleLoadParams LoadParams;
@@ -107,7 +265,8 @@ void NWScriptCompiler::processFile(bool fromMemory, char* fileContents)
if (_stricmp(_sourcePath.filename().string().c_str(), "nwscript.nss") == 0 && _compilerMode == 0)
{
_logger.log("Compiling script: " + _sourcePath.string(), LogType::ConsoleMessage);
- _logger.log("Error: you can't explicitly compile any script named \"nwscript.nss\", this name is reserved for the main engine.", LogType::Critical, "NSC2010");
+ _logger.log("Error: you can't explicitly compile any script named \"nwscript.nss\", this name is reserved for the main engine.",
+ LogType::Critical, NSC2010_CANT_COMPILE_NWSCRIPT_NSS);
_logger.log("File ignored: " + _sourcePath.string() , LogType::Info);
notifyCaller(false);
return;
@@ -147,12 +306,24 @@ void NWScriptCompiler::processFile(bool fromMemory, char* fileContents)
_includePaths.push_back(properDirNameA(wstr2str(s)) + "\\");
}
+ // Set global resource variable to current resource manager
+ g_ResourceManager = _resourceManager.get();
+
+ // Create compiler. Points functions of API to our own.
+ CScriptCompilerAPI cAPI;
+ cAPI.ResManLoadScriptSourceFile = ResManLoadScriptSourceFile;
+ cAPI.ResManUpdateResourceDirectory = ResManUpdateResourceDirectory;
+ cAPI.ResManWriteToFile = ResManWriteToFile;
+ cAPI.TlkResolve = TlkResolve;
+
+ _compilerNative = std::make_unique(NWN::ResNSS, NWN::ResNCS, NWN::ResNDB, cAPI);
+
// Create our compiler/disassembler
- _compiler = std::make_unique(*_resourceManager, _settings->useNonBiowareExtenstions);
- _compiler->NscSetLogger(&_logger);
- _compiler->NscSetIncludePaths(_includePaths);
- _compiler->NscSetCompilerErrorPrefix(SCRIPTERRORPREFIX);
- _compiler->NscSetResourceCacheEnabled(true);
+ _compilerLegacy = std::make_unique(*_resourceManager, _settings->useNonBiowareExtenstions);
+ _compilerLegacy->NscSetLogger(&_logger);
+ _compilerLegacy->NscSetIncludePaths(_includePaths);
+ _compilerLegacy->NscSetCompilerErrorPrefix(SCRIPTERRORPREFIX);
+ _compilerLegacy->NscSetResourceCacheEnabled(true);
}
// Acquire information about NWN Resource Type of the file. Warning of ignored result is incorrect.
@@ -169,7 +340,7 @@ void NWScriptCompiler::processFile(bool fromMemory, char* fileContents)
{
if (!fileToBuffer(_sourcePath.c_str(), inFileContents))
{
- _logger.log("Could not load the specified file: " + wstr2str(_sourcePath), LogType::Critical, "NSC2002");
+ _logger.log("Could not load the specified file: " + wstr2str(_sourcePath), LogType::Critical, NSC2002_OPEN_FILE_FAIL);
notifyCaller(false);
return;
}
@@ -190,23 +361,108 @@ void NWScriptCompiler::processFile(bool fromMemory, char* fileContents)
bool bSuccess = false;
if (_compilerMode == 0)
{
+ // Use old library to fetch preprocessor and make dependencies, since the new Beamdog's compiler don't support them
if (_fetchPreprocessorOnly)
+ {
_logger.log("Fetching preprocessor output for: " + _sourcePath.string(), LogType::ConsoleMessage);
- else
+ bSuccess = compileScriptLegacy(inFileContents, fileResType, fileResRef);
+ }
+
+ if (_makeDependencyView)
+ {
+ _logger.log("Making dependency view for: " + _sourcePath.string(), LogType::ConsoleMessage);
+ bSuccess = compileScriptLegacy(inFileContents, fileResType, fileResRef);
+ }
+
+ // Use new library for compiling to support NWScript latest features
+ if (!_fetchPreprocessorOnly && !_makeDependencyView)
+ {
_logger.log("Compiling script: " + _sourcePath.string(), LogType::ConsoleMessage);
- bSuccess = compileScript(inFileContents, fileResType, fileResRef);
+ if (_settings->compilerEngine == 0)
+ bSuccess = compileScriptNative(inFileContents, fileResType, fileResRef);
+ else
+ bSuccess = compileScriptLegacy(inFileContents, fileResType, fileResRef);
+ }
}
else
{
_logger.log("Disassembling binary: " + _sourcePath.string(), LogType::ConsoleMessage);
- bSuccess = disassembleBinary(inFileContents, fileResType, fileResRef);
+ bSuccess = disassemblyBinary(inFileContents, fileResType, fileResRef);
}
notifyCaller(bSuccess);
}
-bool NWScriptCompiler::compileScript(std::string& fileContents,
+bool NWScriptCompiler::compileScriptNative(std::string& fileContents,
+ const NWN::ResType& fileResType, const NWN::ResRef32& fileResRef)
+{
+ // Setup compiler according to user's preferences
+ _compilerNative->SetGenerateDebuggerOutput(_settings->generateSymbols);
+ uint32_t optimizationFlags = _settings->generateSymbols ? CSCRIPTCOMPILER_OPTIMIZE_NOTHING :
+ _settings->optimizeScript ? CSCRIPTCOMPILER_OPTIMIZE_EVERYTHING : CSCRIPTCOMPILER_OPTIMIZE_NOTHING;
+ _compilerNative->SetOptimizationFlags(optimizationFlags);
+ _compilerNative->SetCompileConditionalOrMain(1);
+ _compilerNative->SetIdentifierSpecification("nwscript");
+ _compilerNative->SetOutputAlias("");
+
+ // Compile memory allocated file
+ NativeCompileResult ret;
+
+ ret.code = _compilerNative->CompileFile(_sourcePath.string());
+
+ //ret.code = _compilerV2->CompileScriptChunk(fileContents, false);
+
+ // Sometimes, CompileFile returns 1 or -1; in which case the error sould be in CapturedError.
+ // Forward from there.
+ if (ret.code == 1 || ret.code == -1)
+ {
+ ret.code = _compilerNative->GetCapturedErrorStrRef();
+ assert(ret.code != 0);
+ if (ret.code == 0)
+ {
+ ret.code = STRREF_CSCRIPTCOMPILER_ERROR_FATAL_COMPILER_ERROR*-1;
+ _logger.log(CompileErrorTlk[ret.code],
+ LogType::Critical, std::string("NSC") + std::to_string(ret.code));
+
+ return false;
+ }
+ }
+
+ // Resolve error messages if apply
+ if (ret.code)
+ {
+ ret.str = ret.code ? _compilerNative->GetCapturedError()->CStr() : (char*)"";
+
+ std::string srcFileName = _sourcePath.stem().string();
+ std::string srcFileExt = _sourcePath.extension().string();
+ srcFileExt.erase(0, 1); // Delete the . before the extension.
+
+ // Pre-process some known errors that are a bit different from the others (don't have line numbers, etc)
+ switch (abs(ret.code))
+ {
+ case 561:
+ case 594:
+ _logger.log(TlkResolve(ret.code), LogType::Error, "NSC" + ret.code, srcFileName, srcFileExt, "-");
+ break;
+
+ // This is about include files. Downgrade to warning...
+ case 623:
+ _logger.log("File [" + _sourcePath.filename().string() + "] appears to be an include file - no void main() or StartingConditional() inside. Ignored.",
+ LogType::Warning, NSC2011_INCLUDE_FILE_IGNORED, srcFileName, srcFileExt, "-");
+ ret.code = 0;
+ break;
+ default:
+ _logger.WriteText(ret.str);
+ break;
+ }
+ }
+
+ return (ret.code == 0);
+}
+
+
+bool NWScriptCompiler::compileScriptLegacy(std::string& fileContents,
const NWN::ResType& fileResType, const NWN::ResRef32& fileResRef)
{
// We always ignore include files. And for our project, the compiler ALWAYS
@@ -243,7 +499,7 @@ bool NWScriptCompiler::compileScript(std::string& fileContents,
swutil::ByteVec debugSymbols;
std::set fileDependencies;
- NscResult result = _compiler->NscCompileScript(fileResRef, fileContents.c_str(), fileContents.size(), _settings->compileVersion,
+ NscResult result = _compilerLegacy->NscCompileScript(fileResRef, fileContents.c_str(), fileContents.size(), _settings->compileVersion,
bOptimize, bIgnoreIncludes, &_logger, compilerFlags, generatedCode, debugSymbols, fileDependencies, _settings->generateSymbols);
switch (result)
@@ -267,7 +523,7 @@ bool NWScriptCompiler::compileScript(std::string& fileContents,
default:
_logger.log("", LogType::ConsoleMessage);
- _logger.log("Unknown status code", LogType::Critical, "NSC2004");
+ _logger.log("Unknown status code", LogType::Critical, NSC2004_UNKNOWN_COMPILE_ERROR);
_logger.log("", LogType::ConsoleMessage);
return false;
}
@@ -286,7 +542,7 @@ bool NWScriptCompiler::compileScript(std::string& fileContents,
if (!bufferToFile(outputPath, dataRef))
{
_logger.log("", LogType::ConsoleMessage);
- _logger.log(TEXT("Could not write compiled output file: ") + outputPath, LogType::Critical, TEXT("NSC2005"));
+ _logger.log(TEXT("Could not write compiled output file: ") + outputPath, LogType::Critical, TEXT(NSC2005_COULD_NOT_WRITE_COMPILED_FILE));
_logger.log("", LogType::ConsoleMessage);
return false;
}
@@ -300,7 +556,7 @@ bool NWScriptCompiler::compileScript(std::string& fileContents,
if (!bufferToFile(outputPath, dataRef))
{
_logger.log("", LogType::ConsoleMessage);
- _logger.log(TEXT("Could not write generated symbols output file: ") + outputPath, LogType::Critical, TEXT("NSC2006"));
+ _logger.log(TEXT("Could not write generated symbols output file: ") + outputPath, LogType::Critical, TEXT(NSC2006_COULD_NOT_GENERATE_SYMBOL_FILE));
_logger.log("", LogType::ConsoleMessage);
return false;
}
@@ -313,19 +569,19 @@ bool NWScriptCompiler::compileScript(std::string& fileContents,
return true;
}
-bool NWScriptCompiler::disassembleBinary(std::string& fileContents,
+bool NWScriptCompiler::disassemblyBinary(std::string& fileContents,
const NWN::ResType& fileResType, const NWN::ResRef32& fileResRef)
{
std::string generatedCode;
// Main disassemble step.
- _compiler->NscDisassembleScript(fileContents.c_str(), fileContents.size(), generatedCode);
+ _compilerLegacy->NscDisassembleScript(fileContents.c_str(), fileContents.size(), generatedCode);
// This is the way the library returns errors to us on that routine... :D
if (generatedCode == "DISASSEMBLY ERROR: COMPILER INITIALIZATION FAILED!")
{
_logger.log("", LogType::ConsoleMessage);
- _logger.log("Disassembler - Compiler Initialization failed!", LogType::Critical, "NSC2007");
+ _logger.log("Disassembler - Compiler Initialization failed!", LogType::Critical, NSC2007_DISASSEMBLY_COMPILER_INIT_FAIL);
_logger.log("", LogType::ConsoleMessage);
return false;
}
@@ -344,7 +600,7 @@ bool NWScriptCompiler::disassembleBinary(std::string& fileContents,
if (!bufferToFile(outputPath, formatedCode.str()))
{
_logger.log("", LogType::ConsoleMessage);
- _logger.log(TEXT("Could not write disassembled output file: ") + outputPath, LogType::Critical, TEXT("NSC2008"));
+ _logger.log(TEXT("Could not write disassembled output file: ") + outputPath, LogType::Critical, TEXT(NSC2008_COULD_NOT_WRITE_DISASSEMBLY_FILE));
_logger.log("", LogType::ConsoleMessage);
return false;
}
@@ -450,11 +706,234 @@ bool NWScriptCompiler::MakeDependenciesFile(const std::set& depende
if (!bufferToFile(outputPath, sdependencies.str()))
{
_logger.log("", LogType::ConsoleMessage);
- _logger.log(TEXT("Could not write dependency file: ") + outputPath, LogType::Critical, TEXT("NSC2009"));
+ _logger.log(TEXT("Could not write dependency file: ") + outputPath, LogType::Critical, TEXT(NSC2009_COULD_NOT_WRITE_DEPENDENCY_FILE));
_logger.log("", LogType::ConsoleMessage);
return false;
}
}
return true;
-}
\ No newline at end of file
+}
+
+
+bool CacheResource(const char* ResFileContents, UINT32 ResFileLength, bool Allocated,
+ const NWN::ResRef32& ResRef, NWN::ResType ResType, const std::string& sLocation)
+{
+ try
+ {
+ ResourceCacheKey Key;
+ ResourceCacheEntry Entry;
+ bool Inserted;
+
+ Key.ResRef = ResRef;
+ Key.ResType = ResType;
+
+ Entry.Allocated = Allocated;
+ Entry.Contents = (char*)ResFileContents;
+ Entry.Size = ResFileLength;
+ Entry.Location = sLocation;
+
+ Inserted = g_NWScriptCompilerV2->getResourceCache().insert(ResourceCache::value_type(Key, Entry)).second;
+
+ assert(Inserted == true);
+ }
+ catch (std::exception)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Dummy function. Interface to new compiler - we do nothing here.
+BOOL NWScriptPlugin::ResManUpdateResourceDirectory(const char* sAlias)
+{
+ return false;
+}
+
+// Intercepts ResManWriteToFile from CScriptCompiler API.
+int32_t NWScriptPlugin::ResManWriteToFile(const char* sFileName, RESTYPE nResType, const uint8_t* pData, size_t nSize, bool bBinary)
+{
+
+ // Decides which type of file to write depending on ResType.
+
+ std::string dataRef;
+ dataRef.assign(reinterpret_cast(pData), nSize);
+
+ generic_string outputPath = str2wstr(g_NWScriptCompilerV2->getDestinationDirectory().string()
+ + "\\" + fs::path(sFileName).stem().string()
+ + "." + g_ResourceManager->ResTypeToExt(nResType)
+ );
+
+ if (!bufferToFile(outputPath, dataRef))
+ {
+ g_NWScriptCompilerV2->logger().log("", LogType::ConsoleMessage);
+
+ switch (nResType)
+ {
+ case NWN::ResNCS:
+ g_NWScriptCompilerV2->logger().log(TEXT("Unable to write compiled output file: ") + outputPath, LogType::Critical, TEXT(NSC2005_COULD_NOT_WRITE_COMPILED_FILE));
+ break;
+ case NWN::ResNDB:
+ g_NWScriptCompilerV2->logger().log(TEXT("Unable to write generated symbols output file: ") + outputPath, LogType::Critical, TEXT(NSC2006_COULD_NOT_GENERATE_SYMBOL_FILE));
+ break;
+ }
+
+ g_NWScriptCompilerV2->logger().log("", LogType::ConsoleMessage);
+ return -1;
+ }
+
+ return 0;
+}
+
+const char* NWScriptPlugin::ResManLoadScriptSourceFile(const char* sFileName, RESTYPE nResType)
+{
+
+ // Try to find resource on cache first.
+ NWN::ResRef32 ResRef;
+ ResourceCacheKey CacheKey;
+
+
+ std::string sFileNameStem = fs::path(sFileName).stem().string();
+
+ try
+ {
+ ResRef = g_ResourceManager->ResRef32FromStr(toLowerCase(sFileNameStem));
+ }
+ catch (std::exception)
+ {
+ return NULL;
+ }
+
+ CacheKey.ResRef = ResRef;
+ CacheKey.ResType = (NWN::ResType)nResType;
+
+ ResourceCache::const_iterator it = g_NWScriptCompilerV2->getResourceCache().find(CacheKey);
+
+ if (it != g_NWScriptCompilerV2->getResourceCache().end())
+ {
+ return it->second.Contents;
+ }
+
+ size_t fileSize = 0;
+ char* fileContents = NULL;
+
+ // Not found: try search include paths first.
+ for (auto it = g_NWScriptCompilerV2->includePaths().begin(); it != g_NWScriptCompilerV2->includePaths().end(); ++it)
+ {
+ std::string Str(*it);
+#ifdef _WINDOWS
+ if (Str.back() != '\\')
+ Str += "\\";
+#else
+ if (Str.back() != '/')
+ Str += "/";
+#endif
+ Str += sFileNameStem;
+ Str += ".";
+ Str += g_ResourceManager->ResTypeToExt(nResType);
+
+ fileSize = 0;
+ fileContents = fileToNullTermBuffer(str2wstr(Str), &fileSize);
+ if (fileSize > 0)
+ {
+ // Cache loaded file for future reference
+ std::string res = *it + sFileNameStem + "." + g_ResourceManager->ResTypeToExt(nResType);
+ CacheResource(fileContents, fileSize, true, ResRef, (NWN::ResType)nResType, res);
+
+ // If not the current compiling file being loaded (eg: loading an include), logs to console
+ std::string srcStem = g_NWScriptCompilerV2->getSourceFilePath().stem().string();
+ if (strcmp(toLowerCase(sFileNameStem).c_str(), toLowerCase(srcStem).c_str()) != 0)
+ g_NWScriptCompilerV2->logger().WriteText("INFO: Loaded File from disk path -> %s\n", Str.c_str());
+
+ return fileContents;
+ }
+ }
+
+ // Not found: try opening via resource files
+ ResourceManager::FileHandle Handle = g_ResourceManager->OpenFile(ResRef, nResType);
+
+ if (Handle == ResourceManager::INVALID_FILE)
+ return NULL;
+
+ // Read entire file upfront
+ fileSize = g_ResourceManager->GetEncapsulatedFileSize(Handle);
+
+ size_t BytesLeft = fileSize;
+ size_t Offset = 0;
+ size_t Read = 0;
+
+ try
+ {
+ if (fileSize != 0)
+ {
+ fileContents = new char[fileSize+1]; // Need a bigger buffer for NULL-Terminated string
+
+ if (fileContents == NULL)
+ {
+ g_NWScriptCompilerV2->logger().log("Critical failure: Memory allocation for resource [" + std::string(sFileName) + "] failed.", LogType::Critical, "NSC2101");
+ throw std::bad_alloc();
+ }
+
+ while (BytesLeft)
+ {
+ if (!g_ResourceManager->ReadEncapsulatedFile(Handle, Offset, BytesLeft, &Read, &fileContents[Offset]))
+ {
+ g_NWScriptCompilerV2->logger().log("Critical failure: ReadEncapsulatedFile did not succeeded.", LogType::Critical, "NSC2101");
+ throw std::runtime_error("Critical failure: ReadEncapsulatedFile did not succeeded");
+ }
+
+ if (Read == 0)
+ {
+ g_NWScriptCompilerV2->logger().log("Critical failure: read 0 bytes from resource file [" + std::string(sFileName) + "]", LogType::Critical, "NSC2102");
+ throw std::runtime_error("Critical failure: read 0 bytes from resource file");
+ }
+
+ Offset += Read;
+ BytesLeft -= Read;
+ }
+
+ fileContents[fileSize] = 0;
+ }
+ else
+ {
+ fileContents = NULL;
+ }
+ }
+ catch (std::exception)
+ {
+ if (fileContents)
+ delete[] fileContents;
+
+ g_ResourceManager->CloseFile(Handle);
+ return NULL;
+ }
+
+ std::string res = "";
+ std::string AccessorName;
+ try
+ {
+ g_ResourceManager->GetResourceAccessorName(Handle, AccessorName);
+ res = AccessorName + "/" + sFileNameStem + "." + g_ResourceManager->ResTypeToExt(nResType);
+ }
+ catch (std::exception) {}
+
+ // Show includes always. Filter in script plugin
+ g_NWScriptCompilerV2->logger().WriteText("INFO: Loaded file from game's resources -> %s\n", res.c_str());
+
+ // Closes file and appends results to cache
+ g_ResourceManager->CloseFile(Handle);
+
+ CacheResource(fileContents, fileSize, true, ResRef, (NWN::ResType)nResType, res);
+
+ return fileContents;
+}
+
+const char* NWScriptPlugin::TlkResolve(STRREF strRef)
+{
+ if (CompileErrorTlk.contains(strRef))
+ return CompileErrorTlk[strRef].c_str();
+ else
+ return "Error: Unknown error code";
+}
+
diff --git a/src/NWScriptCompiler.h b/src/NWScriptCompiler.h
index 32fb485..4b54fed 100644
--- a/src/NWScriptCompiler.h
+++ b/src/NWScriptCompiler.h
@@ -10,7 +10,9 @@
#include
#include
-#include "Nsc.h"
+#include "Native Compiler/exobase.h" // New oficial compiler provided by Beamdog itself.
+#include "Native Compiler/scriptcomp.h" //
+#include "Nsc.h" // Here we are using NscLib for older features like preprocessor and make dependency
#include "Common.h"
#include "Settings.h"
@@ -18,12 +20,53 @@
namespace NWScriptPlugin
{
+
+ // Copied from NscCompiler.cpp -> Resource Cache structures
+ struct ResourceCacheKey
+ {
+ NWN::ResRef32 ResRef;
+ NWN::ResType ResType;
+
+ inline bool operator < (const ResourceCacheKey& other) const
+ {
+ return (ResType < other.ResType) ||
+ (memcmp(&ResRef, &other.ResRef, sizeof(ResRef)) < 0);
+ }
+
+ inline bool operator == (const ResourceCacheKey& other) const
+ {
+ return (ResType == other.ResType) &&
+ (memcmp(&ResRef, &other.ResRef, sizeof(ResRef)) == 0);
+ }
+ };
+
+ struct ResourceCacheEntry
+ {
+ bool Allocated;
+ char* Contents;
+ UINT32 Size;
+ std::string Location;
+ };
+
+ typedef std::map ResourceCache;
+
+ struct NativeCompileResult
+ {
+ int32_t code;
+ char* str; // static buffer
+ };
+
+ // Function pointers to resolve new compiler Resource API requirements
+ static BOOL ResManUpdateResourceDirectory(const char* sAlias);
+ static int32_t ResManWriteToFile(const char* sFileName, RESTYPE nResType, const uint8_t* pData, size_t nSize, bool bBinary);
+ static const char* ResManLoadScriptSourceFile(const char* sFileName, RESTYPE nResType);
+ static const char* TlkResolve(STRREF strRef);
+
class NWScriptCompiler final
{
public:
- NWScriptCompiler() :
- _resourceManager(nullptr), _settings(nullptr), _compiler(nullptr) {}
+ NWScriptCompiler();
bool isInitialized() {
return _resourceManager != nullptr;
@@ -38,18 +81,7 @@ namespace NWScriptPlugin
bool initialize();
// Reset compiler state
- void reset() {
- _resourceManager = nullptr;
- _compiler = nullptr;
- _includePaths.clear();
- _fetchPreprocessorOnly = false;
- _makeDependencyView = false;
- _sourcePath = "";
- _destDir = "";
- setMode(0);
- _processingEndCallback = nullptr;
- clearLog();
- }
+ void reset();
// Sets destination to a VALID and existing directory (or else get an error)
void setDestinationDirectory(fs::path dest) {
@@ -112,15 +144,15 @@ namespace NWScriptPlugin
_makeDependencyView = false;
}
- int getMode() const {
+ inline int getMode() const {
return _compilerMode;
}
- bool isViewDependencies() const {
+ inline bool isViewDependencies() const {
return _makeDependencyView;
}
- bool isFetchPreprocessorOnly() const {
+ inline bool isFetchPreprocessorOnly() const {
return _fetchPreprocessorOnly;
}
@@ -128,17 +160,31 @@ namespace NWScriptPlugin
return _logger;
}
+ std::vector& includePaths() {
+ return _includePaths;
+ }
+
// Returns if an output path is required for operation
- bool isOutputDirRequired() {
+ inline bool isOutputDirRequired() {
return !(_fetchPreprocessorOnly || _makeDependencyView);
}
+ inline ResourceCache& getResourceCache() {
+ return _ResourceCache;
+ }
+
void processFile(bool fromMemory, char* fileContents);
private:
+
std::unique_ptr _resourceManager;
- std::unique_ptr _compiler;
+ ResourceCache _ResourceCache;
+ std::unique_ptr _compilerNative;
+
+ // # TODO: Remove old compiler references
+ std::unique_ptr _compilerLegacy;
+
bool _fetchPreprocessorOnly = false;
bool _makeDependencyView = false;
int _compilerMode = 0;
@@ -163,11 +209,14 @@ namespace NWScriptPlugin
bool loadScriptResources();
// Compile a plain text script into binary format
- bool compileScript(std::string& fileContents,
+ bool compileScriptLegacy(std::string& fileContents,
+ const NWN::ResType& fileResType, const NWN::ResRef32& fileResRef);
+
+ bool compileScriptNative(std::string& fileContents,
const NWN::ResType& fileResType, const NWN::ResRef32& fileResRef);
// Disassemble a binary file into a pcode assembly text format
- bool disassembleBinary(std::string& fileContents,
+ bool disassemblyBinary(std::string& fileContents,
const NWN::ResType& fileResType, const NWN::ResRef32& fileResRef);
// Dependencies files and views
diff --git a/src/NWScriptLogger.cpp b/src/NWScriptLogger.cpp
index 3cee65b..669de68 100644
--- a/src/NWScriptLogger.cpp
+++ b/src/NWScriptLogger.cpp
@@ -12,19 +12,22 @@
#include "NWScriptLogger.h"
#define PREPROCESSORPARSE R"((?:[\w\s\\.\-\(\):]+)(?:[\w\s\\.\-\(\):]+)\((?:\d+)\):\s(?:\w+):\s(?:NSC6022): Preprocessed: (.*))"
-#define COMPILERREGEX R"((?[\w\s\\.\-\(\):]+)\.(?[\w\s\\.\-\(\):]+)\((?\d+)\):\s(?\w+):\s(?NSC\d+):\s(?.+))"
+#define COMPILERREGEXNATIVE R"((?[\w\s\\.\-\(\):]+)\.(?[\w\s\\.\-\(\):]+)\((?\d+)\):\s(?\w+):\s(?.+)\s(?NSC\d+))"
+#define COMPILERREGEXLEGACY R"((?[\w\s\\.\-\(\):]+)\.(?[\w\s\\.\-\(\):]+)\((?\d+)\):\s(?\w+):\s(?NSC\d+):\s(?.+))"
#define GENERALMESSAGE R"(\s*(?WARNING|ERROR|INFO)\s*:\s*(?.+))"
#define INCLUDESPARSEREGEX R"( ShowIncludes: Handled resource ([^\/]+)\/([^\\\n]+))"
typedef jpcre2::select pcre2;
static const pcre2::Regex preprocessorRegex(PREPROCESSORPARSE, 0, jpcre2::JIT_COMPILE);
-static const pcre2::Regex fileParsingMessageRegex(COMPILERREGEX, 0, jpcre2::JIT_COMPILE);
+static const pcre2::Regex fileParsingMessageRegexNative(COMPILERREGEXNATIVE, 0, jpcre2::JIT_COMPILE);
+static const pcre2::Regex fileParsingMessageRegexLegacy(COMPILERREGEXLEGACY, 0, jpcre2::JIT_COMPILE);
static const pcre2::Regex generalMessageRegex(GENERALMESSAGE, PCRE2_CASELESS, jpcre2::JIT_COMPILE);
static const pcre2::Regex includesRegex(INCLUDESPARSEREGEX, 0, jpcre2::JIT_COMPILE);
static pcre2::RegexMatch preprocessorParsing(&preprocessorRegex);
-static pcre2::RegexMatch fileParsingMessage(&fileParsingMessageRegex);
+static pcre2::RegexMatch fileParsingMessageNative(&fileParsingMessageRegexNative);
+static pcre2::RegexMatch fileParsingMessageLegacy(&fileParsingMessageRegexLegacy);
static pcre2::RegexMatch generalMessage(&generalMessageRegex);
static pcre2::RegexMatch includeFile(&includesRegex);
@@ -81,9 +84,24 @@ void NWScriptLogger::WriteTextV(const char* fmt, va_list ap)
}
// Check for compiler file parsing messages
- fileParsingMessage.setNamedSubstringVector(&namedGroup);
- fileParsingMessage.setSubject(buf);
- matches = fileParsingMessage.match();
+
+ // Parsing messages from new Beamdog's compiler
+ fileParsingMessageNative.setNamedSubstringVector(&namedGroup);
+ fileParsingMessageNative.setSubject(buf);
+ matches = fileParsingMessageNative.match();
+ if (matches)
+ {
+ log(namedGroup[0]["message"],
+ (namedGroup[0]["type"] == "Error") ? LogType::Error : (namedGroup[0]["type"] == "Warning") ? LogType::Warning : LogType::Info,
+ namedGroup[0]["code"], namedGroup[0]["fileName"], namedGroup[0]["fileExt"], namedGroup[0]["lineNumber"]);
+
+ return;
+ }
+
+ // Parsing messages from Legacy Compiler
+ fileParsingMessageLegacy.setNamedSubstringVector(&namedGroup);
+ fileParsingMessageLegacy.setSubject(buf);
+ matches = fileParsingMessageLegacy.match();
if (matches)
{
log(namedGroup[0]["message"],
diff --git a/src/Native Compiler/exobase.h b/src/Native Compiler/exobase.h
new file mode 100644
index 0000000..ab17bc2
--- /dev/null
+++ b/src/Native Compiler/exobase.h
@@ -0,0 +1,591 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+#pragma once
+
+// This file is a reduced variant taken from the base game.
+// Do not port changes here back to the game unless needed for script compiler functionality.
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ExoBase
+//::
+//:: Copyright (c) 1999, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ExoBase.h
+//::
+//:: Header for machine-specific base class stuff.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: 04/26/99
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//:: THIS FILE CONTAINS PORTED CODE
+//::///////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "exotypes.h"
+
+#define EXOASSERTNC() assert(false)
+#define EXOASSERTNCSTR(string) assert(!string)
+#define EXOASSERT(cond) assert(cond)
+#define EXOASSERTSTR(cond, string) assert(cond && string)
+
+///////////////////////////////////////////////////////////////////////////////
+// class CExoString
+///////////////////////////////////////////////////////////////////////////////
+// Created by: Don Yakielashek
+// Date: 04/26/99
+//
+// Desc: C++ string storage and manipulation class.
+// CExoString contains a flag whether the string is single or double byte.
+///////////////////////////////////////////////////////////////////////////////
+
+class CExoString
+{
+
+ // *************************************************************************
+public:
+ // *************************************************************************
+
+ static const char* Whitespace;
+ static const char* Letters;
+ static const char* Numbers;
+ static const char* Alphanumeric;
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString();
+ //-------------------------------------------------------------------------
+ // Desc: Creates an empty CExoString.
+ ///////////////////////////////////////////////////////////////////////////
+
+ CExoString(CExoString&& other)
+ {
+ m_sString = other.m_sString;
+ m_nBufferLength = other.m_nBufferLength;
+ other.m_sString = nullptr;
+ other.m_nBufferLength = 0;
+ }
+ CExoString& operator=(CExoString&& other)
+ {
+ if (this == &other) return *this;
+ if (m_sString)
+ {
+ delete[] m_sString;
+ }
+ m_sString = other.m_sString;
+ m_nBufferLength = other.m_nBufferLength;
+ other.m_sString = nullptr;
+ other.m_nBufferLength = 0;
+ return *this;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString(const char *source);
+ //-------------------------------------------------------------------------
+ // Desc: Creates a CExsoString from a null terminated char array.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString(const CExoString &source);
+ //-------------------------------------------------------------------------
+ // Desc: Creates a copy of a CExoString.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString(const char *source, int32_t length);
+ //-------------------------------------------------------------------------
+ // Desc: Creates a CExoString that contains the first length characters
+ // of a CExoString.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString(int32_t value);
+ //-------------------------------------------------------------------------
+ // Desc: Creates a CExoString representing the int value.
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ // The most rudimentary of std::string interop.
+ CExoString(const std::string& other);
+ CExoString& operator=(const std::string& other);
+ operator std::string() const;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ~CExoString();
+ //-------------------------------------------------------------------------
+ // Desc: Destructor.
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString & operator = (const CExoString &string);
+ //-------------------------------------------------------------------------
+ // Desc: Assigns one CExoString to another.
+ // Params: string: CExoString to be assigned to this CExoString.
+ // Returns: A reference to this CExoString.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString & operator = (const char *string);
+ //-------------------------------------------------------------------------
+ // Desc: Assigns the value of a null terminated character array to a
+ // CExoString.
+ // Params: string: A NULL-terminated character string to be assigned
+ // to this CExoString.
+ // Returns: A reference to this CExoString.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator == (const CExoString &string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Compares two CExoString's.
+ // Params: string: CExoString to compare to this CExoString.
+ // Returns: TRUE if CExoString's are equal.
+ // FALSE if CExoString's are not equal.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator == (const char *string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Compares a CExoString to a null terminated character array.
+ // Params: string: A NULL-terminated character string to compare to
+ // this CExoString.
+ // Returns: TRUE if CExoString's are equal.
+ // FALSE if CExoString's are not equal.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator != (const CExoString &string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if two CExoString's are not equal.
+ // Params: string: CExoString to compare to this CExoString.
+ // Returns: TRUE if CExoString's are equal.
+ // FALSE if CExoString's are not equal.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator != (const char *string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is not equal to a null terminated
+ // character array.
+ // Params: string: A NULL-terminated character string to compare to
+ // this CExoString.
+ // Returns: TRUE if CExoString's are equal.
+ // FALSE if CExoString's are not equal.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator < (const CExoString &string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is less than another CExoString.
+ // Params: string: CExoString to compare to this CExoString.
+ // Returns: TRUE CExoString is less than.
+ // FALSE CExoString is not less than.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator < (const char *string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is less than a null terminated
+ // character array.
+ // Params: string: A NULL-terminated character string to compare to
+ // this CExoString.
+ // Returns: TRUE CExoString is less than.
+ // FALSE CExoString is not less than.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator > (const CExoString &string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is greater than another CExoString.
+ // Params: string: CExoString to compare to this CExoString.
+ // Returns: TRUE CExoString is greater than.
+ // FALSE CExoString is not greater than.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator > (const char *string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is greater than a null terminated
+ // character array.
+ // Params: string: A NULL-terminated character string to compare to
+ // this CExoString.
+ // Returns: TRUE CExoString is greater than.
+ // FALSE CExoString is not greater than.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator <= (const CExoString &string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is less than or equal to another
+ // CExoString.
+ // Params: string: CExoString to compare to this CExoString.
+ // Returns: TRUE CExoString is less than or equal to.
+ // FALSE CExoString is not less than or equal to.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator <= (const char *string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is less than or equal to a null
+ // terminated character array.
+ // Params: string: A NULL-terminated character string to compare to
+ // this CExoString.
+ // Returns: TRUE CExoString is less than or equal to
+ // FALSE CExoString is not less than or equal to
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator >= (const CExoString &string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is greater than or equal to another
+ // CExoString.
+ // Params: string: CExoString to compare to this CExoString.
+ // Returns: TRUE CExoString is greater than or equal to.
+ // FALSE CExoString is not greater than or equal to.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL operator >= (const char *string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Determines if CExoString is greater than or equal toa null
+ // terminated character array.
+ // Params: string: A NULL-terminated character string to compare to
+ // this CExoString.
+ // Returns: TRUE CExoString is greater than or equal to.
+ // FALSE CExoString is not greater than or equal to.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ char operator [] (int32_t position) const;
+ //-------------------------------------------------------------------------
+ // Desc: Gets character at position.
+ // Params: position: The position in this CExoString of the
+ // character desired.
+ // Returns: The character at position.
+ ///////////////////////////////////////////////////////////////////////////
+//friend AsiString __fastcall operator +(const char* lhs, const AnsiString& rhs);
+//AnsiString __fastcall operator +(const AnsiString& rhs) const;
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString operator + (const CExoString &string) const;
+ //-------------------------------------------------------------------------
+ // Desc: Returns the result of two CExoString joined together.
+ // Params: string: CExoString to add (append) to this CExoString.
+ // Returns: CExoString consisting of the two strings added together.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+// CExoString operator + (const char *string);
+ //-------------------------------------------------------------------------
+ // Desc: Returns the result of an CExoString joined with a null terminated
+ // character array
+ //
+ // Return: CExoString consisting of the two strings added together
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ //CExoString operator + (const char *string);
+ //-------------------------------------------------------------------------
+ // Desc: Returns the result of an CExoString joined with a null terminated
+ // character array
+ //
+ // Return: CExoString consisting of the two strings added together
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ int32_t AsINT() const;
+ //-------------------------------------------------------------------------
+ // Desc: Retuns integer value the string represents.
+ // Returns: Integer value the string represents.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ float AsFLOAT() const;
+ //-------------------------------------------------------------------------
+ // Desc: Retuns float value the string represents.
+ // Returns: Float value the string represents.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ char* CStr() const;
+ //-------------------------------------------------------------------------
+ // Desc: Retuns a null terminated character array.
+ // Returns: Null terminated character array.
+ ///////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ int32_t Find(const CExoString &string, int32_t position=0) const;
+
+ int32_t Find(char ch, int32_t position=0) const;
+ //-------------------------------------------------------------------------
+ // Desc: Finds a substring within the string.
+ // Params: string: The substring to find in this CExoString.
+ // Returns: Position where substring is.
+ // -1 if string not found.
+ ///////////////////////////////////////////////////////////////////////////
+
+ int32_t FindNot(char ch, int32_t position=0) const;
+ //-------------------------------------------------------------------------
+ // Desc: Finds the first character that is not ch
+ // Params: ch: The character to not find in this CExoString.
+ // Returns: Position where character is.
+ // -1 if string not found.
+ ///////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ CExoString RemoveAll(const char* c) const;
+ //-------------------------------------------------------------------------
+ // Returns: A copy of this string with all characters contained in c
+ // removed, regardless of order.
+ ///////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ CExoString RemoveAllExcept(const char* c) const;
+ //-------------------------------------------------------------------------
+ // Returns: A copy of this string with all characters NOT contained in c
+ // removed, regardless of order.
+ ///////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ void Format(const char *format,...);
+ //-------------------------------------------------------------------------
+ // Desc: Formats a string based on a number of arguments, like sprintf
+ // does.
+ // Params: format: A character string containing the format of the
+ // string to put into this CExoString.
+ // ...: A series of comma-separated variables or constants
+ // to be inserted into format as a string at the
+ // appropriate positions. There can be zero or more
+ // of these, depending on format.
+ ///////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+ inline void DummyFormat(char *format,...) {return;}
+ //-------------------------------------------------------------------------
+ // Desc: Does nothing. Takes same parameter list as Format
+ // Params: format: A character string containing the format of the
+ // string to put into this CExoString.
+ // ...: A series of comma-separated variables or constants
+ // to be inserted into format as a string at the
+ // appropriate positions. There can be zero or more
+ // of these, depending on format.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ template
+ static CExoString F(const char* fmt, T&& ... args)
+ {
+ CExoString f;
+ f.Format(fmt, args...);
+ return f;
+ }
+
+ // Static formatting helper for cleaner code.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ inline int32_t GetLength() const
+ {
+ return m_sString ? (int32_t) strlen(m_sString) : 0;
+ }
+ //-------------------------------------------------------------------------
+ // Desc: Retuns the length of the CExoString.
+ // Returns: The length of the CExoString.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ void Insert(const CExoString &string, int32_t position);
+ //-------------------------------------------------------------------------
+ // Desc: Inserts a string at the given position.
+ // Params: string: The CExoString to insert into this CExoString.
+ // position: Position in this CExoString where string will be
+ // inserted.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL IsEmpty() const;
+ //-------------------------------------------------------------------------
+ // Desc: Checks if CExoString is a blank string.
+ // Returns: TRUE if this CExoString is blank.
+ // FALSE if this CExoString is not blank.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString Left(int32_t count) const;
+ //-------------------------------------------------------------------------
+ // Desc: Returns leftmost 'count' characters.
+ // Params: count: Number of characters to extract starting from the
+ // left.
+ // Returns: CExoString containing the leftmost 'count' characters.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString LowerCase() const;
+ //-------------------------------------------------------------------------
+ // Desc: Returns the string converted to lowercase.
+ // Returns: CExoString converted to lowercase.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString Right(int32_t count) const;
+ //-------------------------------------------------------------------------
+ // Desc: Returns rightmost 'count' characters.
+ // Params: count: Number of characters to extract starting from the
+ // right.
+ // Returns: CExoString containing the rightmost 'count' characters.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString SubString(int32_t start, int32_t count=-1) const;
+ //-------------------------------------------------------------------------
+ // Desc: Returns a portion of string consisting of 'count' characters
+ // starting at 'start'.
+ // Params: start: The starting position of the substring within this
+ // CExoString.
+ // count: Number of characters to extract into the substring.
+ // <0 means extract to end of string
+ // Returns: CExoString containing the substring.
+ ///////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString UpperCase() const;
+ //-------------------------------------------------------------------------
+ // Desc: Returns the string converted to uppercase.
+ // Returns: CExoString converted to uppercase.
+ ///////////////////////////////////////////////////////////////////////////
+
+ BOOL CompareNoCase(const CExoString &sString) const;
+ BOOL ComparePrefixNoCase(const CExoString &sString, int32_t nSize) const;
+
+ ///////////////////////////////////////////////////////////////////////////
+ BOOL StripNonAlphaNumeric( BOOL bFileName = TRUE, BOOL bEmail = FALSE, BOOL bMasterServer = FALSE );
+ //-------------------------------------------------------------------------
+ // Desc: Removes all non-alpha-numeric symbols from the string
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Strip leading and/or trailing characters from this string, returning a
+ // new string.
+ CExoString Strip(bool leading = true, bool trailing = true, const char* set = Whitespace) const;
+
+ ///////////////////////////////////////////////////////////////////////////
+ CExoString AsTAG() const;
+ //-------------------------------------------------------------------------
+ // Desc: Retuns a proper tag version of the string
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Returns a cross-platform, stable 32bit hash of the string (xxh32)
+ int32_t GetHash() const;
+
+ // Static helper that formats a number of bytes as a human-readable
+ // fractional to the nearest magnitude (i.e. "4.1GB").
+ static CExoString FormatBytes(uint64_t bytes);
+
+ // Static helper that formats a number of seconds as a human-readable interval.
+ static CExoString FormatDuration(uint64_t span,
+ // Only show the N most significant intervals that aren't zero:
+ // compact_levels = 1 -> "1d"
+ // compact_levels = 2 -> "1d 4h"
+ // compact_levels = 3 -> "1d 4h 2m"
+ // Note that a compacted value counts as a full "bigger" level.
+ int compact_levels = 4,
+ // Minimum number of levels to show, even if zeroes.
+ int min_level = 1,
+ // Liberty to abbreviate some values if compaction level and labelling.
+ // For example, 48s would be abbreviated to "<1m"
+ //bool abbreviate = true,
+ // Label fields as "s", "m", "h", "d".
+ bool label_fields = true,
+ // Separator between fields
+ const char* separator = " ");
+
+ // Formats a unix timestamp into a human readable string according to the current locale.
+ static CExoString FormatUnixTimestamp(uint64_t ts,
+ // %c -> Thu Aug 23 14:55:02 2001 (locale-dependent)
+ // %F %T -> 2001-08-23 14:55:02 (NOT locale-dependent but only numbers)
+ // %x %X -> 08/23/01 14:55:02 (locale-dependent)
+ // see strftime(3) for more
+ const char* format = "%F %T");
+
+ // Split string by delimiter. Strips out empty values and repeated delimiters.
+ static std::vector Split(const CExoString& str, const CExoString& delimiter);
+ std::vector Split(const CExoString& delimiter) const;
+
+ // Join string array by delimiter. Will not join in empty strings.
+ static CExoString Join(const std::vector& ary, const CExoString& delimiter);
+
+ void Clear()
+ {
+ delete[] m_sString;
+ m_sString = 0;
+ m_nBufferLength = 0;
+ }
+ // Explicit move semantics that don't require new C++ features like &&
+ void Steal(CExoString *other)
+ {
+ m_sString = other->m_sString;
+ m_nBufferLength = other->m_nBufferLength;
+ other->m_sString = NULL;
+ other->m_nBufferLength = 0;
+ }
+ char *Relinquish()
+ {
+ char *buf = m_sString;
+ m_sString = NULL;
+ m_nBufferLength = 0;
+ return buf;
+ }
+
+ // *************************************************************************
+private:
+ // *************************************************************************
+ char *m_sString;
+ uint32_t m_nBufferLength;
+
+ //static char *CExoStringFormatBuffer;
+ //static int32_t CExoStringFormatBufferSize;
+};
+
+
+// Allow CExoString to be used as keys for stl maps.
+namespace std {
+template <>
+struct hash
+{
+ std::size_t operator()(const CExoString& k) const
+ {
+ return std::hash{}(k.CStr());
+ }
+};
+}
diff --git a/src/Native Compiler/exostring.cpp b/src/Native Compiler/exostring.cpp
new file mode 100644
index 0000000..6666c7d
--- /dev/null
+++ b/src/Native Compiler/exostring.cpp
@@ -0,0 +1,1576 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+// This file is a reduced variant taken from the base game.
+// Do not port changes here back to the game unless needed for script compiler functionality.
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ExoBase
+//::
+//:: Copyright (c) 1999, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ExoString.cpp
+//::
+//:: String Class
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Don Yakielashek
+//:: Created On: 04/26/99
+//::
+//::///////////////////////////////////////////////////////////////////////////
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+// external header files
+#include "exobase.h"
+
+// We include xxhash.c transitively through other libs which aren't always present (hello borland and macos ARM)
+// So rather than wrangling with the build system, we'll just inline the XXH32 function here. It's small enough.
+#define XXH_INLINE_ALL
+#include "xxhash.h"
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: class CExoString
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+const char* CExoString::Whitespace = " \t\v\r\n\f";
+const char* CExoString::Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+const char* CExoString::Numbers = "0123456789";
+const char* CExoString::Alphanumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString::CExoString()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/26/99
+// Description:Constructor
+///////////////////////////////////////////////////////////////////////////////
+
+// Creates an empty CExoString
+CExoString::CExoString()
+{
+ m_sString = NULL;
+ m_nBufferLength = 0;
+}
+
+// Creates a CExsoString from a null terminated character array
+CExoString::CExoString(const char *source)
+{
+ if (source && ( strlen( source ) > 0 ))
+ {
+ m_nBufferLength = (uint32_t)strlen(source) + 1;
+ m_sString = new char[m_nBufferLength];
+ strcpy(m_sString, source);
+ }
+ else
+ {
+ m_sString = NULL;
+ m_nBufferLength = 0;
+ }
+}
+
+//Creates a copy of a CExoString
+CExoString::CExoString(const CExoString &source)
+{
+ int32_t nSize = 1;
+ if (source.m_sString && ( strlen( source.m_sString ) > 0 ) )
+ {
+ m_nBufferLength = (uint32_t)strlen(source.m_sString) + 1;
+ m_sString = new char[m_nBufferLength];
+ strcpy(m_sString, source.m_sString);
+ }
+ else
+ {
+ m_sString = NULL;
+ m_nBufferLength = 0;
+ }
+}
+
+// Creates a CExoString that contains the first len characters of a CExoString
+CExoString::CExoString(const char *source, int32_t length)
+{
+ if ( length > 0 )
+ {
+ m_nBufferLength = length + 1;
+ m_sString = new char[m_nBufferLength];
+ strncpy(m_sString, source, length);
+ m_sString[length] = '\0';
+ }
+ else
+ {
+ m_sString = NULL;
+ m_nBufferLength = 0;
+ }
+}
+
+// Creates a CExoString representing the int value
+CExoString::CExoString(int32_t value)
+{
+ char buffer[33];
+
+ sprintf( buffer, "%i", value );
+
+ m_nBufferLength = (uint32_t)strlen(buffer) + 1;
+ m_sString = new char[m_nBufferLength];
+ strcpy(m_sString, buffer);
+
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString::~CExoString()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/26/99
+// Description:Destructor
+///////////////////////////////////////////////////////////////////////////////
+CExoString::~CExoString()
+{
+ Clear();
+}
+
+CExoString::CExoString(const std::string& other)
+{
+ if (!other.empty())
+ {
+ m_nBufferLength = other.size() + 1;
+ m_sString = new char[m_nBufferLength];
+ memmove(m_sString, other.data(), m_nBufferLength - 1);
+ m_sString[m_nBufferLength - 1] = '\0';
+ }
+ else
+ {
+ m_sString = NULL;
+ m_nBufferLength = 0;
+ }
+}
+
+CExoString& CExoString::operator=(const std::string& other)
+{
+ if (other.size() > m_nBufferLength - 1)
+ {
+ delete[] m_sString;
+ m_sString = NULL;
+ }
+
+ if (!other.empty())
+ {
+ m_nBufferLength = other.size() + 1;
+ m_sString = new char[m_nBufferLength];
+ memmove(m_sString, other.data(), m_nBufferLength - 1);
+ m_sString[m_nBufferLength - 1] = '\0';
+ }
+ else
+ {
+ m_sString = NULL;
+ m_nBufferLength = 0;
+ }
+
+ return *this;
+}
+
+CExoString::operator std::string() const
+{
+ return m_nBufferLength == 0 ? std::string("") : std::string(m_sString, strlen(m_sString));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: = operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/26/99
+// Description:Assign operator
+///////////////////////////////////////////////////////////////////////////////
+
+// Assigning one CExoString to another
+CExoString & CExoString::operator = (const CExoString& string)
+{
+ if (this == &string)
+ {
+ return *this;
+ }
+
+ if (m_sString)
+ {
+ if (!string.m_sString ||
+ strlen(string.m_sString) + 1 > m_nBufferLength)
+ {
+ Clear();
+ }
+ }
+
+ if (string.m_sString && ( strlen( string.m_sString ) > 0 ))
+ {
+ if (m_sString == NULL)
+ {
+ m_nBufferLength = (uint32_t)strlen(string.m_sString) + 1;
+ m_sString = new char[m_nBufferLength];
+ }
+ strcpy(m_sString, string.m_sString);
+ }
+ else
+ {
+ Clear();
+ }
+ return *this;
+}
+
+// Assigning the value of a null terminated character array to a CExoString
+CExoString & CExoString::operator = (const char *string)
+{
+ if (m_sString)
+ {
+ if (!string ||
+ strlen(string) + 1 > m_nBufferLength)
+ {
+ Clear();
+ }
+ }
+
+ if (string && ( strlen( string ) > 0 ))
+ {
+ if (m_sString == NULL)
+ {
+ m_nBufferLength = (uint32_t)strlen(string) + 1;
+ m_sString = new char[m_nBufferLength];
+ }
+ strcpy(m_sString, string);
+ }
+ else
+ {
+ Clear();
+ }
+ return *this;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: == operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/26/99
+// Description:Equality operator
+///////////////////////////////////////////////////////////////////////////////
+
+// Compares two CExoString's
+BOOL CExoString::operator == (const CExoString &string) const
+{
+ if ( m_sString && string.m_sString )
+ {
+ return (strcmp(m_sString, string.m_sString) == 0);
+ }
+ else
+ {
+ return ( ( ( m_sString == NULL ) && ( string.m_sString == NULL ) ) ||
+ ( m_sString && ( m_sString[0] == '\0' ) ) ||
+ ( string.m_sString && ( string.m_sString[0] == '\0' ) ) );
+ }
+}
+
+// Compares a CExoString to a null terminated character array
+BOOL CExoString::operator == (const char *string) const
+{
+ if ( m_sString && string )
+ {
+ return (strcmp(m_sString, string) == 0);
+ }
+ else
+ {
+ return ( ( ( m_sString == NULL ) && ( string == NULL ) ) ||
+ ( m_sString && ( m_sString[0] == '\0' ) ) ||
+ ( string && ( string[0] == '\0' ) ) );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: != operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Not Equals operator
+///////////////////////////////////////////////////////////////////////////////
+
+// Determines if two CExoString's are not equal
+BOOL CExoString::operator != (const CExoString &string) const
+{
+ if ( m_sString && string.m_sString )
+ {
+ return (strcmp(m_sString, string.m_sString) != 0);
+ }
+ else
+ {
+ return ( ( m_sString && ( m_sString[0] != '\0' ) ) ||
+ ( string.m_sString && ( string.m_sString[0] != '\0' ) ) );
+ }
+}
+
+// Determines if CExoString is not equal to a null terminated character array
+BOOL CExoString::operator != (const char *string) const
+{
+ if ( m_sString && string )
+ {
+ return (strcmp(m_sString, string) != 0);
+ }
+ else
+ {
+ return ( ( m_sString && ( m_sString[0] != '\0' ) ) ||
+ ( string && ( string[0] != '\0' ) ) );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: < operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Less than operator
+///////////////////////////////////////////////////////////////////////////////
+
+// Determines if CExoString is less than another CExoString
+BOOL CExoString::operator < (const CExoString &string) const
+{
+ if ( m_sString && string.m_sString )
+ {
+ return (strcmp(m_sString, string.m_sString) < 0);
+ }
+ else
+ {
+ return ( string.m_sString && ( string.m_sString[0] != '\0' ) );
+ }
+}
+
+// Determines if CExoString is less than a null terminated character array
+BOOL CExoString::operator < (const char *string) const
+{
+ if ( m_sString && string )
+ {
+ return (strcmp(m_sString, string) < 0);
+ }
+ else
+ {
+ return ( string && ( string[0] != '\0' ) );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: > operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Greater than operator
+///////////////////////////////////////////////////////////////////////////////
+
+// Determines if CExoString is greater than another CExoString
+BOOL CExoString::operator > (const CExoString &string) const
+{
+ if ( m_sString && string.m_sString )
+ {
+ return (strcmp(m_sString, string.m_sString) > 0);
+ }
+ else
+ {
+ return ( m_sString && ( m_sString[0] != '\0' ) );
+ }
+}
+
+// Determines if CExoString is greater than a null terminated character array
+BOOL CExoString::operator > (const char *string) const
+{
+ if ( m_sString && string )
+ {
+ return (strcmp(m_sString, string) > 0);
+ }
+ else
+ {
+ return ( m_sString && ( m_sString[0] != '\0' ) );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: <= operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Less than or equal to operator
+///////////////////////////////////////////////////////////////////////////////
+
+// Determines if CExoString is less than or equal to another CExoString
+BOOL CExoString::operator <= (const CExoString &string) const
+{
+ if ( m_sString && string.m_sString )
+ {
+ return (strcmp(m_sString, string.m_sString) <= 0);
+ }
+ else
+ {
+ return ( ( ( m_sString == NULL ) && ( string.m_sString == NULL ) ) ||
+ ( m_sString && ( m_sString[0] == '\0' ) ) ||
+ ( string.m_sString ) );
+ }
+}
+
+// Determines if CExoString is less then or equal to a null terminated character array
+BOOL CExoString::operator <= (const char *string) const
+{
+ if ( m_sString && string )
+ {
+ return (strcmp(m_sString, string) <= 0);
+ }
+ else
+ {
+ return ( ( ( m_sString == NULL ) && ( string == NULL ) ) ||
+ ( m_sString && ( m_sString[0] == '\0' ) ) ||
+ ( string ) );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: >= operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Greater than or equal to operator
+///////////////////////////////////////////////////////////////////////////////
+
+// Determines if CExoString is greater than or equal to another CExoString
+BOOL CExoString::operator >= (const CExoString &string) const
+{
+ if ( m_sString && string.m_sString )
+ {
+ return (strcmp(m_sString, string.m_sString) >= 0);
+ }
+ else
+ {
+ return ( ( ( m_sString == NULL ) && ( string.m_sString == NULL ) ) ||
+ ( string.m_sString && ( string.m_sString[0] == '\0' ) ) ||
+ ( m_sString ) );
+ }
+}
+
+// Determines if CExoString is greater then or equal to a null terminated character array
+BOOL CExoString::operator >= (const char *string) const
+{
+ if ( m_sString && string )
+ {
+ return (strcmp(m_sString, string) >= 0);
+ }
+ else
+ {
+ return ( ( ( m_sString == NULL ) && ( string == NULL ) ) ||
+ ( string && ( string[0] == '\0' ) ) ||
+ ( m_sString ) );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: [] operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Retuns character at position
+///////////////////////////////////////////////////////////////////////////////
+char CExoString::operator [] (int32_t position) const
+{
+ if ((position < 0) || !m_sString || (strlen(m_sString) <= ((uint32_t) position)))
+ {
+ return '\0';
+ }
+ else
+ {
+ return m_sString[position];
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: + operator
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/30/99
+// Description:Joins two strings
+///////////////////////////////////////////////////////////////////////////////
+
+// Returns the result of two CExoString joined together
+CExoString CExoString::operator + (const CExoString &string) const
+{
+ CExoString newStr;
+ uint32_t stringLength, m_sStringLength;
+
+ if ( string.m_sString )
+ {
+ stringLength = (uint32_t)strlen(string.m_sString);
+ }
+ else
+ {
+ stringLength = 0;
+ }
+
+ if ( m_sString )
+ {
+ m_sStringLength = (uint32_t)strlen(m_sString);
+ }
+ else
+ {
+ m_sStringLength = 0;
+ }
+
+ if ( ( stringLength == 0 ) && ( m_sStringLength == 0 ) )
+ {
+ return newStr;
+ }
+
+ if (newStr.m_sString)
+ {
+ // MGB - November 27, 2001 - Should never call this.
+ EXOASSERT(FALSE);
+ delete[] newStr.m_sString;
+ newStr.m_sString = NULL;
+ newStr.m_nBufferLength = 0;
+ }
+
+ if (stringLength == 0)
+ {
+ newStr.m_nBufferLength = m_sStringLength + 1;
+ newStr.m_sString = new char[newStr.m_nBufferLength];
+
+ strcpy(newStr.m_sString, m_sString);
+ return newStr;
+ }
+
+ if (m_sStringLength == 0)
+ {
+ newStr.m_nBufferLength = stringLength + 1;
+ newStr.m_sString = new char[newStr.m_nBufferLength];
+
+ strcpy(newStr.m_sString, string.m_sString);
+ return newStr;
+ }
+
+ newStr.m_nBufferLength = m_sStringLength + stringLength + 1;
+ newStr.m_sString = new char[newStr.m_nBufferLength];
+ strcpy(newStr.m_sString, m_sString);
+ strcat(newStr.m_sString, string.m_sString);
+ return newStr;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: AsINT()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Howard Chung
+// Created On: 05/15/2001
+// Desc: Retuns integer value the string represents.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CExoString::AsINT() const
+{
+ if ( m_sString )
+ {
+ return atoi( m_sString );
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: AsINT()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Howard Chung
+// Created On: 05/15/2001
+// Desc: Retuns float value the string represents.
+///////////////////////////////////////////////////////////////////////////////
+float CExoString::AsFLOAT() const
+{
+ if ( m_sString )
+ {
+ return (float)atof( m_sString );
+ }
+ else
+ {
+ return 0.0f;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: CStr()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/27/99
+// Description:Retuns a null terminated character array
+///////////////////////////////////////////////////////////////////////////////
+static char g_szEmptyString[1] = { 0 };
+char* CExoString::CStr() const
+{
+ //EXOWARNINGSTR( m_sString != NULL, "CExoString::CStr(): Obtaining NULL pointer from CExoString." );
+
+ if ( m_sString == NULL )
+ {
+ return g_szEmptyString;
+ }
+
+ return m_sString;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: Find()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 05/27/99
+// Description:Finds a substring within the string
+///////////////////////////////////////////////////////////////////////////////
+int32_t CExoString::Find(const CExoString &string, int32_t position) const
+{
+ int32_t cnt, matchLen;
+ char *pChar;
+
+ if ( !m_sString || !string.m_sString || position < 0 )
+ {
+ return -1;
+ }
+
+ pChar = m_sString;
+ for (cnt=0; cnt m_nBufferLength)
+ {
+ Clear();
+ m_nBufferLength = requiredSize + 1;
+ m_sString = new char[m_nBufferLength];
+ }
+
+ strncpy(m_sString, CExoStringFormatBuffer, requiredSize);
+ m_sString[requiredSize] = 0;
+
+ va_end(argList);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: Insert()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Inserts a string at the given position
+///////////////////////////////////////////////////////////////////////////////
+
+void CExoString::Insert(const CExoString &string, int32_t position)
+{
+ char *newStr, *pStr;
+ uint32_t stringLength, m_sStringLength;
+
+ if ( !string.m_sString )
+ {
+ return;
+ }
+
+ stringLength = (uint32_t)strlen(string.m_sString);
+
+ if ( m_sString )
+ {
+ m_sStringLength = (uint32_t)strlen(m_sString);
+ }
+ else
+ {
+ m_sStringLength = 0;
+ }
+
+ if (stringLength == 0)
+ {
+ return;
+ }
+
+ if ((position < 0) || (m_sStringLength <= ((uint32_t) position)))
+ {
+ return;
+ }
+
+ // allocate new string
+ m_nBufferLength = m_sStringLength + stringLength + 1;
+ newStr = new char[m_nBufferLength];
+ newStr[0] = '\0';
+
+ // swap pointer to existing string with pointer to new string
+ pStr = m_sString;
+ m_sString = newStr;
+ newStr = pStr;
+
+ // insert string
+ if ( pStr )
+ {
+ strncpy(m_sString, pStr, position);
+ }
+ m_sString[position] = '\0';
+ strcat(m_sString, string.m_sString);
+ strcat(m_sString, &pStr[position]);
+
+ // delete old string
+ if (pStr)
+ {
+ delete[] pStr;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: IsEmpty()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Checks if CExoString is a blank string
+///////////////////////////////////////////////////////////////////////////////
+
+BOOL CExoString::IsEmpty() const
+{
+ return ( !m_sString || (m_sString[0] == '\0') );
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: Left()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/28/99
+// Description:Returns Leftmost 'count' characters
+///////////////////////////////////////////////////////////////////////////////
+
+CExoString CExoString::Left(int32_t count) const
+{
+ CExoString newStr;
+ int32_t count2;
+ uint32_t m_sStringLength;
+
+ if ( !m_sString )
+ {
+ return newStr;
+ }
+
+ m_sStringLength = (uint32_t)strlen(m_sString);
+
+ count2 = count;
+
+ if (count2 < 0)
+ {
+ return newStr;
+ }
+
+ if (m_sStringLength == 0)
+ {
+ return newStr;
+ }
+ if (((uint32_t) count2) > m_sStringLength)
+ {
+ count2 = m_sStringLength;
+ }
+
+ if (newStr.m_sString)
+ {
+ delete[] newStr.m_sString;
+ }
+ newStr.m_sString = new char[count2+1];
+ strncpy(newStr.m_sString, m_sString, count2);
+ newStr.m_sString[count2] = '\0';
+ return newStr;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: LowerCase()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 05/28/99
+// Description:Returns the string converted to lowsercase
+///////////////////////////////////////////////////////////////////////////////
+CExoString CExoString::LowerCase() const
+{
+ CExoString newStr;
+ int32_t nPos;
+
+ if ( !m_sString )
+ {
+ return newStr;
+ }
+
+ newStr.m_nBufferLength = GetLength() + 1;
+ newStr.m_sString = new char[newStr.m_nBufferLength];
+ nPos = 0;
+ while (m_sString[nPos] != 0)
+ {
+ if (m_sString[nPos] >= 'A' && m_sString[nPos] <= 'Z')
+ {
+ newStr.m_sString[nPos] = m_sString[nPos] - 'A' + 'a';
+ }
+ else
+ {
+ newStr.m_sString[nPos] = m_sString[nPos];
+ }
+ nPos++;
+ }
+ newStr.m_sString[nPos] = 0;
+
+ return newStr;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: Right()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 04/30/99
+// Description:Returns Rightmost 'count' characters
+///////////////////////////////////////////////////////////////////////////////
+
+CExoString CExoString::Right(int32_t count) const
+{
+ CExoString newStr;
+ int32_t count2;
+ uint32_t m_sStringLength;
+
+ if ( !m_sString )
+ {
+ return newStr;
+ }
+
+ m_sStringLength = (uint32_t)strlen(m_sString);
+
+ count2 = count;
+
+ if (count2 < 0)
+ {
+ return newStr;
+ }
+ if (m_sStringLength == 0)
+ {
+ return newStr;
+ }
+ if (((uint32_t) count2) > m_sStringLength)
+ {
+ count2 = m_sStringLength;
+ }
+
+ if (newStr.m_sString)
+ {
+ delete[] newStr.m_sString;
+ }
+ newStr.m_sString = new char[count2+1];
+ strncpy(newStr.m_sString, &(m_sString[m_sStringLength-count2]), count2);
+ newStr.m_sString[count2] = '\0';
+ return newStr;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: SubString()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 05/27/99
+// Description:Returns a portion of string consisting of 'count' characters
+// starting at 'start', count<0 means extract to end of string
+///////////////////////////////////////////////////////////////////////////////
+CExoString CExoString::SubString(int32_t start, int32_t count) const
+{
+ CExoString newStr;
+ int32_t count2;
+ uint32_t m_sStringLength;
+
+ if ( !m_sString )
+ {
+ return newStr;
+ }
+
+ m_sStringLength = (uint32_t)strlen(m_sString);
+
+ if ((start < 0) || (((uint32_t)start) >= m_sStringLength) || (count==0))
+ {
+ return newStr;
+ }
+
+ if (count < 0) // extract to end of string
+ {
+ count = m_sStringLength - start;
+ }
+
+ count2 = count;
+
+ if (((uint32_t) start + count2) > m_sStringLength)
+ {
+ count2 = m_sStringLength - start;
+ }
+
+ if (newStr.m_sString)
+ {
+ delete[] newStr.m_sString;
+ }
+ newStr.m_sString = new char[count+1];
+ newStr.m_nBufferLength = count+1;
+
+ strncpy(newStr.m_sString, &(m_sString[start]), count);
+ newStr.m_sString[count] = '\0';
+ return newStr;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString:: UpperCase()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Don Yakielashek
+// Created On: 05/28/99
+// Description:Returns the string converted to uppercase
+///////////////////////////////////////////////////////////////////////////////
+CExoString CExoString::UpperCase() const
+{
+ CExoString newStr;
+ int32_t nPos;
+
+ if ( !m_sString )
+ {
+ return newStr;
+ }
+
+ newStr.m_nBufferLength = GetLength() + 1;
+ newStr.m_sString = new char[newStr.m_nBufferLength];
+ nPos = 0;
+ while (m_sString[nPos] != 0)
+ {
+ if (m_sString[nPos] >= 'a' && m_sString[nPos] <= 'z')
+ {
+ newStr.m_sString[nPos] = m_sString[nPos] - 'a' + 'A';
+ }
+ else
+ {
+ newStr.m_sString[nPos] = m_sString[nPos];
+ }
+ nPos++;
+ }
+ newStr.m_sString[nPos] = 0;
+
+ return newStr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString::CompareNoCase()
+///////////////////////////////////////////////////////////////////////////////
+// Owned By: Mark Brockington
+// Description:Returns whether the two strings are the same, irrespective
+// of case.
+///////////////////////////////////////////////////////////////////////////////
+BOOL CExoString::CompareNoCase(const CExoString &string) const
+{
+ char *pStringChar;
+ char *pThisStringChar;
+ int32_t nLenString, cnt;
+
+ pStringChar = string.m_sString;
+ nLenString = string.GetLength();
+
+ pThisStringChar = m_sString;
+
+ if (pStringChar == NULL && pThisStringChar == NULL)
+ {
+ return TRUE;
+ }
+ else if (pStringChar == NULL || pThisStringChar == NULL)
+ {
+ return FALSE;
+ }
+ else if (nLenString != GetLength())
+ {
+ return FALSE;
+ }
+
+ for (cnt=0; cnt= 'A' && pStringChar[cnt] <= 'Z')
+ {
+ if (pStringChar[cnt] - 'A' + 'a' != pThisStringChar[cnt])
+ {
+ return FALSE;
+ }
+ }
+ else if (pThisStringChar[cnt] >= 'A' && pThisStringChar[cnt] <= 'Z')
+ {
+ if (pThisStringChar[cnt] - 'A' + 'a' != pStringChar[cnt])
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString::ComparePrefixNoCase()
+///////////////////////////////////////////////////////////////////////////////
+// Owned By: Mark Brockington
+// Description:Returns whether the two strings are the same, irrespective
+// of case.
+///////////////////////////////////////////////////////////////////////////////
+BOOL CExoString::ComparePrefixNoCase(const CExoString &string, int32_t nSize) const
+{
+ char *pStringChar = string.CStr();
+ char *pThisStringChar = m_sString;
+
+ if (pStringChar == NULL && pThisStringChar == NULL)
+ {
+ return TRUE;
+ }
+ else if (pStringChar == NULL || pThisStringChar == NULL)
+ {
+ return FALSE;
+ }
+
+ return !(strnicmp(pStringChar,pThisStringChar,nSize));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString::StripNonAlphaNumeric
+///////////////////////////////////////////////////////////////////////////////
+// Created by: Paul Roffel
+// Created on: April 29, 2002
+// Desc.: Removes all non-alpha-numeric symbols from the string
+///////////////////////////////////////////////////////////////////////////////
+BOOL CExoString::StripNonAlphaNumeric( BOOL bFileName, BOOL bEmail, BOOL bMasterServer )
+{
+ uint32_t cnt, cnt2, max;
+ BOOL bChanged = FALSE;
+ char szTester[128];
+
+ if ( !m_sString )
+ {
+ return FALSE;
+ }
+
+ max = (uint32_t)strlen(m_sString);
+ if ( max == 0 )
+ {
+ return FALSE;
+ }
+
+ if ( bFileName )
+ {
+ strcpy(szTester,
+ "abcdefghijklmnopqrstuvwxyz0123456789'"
+ "\xdf\xe9\xc9\xe8\xc8\xc7\xe7\xf9\xd9\xf1\xd1\xe0\xc0\xc4\xe4\xdc\xfc\xd6\xf6"
+ "_-");
+ }
+ else
+ {
+ strcpy( szTester, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" );
+ }
+
+ if ( bEmail )
+ {
+ strcat( szTester, "@." );
+ }
+
+ if ( bMasterServer ) // 5/18/02 - PLR - Characters allowed on the master server.
+ {
+ strcat(szTester,
+ ".',"
+ "\xdf\xe9\xc9\xe8\xc8\xc7\xe7\xf9\xd9\xf1\xd1\xe0\xc0\xc4\xe4\xdc\xfc\xd6\xf6"
+ "_- ");
+ }
+
+ for ( cnt = 0; cnt < max ; cnt++ )
+ {
+ if ( bFileName ) // 5/18/02 - PLR - Filenames must be converted to lowercase now... *sigh*
+ {
+ if (m_sString[cnt] >= 'A' && m_sString[cnt] <= 'Z')
+ {
+ m_sString[cnt] = m_sString[cnt] - 'A' + 'a';
+ }
+ }
+
+ // MGB - August 3, 2016 - Remove all leading spaces and periods.
+ if ( (cnt == 0 && (m_sString[cnt] == '.' || m_sString[cnt] == ' ') ) ||
+ strchr( szTester, m_sString[cnt] ) == NULL
+ )
+ {
+ for ( cnt2 = cnt ; cnt2 < max ; cnt2++ )
+ {
+ m_sString[cnt2] = m_sString[cnt2+1];
+ }
+ cnt--;
+ max--;
+ bChanged = TRUE;
+ }
+ }
+
+ return bChanged;
+}
+
+CExoString CExoString::Strip(bool leading, bool trailing, const char* set) const
+{
+ int start = 0;
+ int end = GetLength();
+
+ while (leading && start < GetLength() && strchr(set, (*this)[start]))
+ start++;
+
+ while (trailing && end > 0 && strchr(set, (*this)[end - 1]))
+ end--;
+
+ return SubString(start, end - start);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CExoString::AsTAG
+///////////////////////////////////////////////////////////////////////////////
+// Created by: Paul Roffel
+// Created on: Monday, January 27, 2003
+// Desc.: Returns the string as a tag.
+// This is directly from code used in the toolset.
+// TNWGlobal::GetTagFromArbitraryString
+///////////////////////////////////////////////////////////////////////////////
+CExoString CExoString::AsTAG() const
+{
+ uint32_t cnt, max;
+ CExoString newStr;
+ char newBuffer[64];
+ int32_t nIndex = 0;
+
+ if ( !m_sString )
+ {
+ return newStr;
+ }
+
+ max = (uint32_t)strlen(m_sString);
+
+ for ( cnt = 0 ; cnt < max ; cnt++ )
+ {
+ if ( isalnum(m_sString[cnt]) || m_sString[cnt] == '_' )
+ {
+ newBuffer[nIndex++] = m_sString[cnt];
+ if ( nIndex > 62 ) //CNWSTAGNODE_TAG_LENGTH
+ {
+ break;
+ }
+ }
+ }
+ newBuffer[nIndex] = '\0';
+ newStr = newBuffer;
+
+ // PATCH:: Modified _DEBUG macro
+#ifdef _DEBUG_EXOSTRING // 01/27/03 - PLR - Need to debug this properly!
+ if ( newStr != m_sString )
+ {
+ LOGSET("TAG CHANGE ===> (%s) -> (%s)\n", m_sString, newStr.CStr())LOGFLUSH
+ }
+#endif
+
+ return newStr;
+}
+
+int32_t CExoString::GetHash() const
+{
+ // Having the hash of an empty string return zero is a useful property, so we XOR every
+ // hash with the hash of a null string. This has no cryptographic effect since the
+ // bit entropy remains the same. Not that XXH is cryptographically secure.
+ const static int32_t nullhash = (int32_t)XXH32("", 0, 0);
+ return (int32_t)XXH32(CStr(), GetLength(), 0) ^ nullhash;
+}
+
+
+CExoString CExoString::FormatBytes(uint64_t bytes)
+{
+ CExoString ret;
+ const char* suffixes[7];
+ suffixes[0] = "B";
+ suffixes[1] = "KB";
+ suffixes[2] = "MB";
+ suffixes[3] = "GB";
+ suffixes[4] = "TB";
+ suffixes[5] = "PB";
+ suffixes[6] = "EB";
+ unsigned int s = 0; // which suffix to use
+ double count = (double) bytes;
+ while (count >= 1024 && s < 7)
+ {
+ s++;
+ count /= 1024;
+ }
+ if (count - floor(count) == 0.0)
+ ret.Format("%d %s", (int)count, suffixes[s]);
+ else
+ ret.Format("%.1f %s", count, suffixes[s]);
+ return ret;
+}
+
+CExoString CExoString::FormatDuration(uint64_t span,
+ int compact_levels,
+ int min_levels,
+ bool label_fields,
+ const char* separator)
+{
+ const uint64_t days = span / 3600 / 24;
+ const uint64_t hours = span / 3600 - (days * 24);
+ const uint64_t minutes = span / 60 - (hours * 60) - (days * 24 * 60);
+ const uint64_t seconds = span - (minutes * 60) - (hours * 3600) - (days * 24 * 3600);
+
+ //if (compact_less_than_1m && span < 60)
+ //{
+ // ret.Format(" <1m");
+ //}
+ //else
+
+ int levels_shown = 0;
+
+ CExoString ret;
+
+ if ((days > 0 || min_levels > 3) && compact_levels > levels_shown)
+ {
+ ret.Format("%s%s%llu%s", ret.CStr(), separator, days, label_fields ? "d" : "");
+ levels_shown++;
+ }
+ if ((hours > 0 || min_levels > 2) && compact_levels > levels_shown)
+ {
+ ret.Format("%s%s%llu%s", ret.CStr(), separator, hours, label_fields ? "h" : "");
+ levels_shown++;
+ }
+ if ((minutes > 0 || min_levels > 1) && compact_levels > levels_shown)
+ {
+ ret.Format("%s%s%llu%s", ret.CStr(), separator, minutes, label_fields ? "m" : "");
+ levels_shown++;
+ }
+ if ((seconds > 0 || min_levels > 0) && compact_levels > levels_shown)
+ {
+ ret.Format("%s%s%llu%s", ret.CStr(), separator, seconds, label_fields ? "s" : "");
+ levels_shown++;
+ }
+
+ return ret.SubString(strlen(separator));
+}
+
+CExoString CExoString::FormatUnixTimestamp(uint64_t ts, const char* format)
+{
+ char buffer[1025] = {0};
+ auto t = localtime((time_t*) &ts);
+ if (ts > 0 && t)
+ strftime(buffer, 1024, format, t);
+ else
+ sprintf(buffer, "-");
+
+ return buffer;
+}
+
+std::vector CExoString::Split(const CExoString& strin, const CExoString& delimiter)
+{
+ std::vector ret;
+
+ const std::string str = strin;
+ const std::string delim = delimiter;
+
+ size_t prev = 0, pos = 0;
+ do
+ {
+ pos = str.find(delim, prev);
+ if (pos == std::string::npos)
+ {
+ pos = str.length();
+ }
+ std::string token = str.substr(prev, pos-prev);
+ if (!token.empty())
+ {
+ ret.push_back(token);
+ }
+ prev = pos + delim.length();
+ }
+ while (pos < str.length() && prev < str.length());
+
+ return ret;
+}
+
+std::vector CExoString::Split(const CExoString& delimiter) const
+{
+ return CExoString::Split(*this, delimiter);
+}
+
+CExoString CExoString::Join(const std::vector& arin, const CExoString& delimiter)
+{
+ std::ostringstream ret;
+
+ for (unsigned i = 0; i < arin.size(); i++)
+ {
+ if (!arin[1].IsEmpty())
+ {
+ ret << arin[i].CStr();
+ if (i < arin.size() - 1)
+ {
+ ret << delimiter.CStr();
+ }
+ }
+ }
+
+ return ret.str();
+}
diff --git a/src/Native Compiler/exotypes.h b/src/Native Compiler/exotypes.h
new file mode 100644
index 0000000..a20ff55
--- /dev/null
+++ b/src/Native Compiler/exotypes.h
@@ -0,0 +1,97 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+#pragma once
+
+// This file is a reduced variant taken from the base game.
+// Do not port changes here back to the game unless needed for script compiler functionality.
+
+// WIN32 don't clobber std::min/max.
+// This is not what we need in our life.
+//#define NOMINMAX
+
+#include
+#include
+#include
+#include
+
+typedef int BOOL;
+typedef uint32_t STRREF;
+typedef uint32_t OBJECT_ID;
+typedef uint16_t RESTYPE;
+
+#define FALSE 0
+#define TRUE 1
+
+#define INVALID_OBJECT_ID 0x7f000000
+#define RESTYPE_INVALID 0xFFFF
+
+#define MINSHORT 0x8000
+#define MAXSHORT 0x7fff
+#define MAXWORD 0xffff
+#define MAXDWORD 0xffffffff
+#define MAXBYTE 0xff
+
+
+#include
+
+// N.B.: C++98 functions only, see http://en.cppreference.com/w/cpp/algorithm
+
+// Some external libraries (like mss) define their own min/max.
+// This is not what we need in our life.
+#undef min
+#undef max
+#undef clamp
+
+// Legacy. N.B.: semantics changed, now uses < internally. Should not
+// have *any* effect as it's only used to compare numbers.
+// Left here because used in a LOT of places, and it's bad to break
+// assumptions.
+#define NWN_max(a,b) (std::max)(a,b)
+#define NWN_min(a,b) (std::min)(a,b)
+
+// PATCH: __cplusplus macro is defined as 1999 still by Microsoft. We disable here.
+#ifdef DONT_USE_CPLUSPLUC
+
+// This would be in in c++17.
+#if __cplusplus < 201500
+namespace std
+{
+ // Returns value n clamped to inclusive (l, n). Works with any
+ // type that the compiler knows how to compare.
+ template const T& clamp(const T& n, const T& l, const T& h)
+ {
+ return std::max(l, std::min(n, h));
+ }
+
+ // Returns value n clamped to inclusive (l, n).
+ //
+ // Uses Cmp to compare, where Cmp is:
+ // bool(const Type1 &a, const Type2 &b);
+ // Where Type1 and Type2 are implicitly convertible.
+ template const T& clamp(const T& n, const T& l,
+ const T& h, Cmp cmp)
+ {
+ return std::max(l, std::min(n, h, cmp), cmp);
+ }
+};
+#endif
+
+#endif
+#if ((defined __linux__) || (defined __APPLE__))
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif // LINUX
diff --git a/src/Native Compiler/gpl-3.0.txt b/src/Native Compiler/gpl-3.0.txt
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/src/Native Compiler/gpl-3.0.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/src/Native Compiler/scriptcomp.h b/src/Native Compiler/scriptcomp.h
new file mode 100644
index 0000000..0a1032a
--- /dev/null
+++ b/src/Native Compiler/scriptcomp.h
@@ -0,0 +1,644 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+#pragma once
+
+#include
+
+#include "exobase.h"
+#include "scripterrors.h"
+
+// Classes defined in scriptinternal.h
+class CScriptParseTreeNode;
+class CScriptParseTreeNodeBlock;
+class CScriptCompilerStackEntry;
+class CScriptCompilerIdListEntry;
+class CScriptSourceFile;
+class CScriptCompilerVarStackEntry;
+class CScriptCompilerStructureEntry;
+class CScriptCompilerStructureFieldEntry;
+class CScriptCompilerSymbolTableEntry;
+class CScriptCompilerKeyWordEntry;
+class CScriptCompilerIdentifierHashTableEntry;
+
+// Defines required for static size of values.
+#define CSCRIPTCOMPILER_MAX_TABLE_FILENAMES 512
+#define CSCRIPTCOMPILER_MAX_TOKEN_LENGTH 8192
+#define CSCRIPTCOMPILER_MAX_INCLUDE_LEVELS 16
+#define CSCRIPTCOMPILER_MAX_RUNTIME_VARS 8192
+
+#define CSCRIPTCOMPILERIDLISTENTRY_MAX_PARAMETERS 32
+
+//
+// Compiler optimization flags.
+// Note that some optimizations might interfere with NDB generation.
+//
+
+// Removes any functions that cannot possibly be called by any codepath
+#define CSCRIPTCOMPILER_OPTIMIZE_DEAD_FUNCTIONS 0x00000001
+// Merges constant expressions into a single constant where possible.
+// Note: Only affects runtime expressions, assignments to const variables are always folded.
+#define CSCRIPTCOMPILER_OPTIMIZE_FOLD_CONSTANTS 0x00000002
+// Post processes generated instructions to merge sequences into shorter equivalents
+#define CSCRIPTCOMPILER_OPTIMIZE_MELD_INSTRUCTIONS 0x00000004
+
+#define CSCRIPTCOMPILER_OPTIMIZE_NOTHING 0x00000000
+#define CSCRIPTCOMPILER_OPTIMIZE_EVERYTHING 0xFFFFFFFF
+
+
+class CScriptCompilerIncludeFileStackEntry
+{
+public:
+ CExoString m_sCompiledScriptName;
+ CExoString m_sSourceScript;
+
+ // A stack of internal variables (used when processing includes to preserve
+ // the previous state of the scripting language).
+ int32_t m_nLine;
+ int32_t m_nCharacterOnLine;
+ int32_t m_nTokenStatus;
+ int32_t m_nTokenCharacters;
+};
+
+class CScriptCompiler;
+
+// Functions you need to implement when invoking script compiler.
+// Default impl for game is in scriptcompapi.cpp.
+struct CScriptCompilerAPI
+{
+ CScriptCompilerAPI() { memset(this, 0, sizeof(CScriptCompilerAPI)); }
+
+ // Update resman resource dir (reload/reindex).
+ BOOL (*ResManUpdateResourceDirectory)(const char* sAlias);
+
+ // Return 0 if OK, or error STRREF on failure (scripterrors.h)
+ int32_t (*ResManWriteToFile)(const char* sFileName, RESTYPE nResType, const uint8_t* pData, size_t nSize, bool bBinary);
+
+ // Read the given filename+restype from resman, and return a zero-terminated string containing
+ // the content (up to the first null terminator). Returns nullptr if the file cannot be read/loaded.
+ // The returned string is a global static buffer and must not be freed by you.
+ // Repeated calls to this function will replace the buffer.
+ // Please see the default impl in scriptcompapi.cpp for load semantics (e.g. it will serve up .nss files for .css files when not found).
+ const char* (*ResManLoadScriptSourceFile)(const char* sFileName, RESTYPE nResType);
+
+ // Returns zero-terminated string, or "" if lookup failed.
+ // The returned string is a global static buffer and must not be freed by you.
+ // Repeated calls to this function will replace the buffer.
+ const char* (*TlkResolve)(STRREF strRef);
+};
+
+
+class CScriptCompiler
+{
+ // This can be left unimplemented on custom compilers, as long as you provide
+ // callbacks to the constructor,
+ static CScriptCompilerAPI MakeDefaultAPI();
+
+ CScriptCompilerAPI m_cAPI;
+
+ // *************************************************************************
+public:
+ // *************************************************************************
+ explicit CScriptCompiler(RESTYPE nSource, RESTYPE nCompiled, RESTYPE nDebug,
+ // When not given, uses default API as defined in scriptcompapi.cpp.
+ // This is a concession to not changing all callsites.
+ CScriptCompilerAPI api = MakeDefaultAPI());
+ ~CScriptCompiler();
+
+ ///////////////////////////////////////////////////////////////////////
+ void SetIdentifierSpecification(const CExoString &sLanguageSource);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will set the identifier specification that you
+ // want to use when compiling.
+ //
+ // sLanguageSource: (IN) An .nss file containing the definition of
+ // the language
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ void SetOutputAlias(const CExoString &sAlias);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will set the alias used by CompileFile to
+ // determine where to write the output code.
+ //
+ // sAlias: (See ExoAlias for a description of how the aliases are
+ // used.) This alias will be used by ExoResMan to target
+ // the output of the code.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ void SetGenerateDebuggerOutput(int32_t nValue);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will determine whether a .ndb file will also
+ // be generated at the same time as the .ncs file.
+ //
+ // nValue: (IN) A value to determine the type of output.
+ //
+ // 0: No .ndb file will be generated.
+ // 1: An .ndb file will be generated. This information, in
+ // addition to the .ncs file, will allow the debugger to
+ // behave correctly.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ void SetOptimizationFlags(uint32_t nFlags) { m_nOptimizationFlags = nFlags; }
+ uint32_t GetOptimizationFlags() { return m_nOptimizationFlags; }
+
+ ///////////////////////////////////////////////////////////////////////
+ void SetAutomaticCleanUpAfterCompiles(BOOL bValue);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will determine whether CompileFile will make
+ // automatic updates to the Output Directory in the resouce
+ // manager, and clean up large buffers used to compile a file.
+ //
+ // nValue: (IN) A value to determine the type of output.
+ //
+ // FALSE: Does not attempt to call the resource manager to
+ // update the output directory. If you set this value
+ // to false, you are responsible for calling
+ // CScriptCompiler::CleanUpAfterCompiles() before
+ // you attempt to use these files.
+ //
+ // TRUE (default): After each .ncs and .ndb file is created,
+ // the directory where the file is created is updated
+ // in the resource manager and some "memory leaks" are
+ // removed. This is the best choice if you don't know
+ // how to use this. (Other than actually talking to
+ // Mark, or looking in the Test_CompileAllFilesInDirectory
+ // function for how to use a value of FALSE correctly!)
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ void CleanUpAfterCompiles();
+ //---------------------------------------------------------------------
+ // Desc.: This routine will update the output directory (set by
+ // CScriptCompiler::SetOutputAlias). This is required to be
+ // done before you can access any files compiled with
+ // CleanUpAfterCompiles set to FALSE. It will also delete any
+ // buffers created during compilation that are required.
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ void SetCompileConditionalFile(BOOL nValue);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will set the type of output generated by the
+ // parsing routine.
+ //
+ // nValue: (IN) A value to determine the type of output.
+ //
+ // 0: Will compile files that have a "void main()" in them.
+ //
+ // 1: Will compile files that have an
+ // "int StartingConditional()" in them.
+ //
+ // An error will result, depending on the value of this
+ // parameter, if the wrong type of file is attempted to be
+ // passed through CompileFile()
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ void SetCompileConditionalOrMain(BOOL nValue);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will set the type of output generated by the
+ // parsing routine.
+ //
+ // bValue: (IN) A value to determine the type of output.
+ //
+ // 0: Will compile files based on CompileConditionalFile.
+ //
+ // 1: Will compile files that have a void main() by
+ // preference. It will compile int StartingConditional()
+ // files if we can't find a void main() function.
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ int32_t CompileFile(const CExoString &sFileName);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will generate whether the code in the file
+ // specified in sFileName is a valid Script, and then write
+ // the output to sFileName.ncs
+ //
+ // sFileName: (IN) The name of the file to compile.
+ //
+ // Returns: 0 if the script is valid and output has been generated,
+ // and a value other than zero if there is an error during
+ // compilation!
+ //
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ int32_t CompileScriptChunk(const CExoString &sScriptChunk, BOOL bWrapIntoMain);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will attempt to generate code from the string
+ // passed in.
+ //
+ // sFileName: (IN) The script to compile.
+ //
+ // Returns: 0 if the script is valid, and a value other than zero if
+ // there is an error during parsing.
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ int32_t CompileScriptConditional(const CExoString &sScriptConditional);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will generate whether the code in the string
+ // specified (sStringData) is a valid Script.
+ //
+ // sFileName: (IN) The script to compile.
+ //
+ // Returns: 0 if the script is valid, and a value other than zero if
+ // there is an error during parsing.
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ int32_t GetCompiledScriptCode(char **pnCode, int32_t *nCodeSize);
+ //---------------------------------------------------------------------
+ // Desc.: This routine will allow you to access the code generated by
+ // CompileScript
+ //
+ // pnCode [OUT]: Will point to the new location of the code.
+ //
+ // nCodeSize [OUT]: Will point to the size of the new code.
+ //
+ // Returns: 0 if successful, non-zero if there is no code available.
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ void ClearCompiledScriptCode();
+ //---------------------------------------------------------------------
+ // Desc.: This routine will remove the code that has been run.
+ ///////////////////////////////////////////////////////////////////////
+
+ // Returns the captured error string for use by tools that don't need
+ // to access the log.
+ CExoString *GetCapturedError() { return &m_sCapturedError; }
+
+ STRREF GetCapturedErrorStrRef() const { return m_nCapturedErrorStrRef; }
+
+ int32_t WriteFinalCodeToFile(const CExoString &sFileName);
+ int32_t WriteDebuggerOutputToFile(CExoString sFileName);
+
+ // *************************************************************************
+private:
+ // *************************************************************************
+
+ RESTYPE m_nResTypeSource;
+ RESTYPE m_nResTypeCompiled;
+ RESTYPE m_nResTypeDebug;
+
+ void Initialize();
+ void ShutDown();
+
+ uint32_t HashString(const CExoString &sString);
+ uint32_t HashString(const char *pString);
+ void InitializePreDefinedStructures();
+ void InitializeIncludeFile(int32_t nCompileFileLevel);
+ void ShutdownIncludeFile(int32_t nCompileFileLevel);
+
+ void TokenInitialize();
+
+ void PushSRStack(int32_t nState, int32_t nRule, int32_t nTerm,
+ CScriptParseTreeNode *pCurrentTree);
+ int32_t PopSRStack(int32_t *nState,int32_t *nRule, int32_t *nTerm,
+ CScriptParseTreeNode **pCurrentTree,
+ CScriptParseTreeNode **pReturnTree );
+ void ModifySRStackReturnTree( CScriptParseTreeNode *pReturnTree );
+
+ int32_t GenerateParseTree();
+
+ float ParseFloatFromTokenString();
+
+ int32_t HandleToken();
+ int32_t TestIdentifierToken();
+ int32_t HandleIdentifierToken();
+ int32_t m_nKeyWords;
+ CScriptCompilerKeyWordEntry *m_pcKeyWords;
+
+ int32_t ParseCharacterNumeric(int32_t ch);
+ int32_t ParseCharacterPeriod(int32_t chNext);
+ int32_t ParseCharacterSlash(int32_t chNext);
+ int32_t ParseCharacterAsterisk(int32_t chNext);
+ int32_t ParseCharacterAmpersand(int32_t chNext);
+ int32_t ParseCharacterVerticalBar(int32_t chNext);
+ int32_t ParseCharacterAlphabet(int32_t ch);
+ int32_t ParseStringCharacter(int32_t ch, int32_t chNext, char *pScript, int32_t nScriptLength);
+ int32_t ParseRawStringCharacter(int32_t ch, int32_t chNext);
+ int32_t ParseCharacterQuotationMark();
+ int32_t ParseCharacterHyphen(int32_t chNext);
+ int32_t ParseCharacterLeftBrace();
+ int32_t ParseCharacterRightBrace();
+ int32_t ParseCharacterLeftBracket();
+ int32_t ParseCharacterRightBracket();
+ int32_t ParseCharacterLeftSquareBracket();
+ int32_t ParseCharacterRightSquareBracket();
+ int32_t ParseCharacterLeftAngle(int32_t chNext);
+ int32_t ParseCharacterRightAngle(int32_t chNext);
+ int32_t ParseCharacterExclamationPoint(int32_t chNext);
+ int32_t ParseCharacterEqualSign(int32_t chNext);
+ int32_t ParseCharacterPlusSign(int32_t chNext);
+ int32_t ParseCharacterPercentSign(int32_t chNext);
+ int32_t ParseCharacterSemicolon();
+ int32_t ParseCharacterComma();
+ int32_t ParseCharacterCarat(int32_t chNext);
+ int32_t ParseCharacterTilde();
+ int32_t ParseCharacterEllipsis();
+ int32_t ParseCharacterQuestionMark();
+ int32_t ParseCharacterColon();
+
+ int32_t ParseCommentedOutCharacter(int32_t ch);
+
+ int32_t ParseNextCharacter(int32_t ch, int32_t chNext, char *pScript, int32_t nScriptLength);
+
+ int32_t PrintParseSourceError(int32_t nParseCharacterError);
+ int32_t ParseSource(char *pScript, int32_t nScriptLength);
+
+ int32_t OutputError(int32_t nError, CExoString *psFileName, int32_t nLineNumber, const CExoString &sErrorText);
+ CScriptParseTreeNode *DuplicateScriptParseTree(CScriptParseTreeNode *pNode);
+ CScriptParseTreeNode *CreateScriptParseTreeNode(int32_t nNodeOperation, CScriptParseTreeNode *pNodeLeft, CScriptParseTreeNode *pNodeRight);
+ BOOL CheckForBadLValue(CScriptParseTreeNode *pNode);
+ void DeleteScriptParseTreeNode(CScriptParseTreeNode *pParseTreeNode);
+ CScriptParseTreeNode *GetNewScriptParseTreeNode();
+
+ int32_t m_nParseTreeNodeBlockEmptyNodes;
+ CScriptParseTreeNodeBlock *m_pCurrentParseTreeNodeBlock;
+ CScriptParseTreeNodeBlock *m_pParseTreeNodeBlockHead;
+ CScriptParseTreeNodeBlock *m_pParseTreeNodeBlockTail;
+
+ int32_t OutputWalkTreeError(int32_t nError, CScriptParseTreeNode *pNode);
+ int32_t PreVisitGenerateCode(CScriptParseTreeNode *pNode);
+ int32_t InVisitGenerateCode(CScriptParseTreeNode *pNode);
+ int32_t PostVisitGenerateCode(CScriptParseTreeNode *pNode);
+
+ void WriteByteSwap32(char *buffer, int32_t value);
+ int32_t ReadByteSwap32(char *buffer);
+ char *EmitInstruction(uint8_t nOpCode, uint8_t nAuxCode = 0, int32_t nDataSize = 0);
+ void EmitModifyStackPointer(int32_t nModifyBy);
+
+ CExoString **m_ppsParseTreeFileNames;
+ int32_t m_nNextParseTreeFileName;
+ int32_t m_nCurrentParseTreeFileName;
+ void StartLineNumberAtBinaryInstruction(int32_t nFileReference, int32_t nLineNumber, int32_t nBinaryInstruction);
+ void EndLineNumberAtBinaryInstruction(int32_t nFileReference, int32_t nLineNumber, int32_t nBinaryInstruction);
+ void ResolveDebuggingInformation();
+ void ResolveDebuggingInformationForIdentifier(int32_t nIdentifier);
+
+ int32_t m_nCurrentLineNumber;
+ int32_t m_nCurrentLineNumberFileReference;
+ int32_t m_nCurrentLineNumberReferences;
+ int32_t m_nCurrentLineNumberBinaryStartInstruction;
+ int32_t m_nCurrentLineNumberBinaryEndInstruction;
+
+ int32_t m_nTableFileNames;
+ CExoString m_psTableFileNames[CSCRIPTCOMPILER_MAX_TABLE_FILENAMES];
+ int32_t m_nLineNumberEntries;
+ int32_t m_nFinalLineNumberEntries;
+ std::vector m_pnTableInstructionFileReference;
+ std::vector m_pnTableInstructionLineNumber;
+ std::vector m_pnTableInstructionBinaryStart;
+ std::vector m_pnTableInstructionBinaryEnd;
+ std::vector m_pnTableInstructionBinaryFinal;
+ std::vector m_pnTableInstructionBinarySortedOrder;
+
+ int32_t m_nSymbolTableVariables;
+ int32_t m_nFinalSymbolTableVariables;
+ std::vector m_pnSymbolTableVarType;
+ std::vector m_psSymbolTableVarName;
+ std::vector m_psSymbolTableVarStructureName;
+ std::vector m_pnSymbolTableVarStackLoc;
+ std::vector m_pnSymbolTableVarBegin;
+ std::vector m_pnSymbolTableVarEnd;
+ std::vector m_pnSymbolTableBinaryFinal;
+ std::vector m_pnSymbolTableBinarySortedOrder;
+
+
+ void DeleteCompileStack();
+ void DeleteParseTree(BOOL bStack, CScriptParseTreeNode *pNode);
+ int32_t WalkParseTree(CScriptParseTreeNode *pNode);
+
+ void InitializeFinalCode();
+ void FinalizeFinalCode();
+ int32_t GenerateFinalCodeFromParseTree(CExoString sFileName);
+
+ CExoString GenerateDebuggerTypeAbbreviation(int32_t nType, CExoString sStructureName);
+
+ BOOL m_bCompileConditionalFile;
+ BOOL m_bOldCompileConditionalFile;
+ BOOL m_bCompileConditionalOrMain;
+ CExoString m_sLanguageSource;
+ CExoString m_sOutputAlias;
+
+ int32_t m_nLines;
+ int32_t m_nCharacterOnLine;
+
+ // Variable for storing the values for each character (assembled in HashString) for identifiers
+ int32_t *m_pnHashString;
+ // The actual hash table.
+ CScriptCompilerIdentifierHashTableEntry *m_pIdentifierHashTable;
+ uint32_t HashManagerAdd(uint32_t nType, uint32_t nTypeIndice);
+ uint32_t HashManagerDelete(uint32_t nType, uint32_t nTypeIndice);
+ int32_t GetHashEntryByName(const char *psIdentifierName);
+
+ // Status of the current token
+ int32_t m_nTokenStatus;
+ int32_t m_nTokenCharacters;
+ char m_pchToken[CSCRIPTCOMPILER_MAX_TOKEN_LENGTH];
+
+ // Status of the current "compile stack"
+ CScriptCompilerStackEntry *m_pSRStack;
+ int32_t m_nSRStackEntries;
+ int32_t m_nSRStackStates;
+
+
+ // Identifiers (read from language definition file)
+ int32_t m_bCompileIdentifierList;
+ int32_t m_bCompileIdentifierConstants;
+ int32_t m_nIdentifierListState;
+ int32_t m_nIdentifierListVector;
+ int32_t m_nIdentifierListEngineStructure;
+ int32_t m_nIdentifierListReturnType;
+ CScriptCompilerIdListEntry *m_pcIdentifierList;
+ int32_t m_nOccupiedIdentifiers;
+ int32_t m_nMaxPredefinedIdentifierId;
+ int32_t m_nPredefinedIdentifierOrder;
+
+ int32_t PrintParseIdentifierFileError(int32_t nParseCharacterError);
+ int32_t ParseIdentifierFile();
+ int32_t GenerateIdentifierList();
+ int32_t AddUserDefinedIdentifier(CScriptParseTreeNode *pFunctionDeclaration, BOOL bFunctionImplementation);
+ void ClearUserDefinedIdentifiers();
+
+
+ // A stack of includes.
+ int32_t m_nCompileFileLevel;
+ CScriptCompilerIncludeFileStackEntry m_pcIncludeFileStack[CSCRIPTCOMPILER_MAX_INCLUDE_LEVELS];
+
+
+ // A Variable Stack
+ int32_t m_nVarStackRecursionLevel;
+ CScriptCompilerVarStackEntry *m_pcVarStackList;
+ int32_t m_nOccupiedVariables;
+ int32_t m_nVarStackVariableType;
+ CExoString m_sVarStackVariableTypeName;
+
+ // Global variable, Structure and structure field information.
+ CScriptCompilerStructureEntry *m_pcStructList;
+ CScriptCompilerStructureFieldEntry *m_pcStructFieldList;
+ int32_t m_nMaxStructures;
+ int32_t m_nMaxStructureFields;
+ int32_t m_nStructureDefinition;
+ int32_t m_nStructureDefinitionFieldStart;
+ int32_t GetStructureField(const CExoString &sStructureName, const CExoString &sFieldName);
+ int32_t GetStructureSize(const CExoString &sStructureName);
+ int32_t GetIdentifierByName(const CExoString &sIdentifierName);
+
+ BOOL m_bGlobalVariableDefinition;
+ int32_t m_nGlobalVariables;
+ int32_t m_nGlobalVariableSize; // size of all global variables in bytes.
+ CScriptParseTreeNode *m_pGlobalVariableParseTree;
+ int32_t AddToGlobalVariableList(CScriptParseTreeNode *pGlobalVariableNode);
+
+ BOOL ConstantFoldNode(CScriptParseTreeNode *pNode, BOOL bForce=FALSE);
+
+ BOOL m_bConstantVariableDefinition;
+
+ int32_t m_nLoopIdentifier;
+ int32_t m_nLoopStackDepth;
+
+ int32_t m_nSwitchLevel;
+ int32_t m_nSwitchIdentifier;
+ int32_t m_nSwitchStackDepth;
+
+ CExoString m_sUndefinedIdentifier;
+
+ BOOL m_bSwitchLabelDefault;
+ int32_t m_nSwitchLabelNumber;
+ int32_t m_nSwitchLabelArraySize;
+ int32_t* m_pnSwitchLabelStatements;
+ void InitializeSwitchLabelList();
+ int32_t TraverseTreeForSwitchLabels(CScriptParseTreeNode *pNode);
+ void ClearSwitchLabelList();
+ int32_t GenerateCodeForSwitchLabels(CScriptParseTreeNode *pNode);
+
+ int32_t GenerateIdentifiersFromConstantVariables(CScriptParseTreeNode *pNode);
+
+ // Engine-defined structures that can be compiled, but
+ // we don't actually do a lot with them during compilation
+ int32_t m_nNumEngineDefinedStructures;
+ BOOL *m_pbEngineDefinedStructureValid;
+ CExoString *m_psEngineDefinedStructureName;
+
+ int32_t m_bAssignmentToVariable; // we're in the middle of processing an "assignment to a
+ // variable. This is a good thing.
+ BOOL m_bInStructurePart; // In an expression, we want to prevent the part name from
+ // being looked up as a variable ... that'll be done at the
+ // structure part node above this one.
+
+ int32_t FoundReturnStatementOnAllBranches(CScriptParseTreeNode *pNode);
+
+ BOOL m_bFunctionImp;
+ CExoString m_sFunctionImpName;
+ int32_t m_nFunctionImpReturnType;
+ CExoString m_sFunctionImpReturnStructureName;
+ int32_t m_nFunctionImpAbortStackPointer;
+
+ // The Run-Time Stacks for Stuff.
+ int32_t m_nStackCurrentDepth;
+ char m_pchStackTypes[CSCRIPTCOMPILER_MAX_RUNTIME_VARS];
+
+ void AddVariableToStack(int32_t nVariableType, CExoString *psVariableTypeName, BOOL bGenerateCode);
+ void AddStructureToStack(const CExoString &sStructureName, BOOL bGenerateCode);
+
+ void AddToSymbolTableVarStack(int32_t nOccupiedIdentifier, int32_t nStackCurrentDepth, int32_t nGlobalVariableSize);
+ void RemoveFromSymbolTableVarStack(int32_t nOccupiedIdentifier, int32_t nStackCurrentDepth, int32_t nGlobalVariableSize);
+
+ int32_t m_nRunTimeIntegers;
+ int32_t m_nRunTimeFloats;
+ int32_t m_nRunTimeStrings;
+ int32_t m_nRunTimeObjects;
+ int32_t m_nRunTimeActions;
+
+ // The symbols to be added in between the code generation and output passes.
+
+ int32_t m_nSymbolQueryListSize;
+ int32_t m_nSymbolQueryList;
+ CScriptCompilerSymbolTableEntry *m_pSymbolQueryList;
+
+ int32_t m_nSymbolLabelListSize;
+ int32_t m_nSymbolLabelList;
+ CScriptCompilerSymbolTableEntry *m_pSymbolLabelList;
+ int32_t m_pSymbolLabelStartEntry[512];
+
+ CExoString GetFunctionNameFromSymbolSubTypes(int32_t nSubType1,int32_t nSubType2);
+ int32_t AddSymbolToQueryList(int32_t nLocationPointer, int32_t nSymbolType, int32_t nSymbolSubType1, int32_t nSymbolSubType2 = 0);
+ int32_t AddSymbolToLabelList(int32_t nLocationPointer, int32_t nSymbolType, int32_t nSymbolSubType1, int32_t nSymbolSubType2 = 0);
+
+ void ClearAllSymbolLists();
+
+ int32_t CleanUpDuringCompile(int32_t nReturnValue);
+ int32_t CleanUpAfterCompile(int32_t nReturnValue,CScriptParseTreeNode *pReturnTree);
+
+ // Generation of Code
+ int32_t m_nGenerateDebuggerOutput;
+
+ BOOL m_bAutomaticCleanUpAfterCompiles;
+ uint32_t m_nOptimizationFlags;
+ int32_t m_nTotalCompileNodes;
+ BOOL m_bCompilingConditional;
+ char *m_pchOutputCode;
+ int32_t m_nOutputCodeSize;
+ int32_t m_nOutputCodeLength;
+ std::vector m_aOutputCodeInstructionBoundaries;
+
+ char *InstructionLookback(uint32_t last=1);
+
+ // Resolving code to its proper location ... some buffers!
+ char *m_pchResolvedOutputBuffer;
+ int32_t m_nResolvedOutputBufferSize;
+
+ // Generation of Debug Code
+ char *m_pchDebuggerCode;
+ int32_t m_nDebuggerCodeSize;
+ int32_t m_nDebuggerCodeLength;
+
+ // These are used when parsing "operation action" commands to keep track of
+ // what the actual parameters are.
+ char m_pchActionParameters[CSCRIPTCOMPILERIDLISTENTRY_MAX_PARAMETERS];
+ CExoString m_pchActionParameterStructureNames[CSCRIPTCOMPILERIDLISTENTRY_MAX_PARAMETERS];
+
+ // Second Stage Of Code Generation
+ int32_t InstallLoader();
+ CScriptParseTreeNode *InsertGlobalVariablesInParseTree(CScriptParseTreeNode *pOldTree);
+ int32_t OutputIdentifierError(const CExoString &sFunctionName, int32_t nError, int32_t nFileStackDrop = 0);
+ int32_t ValidateLocationOfIdentifier(const CExoString &sFunctionName);
+ int32_t DetermineLocationOfCode();
+ int32_t ResolveLabels();
+ int32_t WriteResolvedOutput();
+
+ int32_t m_nFinalBinarySize;
+
+ // Error generation.
+
+ CExoString m_sCapturedError;
+ STRREF m_nCapturedErrorStrRef;
+
+ void* m_pUserData;
+};
diff --git a/src/Native Compiler/scriptcompcore.cpp b/src/Native Compiler/scriptcompcore.cpp
new file mode 100644
index 0000000..69e959d
--- /dev/null
+++ b/src/Native Compiler/scriptcompcore.cpp
@@ -0,0 +1,1910 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Script Project
+//::
+//:: Copyright (c) 2002, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ScriptCompCore.cpp
+//::
+//:: Implementation of conversion from scripting language to virtual machine
+//:: code.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: Oct. 8, 2002
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: This file contains "ported" code (used when writing out floating point
+//:: numbers on the MacIntosh platforms.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+// external header files
+#include "exobase.h"
+#include "scriptcomp.h"
+
+// internal header files
+#include "scriptinternal.h"
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: class CScriptCompilerIdListEntry
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompilerIdListEntry::CScriptCompilerIdListEntry()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 05/18/2001
+// Description: Default constructor for class.
+///////////////////////////////////////////////////////////////////////////////
+
+CScriptCompilerIdListEntry::CScriptCompilerIdListEntry()
+{
+ m_nIdentifierType = 0;
+ m_nReturnType = 0;
+ m_bImplementationInPlace = FALSE;
+
+ m_nIntegerData = 0;
+ m_fFloatData = 0.0f;
+ m_fVectorData[0] = 0.0f;
+ m_fVectorData[1] = 0.0f;
+ m_fVectorData[2] = 0.0f;
+ m_nParameters = 0;
+ m_nNonOptionalParameters = 0;
+
+ m_nParameterSpace = 0;
+ m_pchParameters = NULL;
+ m_psStructureParameterNames = NULL;
+ m_pbOptionalParameters = NULL;
+ m_pnOptionalParameterIntegerData = NULL;
+ m_pfOptionalParameterFloatData = NULL;
+ m_psOptionalParameterStringData = NULL;
+ m_poidOptionalParameterObjectData = NULL;
+ m_pfOptionalParameterVectorData = NULL;
+
+ m_nBinarySourceStart = -1;
+ m_nBinarySourceFinish = -1;
+ m_nBinaryDestinationStart = -1;
+ m_nBinaryDestinationFinish = -1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompilerIdListEntry::~CScriptCompilerIdListEntry()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/10/2001
+// Description: Default destructor for class.
+///////////////////////////////////////////////////////////////////////////////
+CScriptCompilerIdListEntry::~CScriptCompilerIdListEntry()
+{
+
+ // Delete the allocated arrays.
+ if (m_pchParameters)
+ {
+ delete[] m_pchParameters;
+ }
+ if (m_psStructureParameterNames)
+ {
+ delete[] m_psStructureParameterNames;
+ }
+ if (m_pbOptionalParameters)
+ {
+ delete[] m_pbOptionalParameters;
+ }
+ if (m_pnOptionalParameterIntegerData)
+ {
+ delete[] m_pnOptionalParameterIntegerData;
+ }
+ if (m_pfOptionalParameterFloatData)
+ {
+ delete[] m_pfOptionalParameterFloatData;
+ }
+ if (m_psOptionalParameterStringData)
+ {
+ delete[] m_psOptionalParameterStringData;
+ }
+ if (m_poidOptionalParameterObjectData)
+ {
+ delete[] m_poidOptionalParameterObjectData;
+ }
+ if (m_pfOptionalParameterVectorData)
+ {
+ delete[] m_pfOptionalParameterVectorData;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompilerIdListEntry::ExpandParameterSpace()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 05/18/2001
+// Description: Used to expand the parameter space (when required).
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompilerIdListEntry::ExpandParameterSpace()
+{
+ int32_t nNewParameterSpace;
+
+ if (m_nParameterSpace == CSCRIPTCOMPILERIDLISTENTRY_MAX_PARAMETERS)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOO_MANY_PARAMETERS_ON_FUNCTION;
+ }
+
+ if (m_nParameterSpace == 0)
+ {
+ nNewParameterSpace = 4;
+ }
+ else
+ {
+ nNewParameterSpace = m_nParameterSpace * 2;
+ }
+
+ // Declare the new arrays.
+ char *pchNewParameters = new char[nNewParameterSpace];
+ CExoString *psNewStructureParameterNames = new CExoString[nNewParameterSpace];
+ BOOL *pbNewOptionalParameters = new BOOL[nNewParameterSpace];
+ int32_t *pnNewOptionalParameterIntegerData = new int32_t[nNewParameterSpace];
+ float *pfNewOptionalParameterFloatData = new float[nNewParameterSpace];
+ CExoString *psNewOptionalParameterStringData = new CExoString[nNewParameterSpace];
+ OBJECT_ID *poidNewOptionalParameterObjectData = new OBJECT_ID[nNewParameterSpace];
+ float *pfNewOptionalParameterVectorData = new float[nNewParameterSpace * 3];
+
+ // Copy the old values to the new arrays.
+ int32_t nCount;
+
+ if (m_nParameterSpace != 0)
+ {
+ for (nCount = 0; nCount < m_nParameterSpace; nCount++)
+ {
+ pchNewParameters[nCount] = m_pchParameters[nCount];
+ }
+ for (nCount = 0; nCount < m_nParameterSpace; nCount++)
+ {
+ psNewStructureParameterNames[nCount] = m_psStructureParameterNames[nCount];
+ }
+ for (nCount = 0; nCount < m_nParameterSpace; nCount++)
+ {
+ pbNewOptionalParameters[nCount] = m_pbOptionalParameters[nCount];
+ }
+ for (nCount = 0; nCount < m_nParameterSpace; nCount++)
+ {
+ pnNewOptionalParameterIntegerData[nCount] = m_pnOptionalParameterIntegerData[nCount];
+ }
+ for (nCount = 0; nCount < m_nParameterSpace; nCount++)
+ {
+ pfNewOptionalParameterFloatData[nCount] = m_pfOptionalParameterFloatData[nCount];
+ }
+ for (nCount = 0; nCount < m_nParameterSpace; nCount++)
+ {
+ psNewOptionalParameterStringData[nCount] = m_psOptionalParameterStringData[nCount];
+ }
+ for (nCount = 0; nCount < m_nParameterSpace; nCount++)
+ {
+ poidNewOptionalParameterObjectData[nCount] = m_poidOptionalParameterObjectData[nCount];
+ }
+ for (nCount = 0; nCount < m_nParameterSpace * 3; nCount++)
+ {
+ pfNewOptionalParameterVectorData[nCount] = m_pfOptionalParameterVectorData[nCount];
+ }
+ }
+
+ // Oh, yeah, it's a good idea to declare what the values are!
+ for (nCount = m_nParameterSpace; nCount < nNewParameterSpace; nCount++)
+ {
+ pchNewParameters[nCount] = 0;
+ psNewStructureParameterNames[nCount] = "";
+ pbNewOptionalParameters[nCount] = FALSE;
+ pnNewOptionalParameterIntegerData[nCount] = 0;
+ pfNewOptionalParameterFloatData[nCount] = 0.0f;
+ psNewOptionalParameterStringData[nCount] = "";
+ poidNewOptionalParameterObjectData[nCount] = INVALID_OBJECT_ID;
+ }
+
+ for (nCount = m_nParameterSpace * 3; nCount < nNewParameterSpace * 3; nCount++)
+ {
+ pfNewOptionalParameterVectorData[nCount] = 0.0f;
+ }
+
+ m_nParameterSpace = nNewParameterSpace;
+
+ // Delete the old arrays.
+ if (m_pchParameters)
+ {
+ delete[] m_pchParameters;
+ }
+ if (m_psStructureParameterNames)
+ {
+ delete[] m_psStructureParameterNames;
+ }
+ if (m_pbOptionalParameters)
+ {
+ delete[] m_pbOptionalParameters;
+ }
+ if (m_pnOptionalParameterIntegerData)
+ {
+ delete[] m_pnOptionalParameterIntegerData;
+ }
+ if (m_pfOptionalParameterFloatData)
+ {
+ delete[] m_pfOptionalParameterFloatData;
+ }
+ if (m_psOptionalParameterStringData)
+ {
+ delete[] m_psOptionalParameterStringData;
+ }
+ if (m_poidOptionalParameterObjectData)
+ {
+ delete[] m_poidOptionalParameterObjectData;
+ }
+ if (m_pfOptionalParameterVectorData)
+ {
+ delete[] m_pfOptionalParameterVectorData;
+ }
+
+ m_pchParameters = pchNewParameters;
+ m_psStructureParameterNames = psNewStructureParameterNames;
+ m_pbOptionalParameters = pbNewOptionalParameters;
+ m_pnOptionalParameterIntegerData = pnNewOptionalParameterIntegerData;
+ m_pfOptionalParameterFloatData = pfNewOptionalParameterFloatData;
+ m_psOptionalParameterStringData = psNewOptionalParameterStringData;
+ m_poidOptionalParameterObjectData = poidNewOptionalParameterObjectData;
+ m_pfOptionalParameterVectorData = pfNewOptionalParameterVectorData;
+
+ return 0;
+}
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: class CScriptCompiler
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CScriptCompiler()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Default constructor for class.
+///////////////////////////////////////////////////////////////////////////////
+
+CScriptCompiler::CScriptCompiler(RESTYPE nSource, RESTYPE nCompiled, RESTYPE nDebug, CScriptCompilerAPI api)
+{
+ m_cAPI = api;
+
+ m_nGenerateDebuggerOutput = 1;
+
+ m_sLanguageSource = "";
+ m_sOutputAlias = "OVERRIDE";
+ m_nOptimizationFlags = CSCRIPTCOMPILER_OPTIMIZE_EVERYTHING;
+ m_nIdentifierListState = 0;
+
+ m_pSRStack = NULL;
+ m_pcIdentifierList = NULL;
+ m_pcVarStackList = NULL;
+ m_pcStructList = NULL;
+ m_pcStructFieldList = NULL;
+ m_pcKeyWords = NULL;
+ m_pSymbolQueryList = NULL;
+ m_pSymbolLabelList = NULL;
+ m_pIdentifierHashTable = NULL;
+ m_ppsParseTreeFileNames = NULL;
+
+ m_pParseTreeNodeBlockHead = NULL;
+ m_pParseTreeNodeBlockTail = NULL;
+ m_nParseTreeNodeBlockEmptyNodes = -1;
+ m_pCurrentParseTreeNodeBlock = NULL;
+
+ m_pnHashString = new int32_t[256];
+ int32_t nHashCount;
+ for (nHashCount = 0; nHashCount < 256; nHashCount++)
+ {
+ m_pnHashString[nHashCount] = rand();
+ }
+
+ m_pIdentifierHashTable = new CScriptCompilerIdentifierHashTableEntry[CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE];
+
+ m_nCompileFileLevel = 0;
+ m_bCompileConditionalFile = FALSE;
+ m_bOldCompileConditionalFile = FALSE;
+ m_bCompileConditionalOrMain = FALSE;
+ m_bAutomaticCleanUpAfterCompiles = TRUE;
+
+ m_nNumEngineDefinedStructures = 0;
+ m_pbEngineDefinedStructureValid = NULL;
+ m_psEngineDefinedStructureName = NULL;
+ m_nIdentifierListEngineStructure = 0;
+
+ m_pchOutputCode = NULL;
+ m_pchDebuggerCode = NULL;
+ m_pchResolvedOutputBuffer = NULL;
+ m_nResolvedOutputBufferSize = 0;
+
+ m_nResTypeSource = nSource;
+ m_nResTypeCompiled = nCompiled;
+ m_nResTypeDebug = nDebug;
+
+ Initialize();
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::~CScriptCompiler()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Default destructor for class.
+///////////////////////////////////////////////////////////////////////////////
+
+CScriptCompiler::~CScriptCompiler()
+{
+ ShutDown();
+
+ if (m_pIdentifierHashTable)
+ {
+ delete[] m_pIdentifierHashTable;
+ m_pIdentifierHashTable = NULL;
+ }
+
+ if (m_pnHashString)
+ {
+ delete[] m_pnHashString;
+ m_pnHashString = NULL;
+ }
+
+ // Delete linked list of ParseTreeNodeBlock structures.
+ if (m_pParseTreeNodeBlockHead)
+ {
+ CScriptParseTreeNodeBlock *pBlockPtr = m_pParseTreeNodeBlockHead;
+
+ while (pBlockPtr != NULL)
+ {
+ CScriptParseTreeNodeBlock *pCurrentPtr = pBlockPtr;
+ pBlockPtr = pBlockPtr->m_pNextBlock;
+ delete pCurrentPtr;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ShutDown()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Removes memory allocated by CScriptCompiler during process
+// of running.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::ShutDown()
+{
+
+ if (m_pSRStack)
+ {
+ delete[] m_pSRStack;
+ }
+
+ if (m_pcIdentifierList)
+ {
+ delete[] m_pcIdentifierList;
+ }
+
+ if (m_pcVarStackList)
+ {
+ delete[] m_pcVarStackList;
+ }
+
+ int32_t nCount = CSCRIPTCOMPILER_MAX_KEYWORDS - 1;
+ while (nCount >= 0)
+ {
+ HashManagerDelete(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_KEYWORD, nCount);
+ --nCount;
+ }
+
+ if (m_pcKeyWords != NULL)
+ {
+ delete[] m_pcKeyWords;
+ }
+
+ if (m_pcStructList != NULL)
+ {
+ delete[] m_pcStructList;
+ m_pcStructList = NULL;
+ }
+
+ if (m_pcStructFieldList != NULL)
+ {
+ delete[] m_pcStructFieldList;
+ m_pcStructFieldList = NULL;
+ }
+
+ if (m_psEngineDefinedStructureName != NULL)
+ {
+ delete[] m_psEngineDefinedStructureName;
+ m_psEngineDefinedStructureName = NULL;
+ }
+
+ if (m_pbEngineDefinedStructureValid)
+ {
+ delete[] m_pbEngineDefinedStructureValid;
+ m_pbEngineDefinedStructureValid = NULL;
+ }
+
+ if (m_ppsParseTreeFileNames)
+ {
+ for (int32_t count = 0; count < CSCRIPTCOMPILER_MAX_TABLE_FILENAMES; count++)
+ {
+ if (m_ppsParseTreeFileNames[count] != NULL)
+ {
+ delete m_ppsParseTreeFileNames[count];
+ m_ppsParseTreeFileNames[count] = NULL;
+ }
+ }
+ delete[] m_ppsParseTreeFileNames;
+ m_ppsParseTreeFileNames = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::Initialize()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Sets up parsing routine to be ready to accept a new script.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::Initialize( )
+{
+
+
+ m_sCapturedError = "";
+ m_nCapturedErrorStrRef = 0;
+
+ m_nLines = 1;
+ m_nCharacterOnLine = 1;
+
+ m_nSRStackStates = -1;
+ m_nSRStackEntries = CSCRIPTCOMPILER_MAX_STACK_ENTRIES;
+ if (m_pSRStack == NULL)
+ {
+ m_pSRStack = new CScriptCompilerStackEntry[m_nSRStackEntries];
+ }
+ PushSRStack(0,0,0,NULL);
+
+ if (m_pcStructList == NULL)
+ {
+ m_pcStructList = new CScriptCompilerStructureEntry[CSCRIPTCOMPILER_MAX_STRUCTURES];
+ }
+
+ if (m_pcStructFieldList == NULL)
+ {
+ m_pcStructFieldList = new CScriptCompilerStructureFieldEntry[CSCRIPTCOMPILER_MAX_STRUCTURE_FIELDS];
+ }
+
+ if (m_ppsParseTreeFileNames == NULL)
+ {
+ m_ppsParseTreeFileNames = new CExoString *[CSCRIPTCOMPILER_MAX_TABLE_FILENAMES];
+ for (int32_t count = 0; count < CSCRIPTCOMPILER_MAX_TABLE_FILENAMES; count++)
+ {
+ m_ppsParseTreeFileNames[count] = NULL;
+ }
+ }
+
+ int32_t count;
+
+ for (count = 0; count < CSCRIPTCOMPILER_MAX_TABLE_FILENAMES; count++)
+ {
+ if (m_ppsParseTreeFileNames[count] != NULL)
+ {
+ delete m_ppsParseTreeFileNames[count];
+ m_ppsParseTreeFileNames[count] = NULL;
+ }
+ }
+
+ for (count = 0; count < 512; count++)
+ {
+ m_pSymbolLabelStartEntry[count] = -1;
+ }
+
+ m_nCurrentParseTreeFileName = -1;
+ m_nNextParseTreeFileName = 0;
+
+ m_nParseTreeNodeBlockEmptyNodes = -1;
+ m_pCurrentParseTreeNodeBlock = m_pParseTreeNodeBlockHead;
+ if (m_pCurrentParseTreeNodeBlock != NULL)
+ {
+ m_pCurrentParseTreeNodeBlock->CleanBlockEntries();
+ m_nParseTreeNodeBlockEmptyNodes = CSCRIPTCOMPILER_PARSETREENODEBLOCK_SIZE - 1;
+ }
+
+ if (m_pcKeyWords == NULL)
+ {
+ m_nKeyWords = CSCRIPTCOMPILER_MAX_KEYWORDS;
+ m_pcKeyWords = new CScriptCompilerKeyWordEntry[CSCRIPTCOMPILER_MAX_KEYWORDS];
+ m_pcKeyWords[0] .Add("if" ,HashString("if"), CSCRIPTCOMPILER_TOKEN_KEYWORD_IF);
+ m_pcKeyWords[1] .Add("do" ,HashString("do"), CSCRIPTCOMPILER_TOKEN_KEYWORD_DO);
+ m_pcKeyWords[2] .Add("else" ,HashString("else"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ELSE);
+ m_pcKeyWords[3] .Add("int" ,HashString("int"), CSCRIPTCOMPILER_TOKEN_KEYWORD_INT);
+ m_pcKeyWords[4] .Add("float" ,HashString("float"), CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT);
+ m_pcKeyWords[5] .Add("string" ,HashString("string"),CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING);
+ m_pcKeyWords[6] .Add("object" ,HashString("object"),CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT);
+ m_pcKeyWords[7] .Add("return" ,HashString("return"),CSCRIPTCOMPILER_TOKEN_KEYWORD_RETURN);
+ m_pcKeyWords[8] .Add("while" ,HashString("while"), CSCRIPTCOMPILER_TOKEN_KEYWORD_WHILE);
+ m_pcKeyWords[9] .Add("for" ,HashString("for"), CSCRIPTCOMPILER_TOKEN_KEYWORD_FOR);
+ m_pcKeyWords[10].Add("void" ,HashString("void"), CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID);
+ m_pcKeyWords[11].Add("case" ,HashString("case"), CSCRIPTCOMPILER_TOKEN_KEYWORD_CASE);
+ m_pcKeyWords[12].Add("break" ,HashString("break"), CSCRIPTCOMPILER_TOKEN_KEYWORD_BREAK);
+ m_pcKeyWords[13].Add("struct" ,HashString("struct"),CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT);
+ m_pcKeyWords[14].Add("action" ,HashString("action"),CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION);
+ m_pcKeyWords[15].Add("switch" ,HashString("switch"),CSCRIPTCOMPILER_TOKEN_KEYWORD_SWITCH);
+ m_pcKeyWords[16].Add("default" ,HashString("default"), CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFAULT);
+ m_pcKeyWords[17].Add("#include",HashString("#include"), CSCRIPTCOMPILER_TOKEN_KEYWORD_INCLUDE);
+ m_pcKeyWords[18].Add("continue",HashString("continue"), CSCRIPTCOMPILER_TOKEN_KEYWORD_CONTINUE);
+ m_pcKeyWords[19].Add("vector" ,HashString("vector"), CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR);
+ m_pcKeyWords[20].Add("const" ,HashString("const"), CSCRIPTCOMPILER_TOKEN_KEYWORD_CONST);
+ m_pcKeyWords[21].Add("#define" ,HashString("#define"), CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFINE);
+ m_pcKeyWords[22].Add("OBJECT_SELF" ,HashString("OBJECT_SELF"), CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_SELF);
+ m_pcKeyWords[23].Add("OBJECT_INVALID" ,HashString("OBJECT_INVALID"), CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_INVALID);
+ m_pcKeyWords[24].Add("ENGINE_NUM_STRUCTURES" ,HashString("ENGINE_NUM_STRUCTURES"),CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_NUM_STRUCTURES_DEFINITION);
+ m_pcKeyWords[25].Add("ENGINE_STRUCTURE_0" ,HashString("ENGINE_STRUCTURE_0"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[26].Add("ENGINE_STRUCTURE_1" ,HashString("ENGINE_STRUCTURE_1"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[27].Add("ENGINE_STRUCTURE_2" ,HashString("ENGINE_STRUCTURE_2"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[28].Add("ENGINE_STRUCTURE_3" ,HashString("ENGINE_STRUCTURE_3"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[29].Add("ENGINE_STRUCTURE_4" ,HashString("ENGINE_STRUCTURE_4"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[30].Add("ENGINE_STRUCTURE_5" ,HashString("ENGINE_STRUCTURE_5"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[31].Add("ENGINE_STRUCTURE_6" ,HashString("ENGINE_STRUCTURE_6"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[32].Add("ENGINE_STRUCTURE_7" ,HashString("ENGINE_STRUCTURE_7"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[33].Add("ENGINE_STRUCTURE_8" ,HashString("ENGINE_STRUCTURE_8"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[34].Add("ENGINE_STRUCTURE_9" ,HashString("ENGINE_STRUCTURE_9"), CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION);
+ m_pcKeyWords[35].Add("JSON_NULL" ,HashString("JSON_NULL"), CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL);
+ m_pcKeyWords[36].Add("JSON_FALSE" ,HashString("JSON_FALSE"), CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE);
+ m_pcKeyWords[37].Add("JSON_TRUE" ,HashString("JSON_TRUE"), CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE);
+ m_pcKeyWords[38].Add("JSON_OBJECT" ,HashString("JSON_OBJECT"), CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT);
+ m_pcKeyWords[39].Add("JSON_ARRAY" ,HashString("JSON_ARRAY"), CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY);
+ m_pcKeyWords[40].Add("JSON_STRING" ,HashString("JSON_STRING"), CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING);
+ m_pcKeyWords[41].Add("LOCATION_INVALID" ,HashString("LOCATION_INVALID"), CSCRIPTCOMPILER_TOKEN_KEYWORD_LOCATION_INVALID);
+
+ int32_t nCount;
+ for (nCount = 0; nCount < CSCRIPTCOMPILER_MAX_KEYWORDS; ++nCount)
+ {
+ HashManagerAdd(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_KEYWORD,nCount);
+ }
+ }
+
+ //HashManagerAddKeywords();
+
+ m_nMaxStructures = 0;
+ m_nMaxStructureFields = 0;
+ m_nStructureDefinition = 0;
+ m_bGlobalVariableDefinition = FALSE;
+ m_nGlobalVariables = 0;
+ m_nGlobalVariableSize = 0;
+ m_bConstantVariableDefinition = FALSE;
+
+ m_nVarStackRecursionLevel = 0;
+
+ m_nSwitchLevel = 0;
+ m_nSwitchIdentifier = 0;
+ m_nSwitchStackDepth = 0;
+ m_bSwitchLabelDefault = FALSE;
+ m_nSwitchLabelNumber = 0;
+ m_nSwitchLabelArraySize = 16;
+ m_pnSwitchLabelStatements = NULL;
+
+ m_nLoopIdentifier = 0;
+ m_nLoopStackDepth = 0;
+
+ InitializePreDefinedStructures();
+
+ m_bCompileIdentifierConstants = FALSE;
+ m_bCompileIdentifierList = FALSE;
+
+ if (m_pcVarStackList == NULL)
+ {
+ m_pcVarStackList = new CScriptCompilerVarStackEntry[CSCRIPTCOMPILER_MAX_VARIABLES];
+ }
+
+ // MGB - 06/07/2001 - Moved this out of the first declaration of the var stack list,
+ // since this should really be run every time we're initializing the compiler.
+ m_nOccupiedVariables = -1;
+ m_nVarStackVariableType = CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION;
+
+ // Set up the runtime stacks.
+ m_nStackCurrentDepth = 0;
+ m_bAssignmentToVariable = FALSE;
+ m_bInStructurePart = FALSE;
+
+ ClearAllSymbolLists();
+
+ m_bFunctionImp = FALSE;
+ m_sFunctionImpName = "";
+ m_nFunctionImpReturnType = 0;
+ m_sFunctionImpReturnStructureName = "";
+ m_nFunctionImpAbortStackPointer = 0;
+
+ m_pGlobalVariableParseTree = NULL;
+ m_nCurrentLineNumber = 0;
+ m_nCurrentLineNumberFileReference = -1;
+ m_nCurrentLineNumberReferences = 0;
+ m_nCurrentLineNumberBinaryStartInstruction = 0;
+ m_nCurrentLineNumberBinaryEndInstruction = 0;
+
+ m_nTableFileNames = 0;
+
+ m_nFinalLineNumberEntries = 0;
+ m_nLineNumberEntries = 0;
+
+ m_nSymbolTableVariables = 0;
+ m_nFinalSymbolTableVariables = 0;
+
+ TokenInitialize();
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::HashString()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Nov. 20, 2002
+// Description: Hashes a string and returns a 32-bit value associated with
+// the string. (The theory is that two identifiers will not
+// match unless the hash values match.)
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t CScriptCompiler::HashString(const char *pString)
+{
+ if (m_pnHashString == NULL || pString == NULL)
+ {
+ return 0;
+ }
+
+ uint32_t nHashValue = 0;
+ uint32_t nStringLength = (uint32_t)strlen(pString);
+ uint32_t nStringCount = 0;
+
+ for (nStringCount = 0; nStringCount < nStringLength; nStringCount++)
+ {
+ nHashValue ^= m_pnHashString[pString[nStringCount]];
+ nHashValue += (nStringCount + 512);
+ }
+
+ return nHashValue;
+}
+
+
+uint32_t CScriptCompiler::HashString(const CExoString &sString)
+{
+ if (m_pnHashString == NULL)
+ {
+ return 0;
+ }
+
+ uint32_t nHashValue = 0;
+ uint32_t nStringLength = sString.GetLength();
+ uint32_t nStringCount = 0;
+ char *pcString = sString.CStr();
+
+ for (nStringCount = 0; nStringCount < nStringLength; nStringCount++)
+ {
+ nHashValue ^= m_pnHashString[pcString[nStringCount]];
+ nHashValue += (nStringCount + 512);
+ }
+
+ return nHashValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GetHashEntryByName()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Dec. 3, 2002
+// Description: This routine will return the location of the entry in the
+// hash table for the given token. Returns -1 if no hash entry
+// has been found.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::GetHashEntryByName(const char *psIdentifierName)
+{
+ BOOL bInfiniteLoop = TRUE;
+ uint32_t nOriginalHash = HashString(psIdentifierName);
+
+ // Search for the exact entry.
+ uint32_t nHash = nOriginalHash % CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE;
+ uint32_t nEndHash = nHash + (CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE - 1) & CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+
+ while (bInfiniteLoop)
+ {
+ // If we're at the correct entry, confirm that the strings are identical and then
+ // return to the main routine.
+ if (m_pIdentifierHashTable[nHash].m_nHashValue == nOriginalHash)
+ {
+ int32_t nIndex = m_pIdentifierHashTable[nHash].m_nIdentifierIndex;
+ if (m_pIdentifierHashTable[nHash].m_nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER)
+ {
+ if (strcmp(m_pcIdentifierList[nIndex].m_psIdentifier.CStr(),psIdentifierName) == 0)
+ {
+ return nHash;
+ }
+ }
+ else if (m_pIdentifierHashTable[nHash].m_nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_KEYWORD)
+ {
+ if (strcmp((m_pcKeyWords[nIndex].GetPointerToName())->CStr(),psIdentifierName) == 0)
+ {
+ return nHash;
+ }
+ }
+ else if (m_pIdentifierHashTable[nHash].m_nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_ENGINE_STRUCTURE)
+ {
+ if (strcmp(m_psEngineDefinedStructureName[nIndex].CStr(),psIdentifierName) == 0)
+ {
+ return nHash;
+ }
+ }
+ }
+
+ // Have we hit a blank entry? Then it's not in the list.
+ if (m_pIdentifierHashTable[nHash].m_nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_UNKNOWN)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ }
+
+ // Have we searched the entire list?
+ if (nEndHash == nHash)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ }
+
+ // Move to the next entry in the list.
+ ++nHash;
+ nHash &= CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+
+ }
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::HashManagerAdd()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Nov. 21, 2002
+// Description: Adds a identifier or keyword to the identifier hash table
+// so that we can figure out what the identifier is quickly!
+///////////////////////////////////////////////////////////////////////////////
+uint32_t CScriptCompiler::HashManagerAdd(uint32_t nType, uint32_t nIndice)
+{
+ uint32_t nHash;
+ uint32_t nOriginalHash=0;
+
+ // Get the hash value based on the type of entry.
+ if (nType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER)
+ {
+ CScriptCompilerIdListEntry *pIdentifier = &(m_pcIdentifierList[nIndice]);
+ nOriginalHash = HashString(pIdentifier->m_psIdentifier);
+ }
+ else if (nType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_KEYWORD)
+ {
+ CScriptCompilerKeyWordEntry *pEntry = &(m_pcKeyWords[nIndice]);
+ nOriginalHash = HashString(pEntry->GetAlphanumericName());
+ }
+ else if (nType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_ENGINE_STRUCTURE)
+ {
+ nOriginalHash = HashString(m_psEngineDefinedStructureName[nIndice]);
+ }
+
+
+ // Search for an empty entry.
+ nHash = nOriginalHash % CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE;
+ uint32_t nEndHash = nHash + (CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE - 1) & CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+ while (m_pIdentifierHashTable[nHash].m_nIdentifierType != CSCRIPTCOMPILER_HASH_MANAGER_TYPE_UNKNOWN && nHash != nEndHash)
+ {
+ ++nHash;
+ nHash &= CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+ }
+
+ // If we found an empty entry, do something about it.
+ if (m_pIdentifierHashTable[nHash].m_nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_UNKNOWN)
+ {
+ m_pIdentifierHashTable[nHash].m_nHashValue = nOriginalHash;
+ m_pIdentifierHashTable[nHash].m_nIdentifierType = nType;
+ m_pIdentifierHashTable[nHash].m_nIdentifierIndex = nIndice;
+
+ return 0;
+ }
+
+ // We didn't find an empty entry. This is bad.
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::HashManagerDelete()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Nov. 21, 2002
+// Description: Removes a identifier or keyword from the identifier hash table
+// so that we don't look for it any more in the table!
+///////////////////////////////////////////////////////////////////////////////
+uint32_t CScriptCompiler::HashManagerDelete(uint32_t nType, uint32_t nIndice)
+{
+ uint32_t nHash;
+ uint32_t nOriginalHash=0;
+
+ // Generate the hash value based on the type
+ if (nType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER)
+ {
+ CScriptCompilerIdListEntry *pIdentifier = &(m_pcIdentifierList[nIndice]);
+ nOriginalHash = HashString(pIdentifier->m_psIdentifier);
+ }
+ else if (nType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_KEYWORD)
+ {
+ CScriptCompilerKeyWordEntry *pEntry = &(m_pcKeyWords[nIndice]);
+ nOriginalHash = HashString(pEntry->GetAlphanumericName());
+ }
+ else if (nType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_ENGINE_STRUCTURE)
+ {
+ nOriginalHash = HashString(m_psEngineDefinedStructureName[nIndice]);
+ }
+
+ // Search for the exact entry.
+ nHash = nOriginalHash % CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE;
+ uint32_t nEndHash = nHash + (CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE - 1) & CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+ while (((m_pIdentifierHashTable[nHash].m_nHashValue != nOriginalHash) ||
+ (m_pIdentifierHashTable[nHash].m_nIdentifierType != nType) ||
+ (m_pIdentifierHashTable[nHash].m_nIdentifierIndex != nIndice)) && nHash != nEndHash)
+ {
+ ++nHash;
+ nHash &= CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+ }
+
+ // Delete the entry if we find its exact match.
+ if (m_pIdentifierHashTable[nHash].m_nIdentifierType == nType &&
+ m_pIdentifierHashTable[nHash].m_nIdentifierIndex == nIndice &&
+ m_pIdentifierHashTable[nHash].m_nHashValue == nOriginalHash)
+ {
+ m_pIdentifierHashTable[nHash].m_nHashValue = 0;
+ m_pIdentifierHashTable[nHash].m_nIdentifierType = CSCRIPTCOMPILER_HASH_MANAGER_TYPE_UNKNOWN;
+ m_pIdentifierHashTable[nHash].m_nIdentifierIndex = 0;
+ return 0;
+ }
+
+ // We didn't find it ... this is also bad.
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::InitializePreDefinedStructures()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 10/17/2000
+// Description: Sets up script compiler internal variables for the next
+// include file.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::InitializePreDefinedStructures()
+{
+
+ // Define the "vector" structure (used to compile vector calls).
+ m_nMaxStructures = 1;
+
+ m_pcStructList[0].m_nByteSize = 12;
+ m_pcStructList[0].m_nFieldStart = 0;
+ m_pcStructList[0].m_nFieldEnd = 2;
+ m_pcStructList[0].m_psName = "vector";
+
+ m_nMaxStructureFields = 3;
+
+ m_pcStructFieldList[0].m_psVarName = "x";
+ m_pcStructFieldList[0].m_nLocation = 0;
+ m_pcStructFieldList[0].m_pchType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+
+ m_pcStructFieldList[1].m_psVarName = "y";
+ m_pcStructFieldList[1].m_nLocation = 4;
+ m_pcStructFieldList[1].m_pchType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+
+ m_pcStructFieldList[2].m_psVarName = "z";
+ m_pcStructFieldList[2].m_nLocation = 8;
+ m_pcStructFieldList[2].m_pchType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+
+}
+
+void CScriptCompiler::InitializeIncludeFile(int32_t nCompileFileLevel)
+{
+
+ // Preserve the old state
+ if (nCompileFileLevel >= 1)
+ {
+ m_pcIncludeFileStack[nCompileFileLevel-1].m_nLine = m_nLines;
+ m_pcIncludeFileStack[nCompileFileLevel-1].m_nCharacterOnLine = m_nCharacterOnLine;
+ m_pcIncludeFileStack[nCompileFileLevel-1].m_nTokenStatus = m_nTokenStatus;
+ m_pcIncludeFileStack[nCompileFileLevel-1].m_nTokenCharacters = m_nTokenCharacters;
+
+ m_nLines = 1;
+ m_nCharacterOnLine = 1;
+ TokenInitialize();
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ShutdownIncludeFile()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/18/2000
+// Description: Reinstantiates script compiler internal variables when going
+// back to the earlier script.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::ShutdownIncludeFile(int32_t nCompileFileLevel)
+{
+
+ // Retrieve the old state
+ if (nCompileFileLevel >= 1)
+ {
+ m_nLines = m_pcIncludeFileStack[nCompileFileLevel - 1].m_nLine;
+ m_nCharacterOnLine = m_pcIncludeFileStack[nCompileFileLevel - 1].m_nCharacterOnLine;
+ m_nTokenStatus = m_pcIncludeFileStack[nCompileFileLevel - 1].m_nTokenStatus;
+ m_nTokenCharacters = m_pcIncludeFileStack[nCompileFileLevel - 1].m_nTokenCharacters;
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::DeleteParseTree()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 08/05/99
+// Description: This routine will take the root of a compile tree, ensure that
+// each of its branches have been deleted (recursively), and
+// then we can delete the node itself!
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::DeleteParseTree(BOOL bStack, CScriptParseTreeNode *pNode)
+{
+ if (pNode != NULL)
+ {
+ // Delete all of the subtrees
+ DeleteParseTree(bStack, pNode->pLeft);
+ DeleteParseTree(bStack, pNode->pRight);
+
+ if (bStack == TRUE)
+ {
+ // Delete any references to this node from the stack.
+ int32_t i;
+
+ for (i=0; i <= m_nSRStackStates; i++)
+ {
+ if (m_pSRStack[i].pCurrentTree != NULL)
+ {
+ m_pSRStack[i].pCurrentTree = NULL;
+ }
+ if (m_pSRStack[i].pReturnTree != NULL)
+ {
+ m_pSRStack[i].pReturnTree = NULL;
+ }
+ }
+ }
+
+ // Finally delete the node itself.
+ DeleteScriptParseTreeNode(pNode);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::SetGenerateDebuggerOutput()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: August 30, 2002
+// Description: This determines whether the debugger.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::SetGenerateDebuggerOutput(int32_t nValue)
+{
+ m_nGenerateDebuggerOutput = nValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::SetIdentifierSpecification()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/15/2001
+// Description: This routine will set whether the compiler should generate
+// a symbolic output or a regular output.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::SetIdentifierSpecification(const CExoString &sLanguageSource)
+{
+
+ if (m_sLanguageSource != sLanguageSource)
+ {
+ m_sLanguageSource = sLanguageSource;
+
+ if (m_pcIdentifierList != NULL)
+ {
+ while (m_nOccupiedIdentifiers > 0)
+ {
+ --m_nOccupiedIdentifiers;
+ HashManagerDelete(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER, m_nOccupiedIdentifiers);
+ }
+
+ delete[] m_pcIdentifierList;
+ }
+
+ if (m_pbEngineDefinedStructureValid != NULL)
+ {
+ int32_t nCount = 9;
+ while (nCount >= 0)
+ {
+ if (m_pbEngineDefinedStructureValid[nCount] == TRUE)
+ {
+ HashManagerDelete(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_ENGINE_STRUCTURE, nCount);
+ m_pbEngineDefinedStructureValid[nCount] = FALSE;
+ }
+ --nCount;
+ }
+ }
+
+ if (m_pcIdentifierList == NULL)
+ {
+ m_pcIdentifierList = new CScriptCompilerIdListEntry[CSCRIPTCOMPILER_MAX_IDENTIFIERS];
+ m_bCompileIdentifierList = TRUE;
+ m_bCompileIdentifierConstants = TRUE;
+ m_nOccupiedIdentifiers = 0;
+ m_nMaxPredefinedIdentifierId = 0;
+ ParseIdentifierFile();
+
+ m_nLines = 1;
+ m_nCharacterOnLine = 1;
+ m_nSRStackStates = -1;
+
+ m_bCompileIdentifierList = FALSE;
+ m_bCompileIdentifierConstants = FALSE;
+ }
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::SetOutputAlias()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/09/2001
+// Description: This routine will set the output alias for where we wish
+// to output the result of CompileFile.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::SetOutputAlias(const CExoString &sAlias)
+{
+ m_sOutputAlias = sAlias;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::SetCompileConditionalFile()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: This routine will set whether the compiler should generate
+// all functions (whether or not they are called), or only
+// those functions that could possibly be called via any
+// execution.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::SetCompileConditionalFile(BOOL bValue)
+{
+ m_bCompileConditionalFile = bValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::SetCompileConditionalOrMain()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Feb. 17, 2003
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::SetCompileConditionalOrMain(BOOL bValue)
+{
+ m_bCompileConditionalOrMain = bValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::SetAutomaticCleanUpAfterCompiles()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Feb/06/2003
+// Description:
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::SetAutomaticCleanUpAfterCompiles(BOOL bValue)
+{
+ m_bAutomaticCleanUpAfterCompiles = bValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::UpdateOutputDirectory()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Feb/06/2003
+// Description: Updates the current output alias to allow the resource
+// manager to use the scripts that were compiled! (Use of this
+// function is ONLY required when you have set the automatic
+// update of the output directory to FALSE. If the value was
+// TRUE during a CompileFile instruction, this code has already
+// been run on the newly created files!)
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::CleanUpAfterCompiles()
+{
+ // Update the resource directory.
+ CExoString sDirectoryFileName;
+
+ sDirectoryFileName.Format("%s:",m_sOutputAlias.CStr());
+ m_cAPI.ResManUpdateResourceDirectory(sDirectoryFileName.CStr());
+
+ // Delete the Debugger code buffer.
+ if (m_pchDebuggerCode != NULL)
+ {
+ delete[] m_pchDebuggerCode;
+ m_pchDebuggerCode = NULL;
+ m_nDebuggerCodeSize = 0;
+ }
+
+ // The resolved output buffer should go, too.
+ if (m_pchResolvedOutputBuffer != NULL)
+ {
+ delete[] m_pchResolvedOutputBuffer;
+ m_pchResolvedOutputBuffer = NULL;
+ m_nResolvedOutputBufferSize = 0;
+ }
+
+ // And the script code buffer should also be deallocated.
+ ClearCompiledScriptCode();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CompileFile()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: This routine will compile the file specified in sFileName
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::CompileFile(const CExoString &sFileName)
+{
+
+ char *pScript;
+ uint32_t nScriptLength;
+
+ if (m_nCompileFileLevel == 0)
+ {
+ Initialize();
+ }
+
+ if (m_nCompileFileLevel >= CSCRIPTCOMPILER_MAX_INCLUDE_LEVELS)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_INCLUDE_TOO_MANY_LEVELS;
+ }
+
+ if (m_nCompileFileLevel > 0)
+ {
+ int count;
+
+ for (count = 0; count < m_nCompileFileLevel; ++count)
+ {
+ if (m_pcIncludeFileStack[count].m_sCompiledScriptName == sFileName)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_INCLUDE_RECURSIVE;
+ }
+ }
+
+ InitializeIncludeFile(m_nCompileFileLevel);
+ }
+
+ m_pcIncludeFileStack[m_nCompileFileLevel].m_sCompiledScriptName = sFileName;
+
+ const char* sTest = m_cAPI.ResManLoadScriptSourceFile(sFileName.CStr(), m_nResTypeSource);
+ if (!sTest)
+ {
+ if (m_nCompileFileLevel > 0)
+ {
+ ShutdownIncludeFile(m_nCompileFileLevel);
+ }
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_FILE_NOT_FOUND;
+ }
+ m_pcIncludeFileStack[m_nCompileFileLevel].m_sSourceScript = sTest;
+ pScript = m_pcIncludeFileStack[m_nCompileFileLevel].m_sSourceScript.CStr();
+ nScriptLength = m_pcIncludeFileStack[m_nCompileFileLevel].m_sSourceScript.GetLength();
+
+ ++m_nCompileFileLevel;
+
+ int32_t nReturnValue = ParseSource(pScript,nScriptLength);
+
+ if (nReturnValue < 0)
+ {
+ // MGB - 02/15/2001 - DO NOT SUBTRACT ONE FROM COMPILEFILELEVEL.
+ // Why? It is taken off in CleanUpDuringCompile.
+ m_pcIncludeFileStack[m_nCompileFileLevel].m_sSourceScript = "";
+ return nReturnValue;
+ }
+
+ // We have successfully compiled this file. If we are still in
+ // the middle of another CompileFile (i.e. this is an included
+ // file, return success back to the main routine.
+
+ m_pcIncludeFileStack[m_nCompileFileLevel-1].m_sSourceScript = "";
+
+ --m_nCompileFileLevel;
+ if (m_nCompileFileLevel > 0)
+ {
+ ShutdownIncludeFile(m_nCompileFileLevel);
+ return 0;
+ }
+
+ // This is the "outermost" script level. Here, we should
+ // attempt to write out the virtual machine code.
+
+ InitializeFinalCode();
+
+ nReturnValue = GenerateFinalCodeFromParseTree(sFileName);
+
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+ FinalizeFinalCode();
+
+ nReturnValue = WriteFinalCodeToFile(sFileName);
+
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+
+
+ return nReturnValue;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CompileScriptChunk()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/11/2001
+// Description: This routine will compile the string specified in sStringData.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::CompileScriptChunk(const CExoString &sScriptChunk, BOOL bWrapIntoMain)
+{
+ char *pScript;
+ uint32_t nScriptLength;
+
+ Initialize();
+
+ if (m_nCompileFileLevel != 0)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_INCLUDE_TOO_MANY_LEVELS;
+ }
+
+ m_pcIncludeFileStack[m_nCompileFileLevel].m_sCompiledScriptName = "!Chunk";
+
+ if (bWrapIntoMain)
+ {
+ nScriptLength = sScriptChunk.GetLength() + 13;
+ pScript = new char[nScriptLength + 13];
+ sprintf(pScript, "void main(){%s}", sScriptChunk.CStr());
+ }
+ else
+ {
+ nScriptLength = sScriptChunk.GetLength();
+ pScript = new char[nScriptLength];
+ memmove(pScript, sScriptChunk.CStr(), nScriptLength);
+ }
+
+ ++m_nCompileFileLevel;
+
+ int32_t nReturnValue = ParseSource(pScript,nScriptLength);
+
+ if (nReturnValue < 0)
+ {
+ delete[] pScript;
+ return nReturnValue;
+ }
+
+ --m_nCompileFileLevel;
+
+ InitializeFinalCode();
+
+ nReturnValue = GenerateFinalCodeFromParseTree("!Chunk");
+
+ if (nReturnValue < 0)
+ {
+ delete[] pScript;
+ return nReturnValue;
+ }
+
+ FinalizeFinalCode();
+
+ delete[] pScript;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CompileScriptConditional()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/11/2001
+// Description: This routine will compile the string specified in sStringData.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::CompileScriptConditional(const CExoString &sScriptConditional)
+{
+
+ char *pScript;
+ uint32_t nScriptLength;
+
+ Initialize();
+
+ if (m_nCompileFileLevel != 0)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_INCLUDE_TOO_MANY_LEVELS;
+ }
+
+ m_pcIncludeFileStack[m_nCompileFileLevel].m_sCompiledScriptName = "!Conditional";
+
+ nScriptLength = sScriptConditional.GetLength() + 22;
+ pScript = new char[nScriptLength + 22];
+ sprintf(pScript,"int main(){ return(%s);}",sScriptConditional.CStr());
+
+ ++m_nCompileFileLevel;
+
+ int32_t nReturnValue = ParseSource(pScript,nScriptLength);
+
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+ --m_nCompileFileLevel;
+
+ InitializeFinalCode();
+
+ nReturnValue = GenerateFinalCodeFromParseTree("!Conditional");
+
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+ FinalizeFinalCode();
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GetCompiledScriptCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/11/2001
+// Description: This routine will return the data that has already been
+// compiled.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::GetCompiledScriptCode(char **ppnCode, int32_t *pnCodeSize)
+{
+ *pnCodeSize = m_nOutputCodeSize;
+ *ppnCode = m_pchOutputCode;
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ClearCompiledScriptCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/11/2001
+// Description: This routine will return delete any data that has already
+// been compiled.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::ClearCompiledScriptCode()
+{
+ m_nOutputCodeSize = 0;
+ if (m_pchOutputCode)
+ {
+ delete[] m_pchOutputCode;
+ m_pchOutputCode = NULL;
+ }
+ m_nOutputCodeLength = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::OutputError()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/23/2001
+// Description: A standardization of ALL error messages that could possibly
+// come out of the compilation of any/all code.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::OutputError(int32_t nError, CExoString *psFileName, int32_t nLineNumber, const CExoString &sErrorText)
+{
+ // Construct the error string, if appropriate
+ if (nError == STRREF_CSCRIPTCOMPILER_ERROR_ALREADY_PRINTED)
+ {
+ return nError;
+ }
+
+ CExoString sFullErrorText;
+
+ if (psFileName->Left(1) == "!")
+ {
+ if (nLineNumber > 0)
+ {
+ sFullErrorText.Format("%s(%d): %s\n",psFileName->Right(psFileName->GetLength()-1).CStr(),nLineNumber,sErrorText.CStr());
+ }
+ else
+ {
+ sFullErrorText.Format("%s: %s\n",psFileName->Right(psFileName->GetLength()-1).CStr(),sErrorText.CStr());
+ }
+ }
+ else
+ {
+ if (nLineNumber > 0)
+ {
+ sFullErrorText.Format("%s.nss(%d): %s\n",psFileName->CStr(),nLineNumber,sErrorText.CStr());
+ }
+ else
+ {
+ sFullErrorText.Format("%s.nss: %s\n",psFileName->CStr(),sErrorText.CStr());
+ }
+ }
+
+ m_sCapturedError = sFullErrorText;
+ m_nCapturedErrorStrRef = nError;
+
+ // Print the full error text to the log file.
+ // This is used and parsed by the toolset :( Do not remove.
+#ifdef BORLAND
+ g_pExoBase->m_pcExoDebug->m_sLogString.Format("%s",sFullErrorText.CStr());
+ g_pExoBase->m_pcExoDebug->WriteToLogFile(g_pExoBase->m_pcExoDebug->m_sLogString);
+ g_pExoBase->m_pcExoDebug->FlushLogFile();
+#endif
+
+ return nError;
+}
+
+
+// Destructively modify a node and all its children to decay it into a single
+// CONSTANT operation, if possible.
+// This function is safe to call multiple times on the same node.
+BOOL CScriptCompiler::ConstantFoldNode(CScriptParseTreeNode *pNode, BOOL bForce)
+{
+ if (!bForce && !(m_nOptimizationFlags & CSCRIPTCOMPILER_OPTIMIZE_FOLD_CONSTANTS))
+ return FALSE;
+
+ if (!pNode)
+ return FALSE;
+
+ // Only fold operations that have two operands
+ // TODO: ~0 unary op?
+ if (!pNode->pLeft || !pNode->pRight)
+ return FALSE;
+
+ // In case of complex expression, start folding at the leaf nodes
+ // e.g.: C = 3 + 2*4 - First fold 2*4 into 8, then 3+8 into 11
+ ConstantFoldNode(pNode->pLeft, bForce);
+ ConstantFoldNode(pNode->pRight, bForce);
+
+ // Can only fold if the operands are constants.
+ if (pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER &&
+ pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT &&
+ pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING)
+ {
+ return FALSE;
+ }
+
+ // Only fold operations on same type. Expressions like "3.0f + 1" are not folded
+ if (pNode->pLeft->nOperation != pNode->pRight->nOperation)
+ return FALSE;
+
+ if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ int32_t result;
+ int32_t left = pNode->pLeft->nIntegerData;
+ int32_t right = pNode->pRight->nIntegerData;
+ switch (pNode->nOperation)
+ {
+ case CSCRIPTCOMPILER_OPERATION_LOGICAL_OR: result = left || right; break;
+ case CSCRIPTCOMPILER_OPERATION_LOGICAL_AND: result = left && right; break;
+ case CSCRIPTCOMPILER_OPERATION_INCLUSIVE_OR: result = left | right; break;
+ case CSCRIPTCOMPILER_OPERATION_EXCLUSIVE_OR: result = left ^ right; break;
+ case CSCRIPTCOMPILER_OPERATION_BOOLEAN_AND: result = left & right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL: result = left == right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_NOT_EQUAL: result = left != right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_GEQ: result = left >= right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_GT: result = left > right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_LT: result = left < right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_LEQ: result = left <= right; break;
+ case CSCRIPTCOMPILER_OPERATION_SHIFT_LEFT: result = left << right; break;
+ case CSCRIPTCOMPILER_OPERATION_SHIFT_RIGHT: result = left >> right; break;
+ case CSCRIPTCOMPILER_OPERATION_ADD: result = left + right; break;
+ case CSCRIPTCOMPILER_OPERATION_SUBTRACT: result = left - right; break;
+ case CSCRIPTCOMPILER_OPERATION_MULTIPLY: result = left * right; break;
+ case CSCRIPTCOMPILER_OPERATION_DIVIDE: result = left / right; break;
+ case CSCRIPTCOMPILER_OPERATION_MODULUS: result = left % right; break;
+ default: return FALSE;
+ }
+ pNode->pLeft->Clean();
+ pNode->pRight->Clean();
+ pNode->Clean();
+ pNode->nOperation = CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER;
+ pNode->nIntegerData = result;
+ return TRUE;
+ }
+
+ if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT)
+ {
+ float result;
+ int resultBool = -1;
+ float left = pNode->pLeft->fFloatData;
+ float right = pNode->pRight->fFloatData;
+ switch (pNode->nOperation)
+ {
+ case CSCRIPTCOMPILER_OPERATION_ADD: result = left + right; break;
+ case CSCRIPTCOMPILER_OPERATION_SUBTRACT: result = left - right; break;
+ case CSCRIPTCOMPILER_OPERATION_MULTIPLY: result = left * right; break;
+ case CSCRIPTCOMPILER_OPERATION_DIVIDE: result = left / right; break;
+ // Relational ops on floats produce a bool result
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL: resultBool = left == right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_NOT_EQUAL: resultBool = left != right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_GEQ: resultBool = left >= right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_GT: resultBool = left > right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_LT: resultBool = left < right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_LEQ: resultBool = left <= right; break;
+ default: return FALSE;
+ }
+ pNode->pLeft->Clean();
+ pNode->pRight->Clean();
+ pNode->Clean();
+ if (resultBool != -1)
+ {
+ pNode->nOperation = CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER;
+ pNode->nIntegerData = resultBool;
+ }
+ else
+ {
+ pNode->nOperation = CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT;
+ pNode->fFloatData = result;
+ }
+ return TRUE;
+ }
+
+ if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING)
+ {
+ CExoString left = (pNode->pLeft->m_psStringData ? *pNode->pLeft->m_psStringData : CExoString(""));
+ CExoString right = (pNode->pRight->m_psStringData ? *pNode->pRight->m_psStringData : CExoString(""));
+ CExoString result;
+ int resultBool = -1;
+ switch (pNode->nOperation)
+ {
+ case CSCRIPTCOMPILER_OPERATION_ADD: result = left + right; break;
+ // Relational ops on string produce a bool result
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL: resultBool = left == right; break;
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_NOT_EQUAL: resultBool = left != right; break;
+ default: return FALSE;
+ }
+ pNode->pLeft->Clean();
+ pNode->pRight->Clean();
+ pNode->Clean();
+ if (resultBool != -1)
+ {
+ pNode->nOperation = CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER;
+ pNode->nIntegerData = resultBool;
+ }
+ else
+ {
+ pNode->nOperation = CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING;
+ pNode->m_psStringData = new CExoString(result);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+const char *TokenKeywordToString(int nTokenKeyword)
+{
+ switch (nTokenKeyword)
+ {
+ case CSCRIPTCOMPILER_TOKEN_UNKNOWN: return "UNKNOWN";
+ case CSCRIPTCOMPILER_TOKEN_DIVIDE: return "DIVIDE";
+ case CSCRIPTCOMPILER_TOKEN_CPLUSCOMMENT: return "CPLUSCOMMENT";
+ case CSCRIPTCOMPILER_TOKEN_CCOMMENT: return "CCOMMENT";
+ case CSCRIPTCOMPILER_TOKEN_INTEGER: return "INTEGER";
+ case CSCRIPTCOMPILER_TOKEN_FLOAT: return "FLOAT";
+ case CSCRIPTCOMPILER_TOKEN_IDENTIFIER: return "IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_STRING: return "STRING";
+ case CSCRIPTCOMPILER_TOKEN_LOGICAL_AND: return "LOGICAL_AND";
+ case CSCRIPTCOMPILER_TOKEN_LOGICAL_OR: return "LOGICAL_OR";
+ case CSCRIPTCOMPILER_TOKEN_MINUS: return "MINUS";
+ case CSCRIPTCOMPILER_TOKEN_LEFT_BRACE: return "LEFT_BRACE";
+ case CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE: return "RIGHT_BRACE";
+ case CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET: return "LEFT_BRACKET";
+ case CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET: return "RIGHT_BRACKET";
+ case CSCRIPTCOMPILER_TOKEN_SEMICOLON: return "SEMICOLON";
+ case CSCRIPTCOMPILER_TOKEN_COMMA: return "COMMA";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_IF: return "KEYWORD_IF";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ELSE: return "KEYWORD_ELSE";
+ case CSCRIPTCOMPILER_TOKEN_EOF: return "EOF";
+ case CSCRIPTCOMPILER_TOKEN_COND_GREATER_EQUAL: return "COND_GREATER_EQUAL";
+ case CSCRIPTCOMPILER_TOKEN_COND_LESS_EQUAL: return "COND_LESS_EQUAL";
+ case CSCRIPTCOMPILER_TOKEN_COND_GREATER_THAN: return "COND_GREATER_THAN";
+ case CSCRIPTCOMPILER_TOKEN_COND_LESS_THAN: return "COND_LESS_THAN";
+ case CSCRIPTCOMPILER_TOKEN_COND_NOT_EQUAL: return "COND_NOT_EQUAL";
+ case CSCRIPTCOMPILER_TOKEN_COND_EQUAL: return "COND_EQUAL";
+ case CSCRIPTCOMPILER_TOKEN_PLUS: return "PLUS";
+ case CSCRIPTCOMPILER_TOKEN_MODULUS: return "MODULUS";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL: return "ASSIGNMENT_EQUAL";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_INT: return "KEYWORD_INT";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT: return "KEYWORD_FLOAT";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING: return "KEYWORD_STRING";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT: return "KEYWORD_OBJECT";
+ case CSCRIPTCOMPILER_TOKEN_VARIABLE: return "VARIABLE";
+ case CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER: return "INTEGER_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER: return "FLOAT_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER: return "STRING_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER: return "OBJECT_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER: return "VOID_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_INCLUSIVE_OR: return "INCLUSIVE_OR";
+ case CSCRIPTCOMPILER_TOKEN_EXCLUSIVE_OR: return "EXCLUSIVE_OR";
+ case CSCRIPTCOMPILER_TOKEN_BOOLEAN_AND: return "BOOLEAN_AND";
+ case CSCRIPTCOMPILER_TOKEN_SHIFT_LEFT: return "SHIFT_LEFT";
+ case CSCRIPTCOMPILER_TOKEN_SHIFT_RIGHT: return "SHIFT_RIGHT";
+ case CSCRIPTCOMPILER_TOKEN_MULTIPLY: return "MULTIPLY";
+ case CSCRIPTCOMPILER_TOKEN_HEX_INTEGER: return "HEX_INTEGER";
+ case CSCRIPTCOMPILER_TOKEN_UNSIGNED_SHIFT_RIGHT: return "UNSIGNED_SHIFT_RIGHT";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION: return "KEYWORD_ACTION";
+ case CSCRIPTCOMPILER_TOKEN_TILDE: return "TILDE";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_RETURN: return "KEYWORD_RETURN";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_WHILE: return "KEYWORD_WHILE";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_FOR: return "KEYWORD_FOR";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_DO: return "KEYWORD_DO";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID: return "KEYWORD_VOID";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT: return "KEYWORD_STRUCT";
+ case CSCRIPTCOMPILER_TOKEN_STRUCTURE_PART_SPECIFY: return "STRUCTURE_PART_SPECIFY";
+ case CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER: return "STRUCTURE_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_INCLUDE: return "KEYWORD_INCLUDE";
+ case CSCRIPTCOMPILER_TOKEN_BOOLEAN_NOT: return "BOOLEAN_NOT";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR: return "KEYWORD_VECTOR";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFINE: return "KEYWORD_DEFINE";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_NUM_STRUCTURES_DEFINITION: return "KEYWORD_ENGINE_NUM_STRUCTURES_DEFINITION";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION: return "KEYWORD_ENGINE_STRUCTURE_DEFINITION";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0: return "KEYWORD_ENGINE_STRUCTURE0";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE1: return "KEYWORD_ENGINE_STRUCTURE1";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2: return "KEYWORD_ENGINE_STRUCTURE2";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE3: return "KEYWORD_ENGINE_STRUCTURE3";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE4: return "KEYWORD_ENGINE_STRUCTURE4";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE5: return "KEYWORD_ENGINE_STRUCTURE5";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE6: return "KEYWORD_ENGINE_STRUCTURE6";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7: return "KEYWORD_ENGINE_STRUCTURE7";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE8: return "KEYWORD_ENGINE_STRUCTURE8";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9: return "KEYWORD_ENGINE_STRUCTURE9";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER: return "ENGINE_STRUCTURE0_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE1_IDENTIFIER: return "ENGINE_STRUCTURE1_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE2_IDENTIFIER: return "ENGINE_STRUCTURE2_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE3_IDENTIFIER: return "ENGINE_STRUCTURE3_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE4_IDENTIFIER: return "ENGINE_STRUCTURE4_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE5_IDENTIFIER: return "ENGINE_STRUCTURE5_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE6_IDENTIFIER: return "ENGINE_STRUCTURE6_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE7_IDENTIFIER: return "ENGINE_STRUCTURE7_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE8_IDENTIFIER: return "ENGINE_STRUCTURE8_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER: return "ENGINE_STRUCTURE9_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_SELF: return "KEYWORD_OBJECT_SELF";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_INVALID: return "KEYWORD_OBJECT_INVALID";
+ case CSCRIPTCOMPILER_TOKEN_VECTOR_IDENTIFIER: return "VECTOR_IDENTIFIER";
+ case CSCRIPTCOMPILER_TOKEN_LEFT_SQUARE_BRACKET: return "LEFT_SQUARE_BRACKET";
+ case CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET: return "RIGHT_SQUARE_BRACKET";
+ case CSCRIPTCOMPILER_TOKEN_INCREMENT: return "INCREMENT";
+ case CSCRIPTCOMPILER_TOKEN_DECREMENT: return "DECREMENT";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MINUS: return "ASSIGNMENT_MINUS";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_PLUS: return "ASSIGNMENT_PLUS";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MULTIPLY: return "ASSIGNMENT_MULTIPLY";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_DIVIDE: return "ASSIGNMENT_DIVIDE";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MODULUS: return "ASSIGNMENT_MODULUS";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_AND: return "ASSIGNMENT_AND";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_XOR: return "ASSIGNMENT_XOR";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_OR: return "ASSIGNMENT_OR";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_LEFT: return "ASSIGNMENT_SHIFT_LEFT";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_RIGHT: return "ASSIGNMENT_SHIFT_RIGHT";
+ case CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_USHIFT_RIGHT: return "ASSIGNMENT_USHIFT_RIGHT";
+ case CSCRIPTCOMPILER_TOKEN_QUESTION_MARK: return "QUESTION_MARK";
+ case CSCRIPTCOMPILER_TOKEN_COLON: return "COLON";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_CASE: return "KEYWORD_CASE";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_BREAK: return "KEYWORD_BREAK";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_SWITCH: return "KEYWORD_SWITCH";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFAULT: return "KEYWORD_DEFAULT";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_CONTINUE: return "KEYWORD_CONTINUE";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_CONST: return "KEYWORD_CONST";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL: return "KEYWORD_JSON_NULL";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE: return "KEYWORD_JSON_FALSE";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE: return "KEYWORD_JSON_TRUE";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT: return "KEYWORD_JSON_OBJECT";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY: return "KEYWORD_JSON_ARRAY";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING: return "KEYWORD_JSON_STRING";
+ case CSCRIPTCOMPILER_TOKEN_KEYWORD_LOCATION_INVALID: return "KEYWORD_LOCATION_INVALID";
+ }
+ return "(unknown token keyword)";
+}
+
+const char *GrammarToString(int nGrammar)
+{
+ switch (nGrammar)
+ {
+ case CSCRIPTCOMPILER_GRAMMAR_PROGRAM: return "PROGRAM";
+ case CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT: return "FUNCTIONAL_UNIT";
+ case CSCRIPTCOMPILER_GRAMMAR_AFTER_PROGRAM: return "AFTER_PROGRAM";
+ case CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST: return "FUNCTION_PARAM_LIST";
+ case CSCRIPTCOMPILER_GRAMMAR_AFTER_FUNCTION_PARAM: return "AFTER_FUNCTION_PARAM";
+ case CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST: return "NON_INIT_DECL_LIST";
+ case CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST: return "NON_INIT_DECL_VARLIST";
+ case CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST_SEPARATOR: return "NON_INIT_DECL_VARLIST_SEPARATOR";
+ case CSCRIPTCOMPILER_GRAMMAR_WITHIN_COMPOUND_STATEMENT: return "WITHIN_COMPOUND_STATEMENT";
+ case CSCRIPTCOMPILER_GRAMMAR_WITHIN_STATEMENT_LIST: return "WITHIN_STATEMENT_LIST";
+ case CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT: return "WITHIN_A_STATEMENT";
+ case CSCRIPTCOMPILER_GRAMMAR_ANY_TYPE_SPECIFIER: return "ANY_TYPE_SPECIFIER";
+ case CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER: return "NON_VOID_TYPE_SPECIFIER";
+ case CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST: return "DECL_VARLIST";
+ case CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST_SEPARATOR: return "DECL_VARLIST_SEPARATOR";
+ case CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST: return "ARGUMENT_EXPRESSION_LIST";
+ case CSCRIPTCOMPILER_GRAMMAR_AFTER_ARGUMENT_EXPRESSION: return "AFTER_ARGUMENT_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION: return "BOOLEAN_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION: return "NON_VOID_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_EXPRESSION: return "EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_ASSIGNMENT_EXPRESSION: return "ASSIGNMENT_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION: return "CONDITIONAL_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_LOGICAL_OR_EXPRESSION: return "LOGICAL_OR_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION: return "LOGICAL_AND_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION: return "INCLUSIVE_OR_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION: return "EXCLUSIVE_OR_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION: return "BOOLEAN_AND_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION: return "EQUALITY_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION: return "RELATIONAL_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION: return "SHIFT_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION: return "ADDITIVE_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION: return "MULTIPLICATIVE_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION: return "UNARY_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION: return "POST_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION: return "PRIMARY_EXPRESSION";
+ case CSCRIPTCOMPILER_GRAMMAR_CONSTANT: return "CONSTANT";
+ }
+ return "(unknown grammar)";
+}
+
+
+const char *OperationToString(int nOperation)
+{
+ switch (nOperation)
+ {
+ case CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT: return "COMPOUND_STATEMENT";
+ case CSCRIPTCOMPILER_OPERATION_STATEMENT: return "STATEMENT";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION: return "KEYWORD_DECLARATION";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_INT: return "KEYWORD_INT";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT: return "KEYWORD_FLOAT";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING: return "KEYWORD_STRING";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT: return "KEYWORD_OBJECT";
+ case CSCRIPTCOMPILER_OPERATION_VARIABLE_LIST: return "VARIABLE_LIST";
+ case CSCRIPTCOMPILER_OPERATION_VARIABLE: return "VARIABLE";
+ case CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST: return "STATEMENT_LIST";
+ case CSCRIPTCOMPILER_OPERATION_IF_BLOCK: return "IF_BLOCK";
+ case CSCRIPTCOMPILER_OPERATION_IF_CHOICE: return "IF_CHOICE";
+ case CSCRIPTCOMPILER_OPERATION_IF_CONDITION: return "IF_CONDITION";
+ case CSCRIPTCOMPILER_OPERATION_ACTION: return "ACTION";
+ case CSCRIPTCOMPILER_OPERATION_ACTION_ID: return "ACTION_ID";
+ case CSCRIPTCOMPILER_OPERATION_ASSIGNMENT: return "ASSIGNMENT";
+ case CSCRIPTCOMPILER_OPERATION_ACTION_ARG_LIST: return "ACTION_ARG_LIST";
+ case CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER: return "CONSTANT_INTEGER";
+ case CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT: return "CONSTANT_FLOAT";
+ case CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING: return "CONSTANT_STRING";
+ case CSCRIPTCOMPILER_OPERATION_INTEGER_EXPRESSION: return "INTEGER_EXPRESSION";
+ case CSCRIPTCOMPILER_OPERATION_NON_VOID_EXPRESSION: return "NON_VOID_EXPRESSION";
+ case CSCRIPTCOMPILER_OPERATION_LOGICAL_OR: return "LOGICAL_OR";
+ case CSCRIPTCOMPILER_OPERATION_LOGICAL_AND: return "LOGICAL_AND";
+ case CSCRIPTCOMPILER_OPERATION_INCLUSIVE_OR: return "INCLUSIVE_OR";
+ case CSCRIPTCOMPILER_OPERATION_EXCLUSIVE_OR: return "EXCLUSIVE_OR";
+ case CSCRIPTCOMPILER_OPERATION_BOOLEAN_AND: return "BOOLEAN_AND";
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL: return "CONDITION_EQUAL";
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_NOT_EQUAL: return "CONDITION_NOT_EQUAL";
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_GEQ: return "CONDITION_GEQ";
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_GT: return "CONDITION_GT";
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_LT: return "CONDITION_LT";
+ case CSCRIPTCOMPILER_OPERATION_CONDITION_LEQ: return "CONDITION_LEQ";
+ case CSCRIPTCOMPILER_OPERATION_SHIFT_LEFT: return "SHIFT_LEFT";
+ case CSCRIPTCOMPILER_OPERATION_SHIFT_RIGHT: return "SHIFT_RIGHT";
+ case CSCRIPTCOMPILER_OPERATION_ADD: return "ADD";
+ case CSCRIPTCOMPILER_OPERATION_SUBTRACT: return "SUBTRACT";
+ case CSCRIPTCOMPILER_OPERATION_MULTIPLY: return "MULTIPLY";
+ case CSCRIPTCOMPILER_OPERATION_DIVIDE: return "DIVIDE";
+ case CSCRIPTCOMPILER_OPERATION_MODULUS: return "MODULUS";
+ case CSCRIPTCOMPILER_OPERATION_NEGATION: return "NEGATION";
+ case CSCRIPTCOMPILER_OPERATION_ACTION_PARAMETER: return "ACTION_PARAMETER";
+ case CSCRIPTCOMPILER_OPERATION_UNSIGNED_SHIFT_RIGHT: return "UNSIGNED_SHIFT_RIGHT";
+ case CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART: return "STRUCTURE_PART";
+ case CSCRIPTCOMPILER_OPERATION_ONES_COMPLEMENT: return "ONES_COMPLEMENT";
+ case CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK: return "WHILE_BLOCK";
+ case CSCRIPTCOMPILER_OPERATION_WHILE_CHOICE: return "WHILE_CHOICE";
+ case CSCRIPTCOMPILER_OPERATION_WHILE_CONDITION: return "WHILE_CONDITION";
+ case CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK: return "DOWHILE_BLOCK";
+ case CSCRIPTCOMPILER_OPERATION_DOWHILE_CONDITION: return "DOWHILE_CONDITION";
+ case CSCRIPTCOMPILER_OPERATION_FUNCTIONAL_UNIT: return "FUNCTIONAL_UNIT";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT: return "KEYWORD_STRUCT";
+ case CSCRIPTCOMPILER_OPERATION_STRUCTURE_DEFINITION: return "STRUCTURE_DEFINITION";
+ case CSCRIPTCOMPILER_OPERATION_FUNCTION_IDENTIFIER: return "FUNCTION_IDENTIFIER";
+ case CSCRIPTCOMPILER_OPERATION_FUNCTION_DECLARATION: return "FUNCTION_DECLARATION";
+ case CSCRIPTCOMPILER_OPERATION_FUNCTION: return "FUNCTION";
+ case CSCRIPTCOMPILER_OPERATION_FUNCTION_PARAM_NAME: return "FUNCTION_PARAM_NAME";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID: return "KEYWORD_VOID";
+ case CSCRIPTCOMPILER_OPERATION_RETURN: return "RETURN";
+ case CSCRIPTCOMPILER_OPERATION_BOOLEAN_NOT: return "BOOLEAN_NOT";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0: return "KEYWORD_ENGINE_STRUCTURE0";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE1: return "KEYWORD_ENGINE_STRUCTURE1";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE2: return "KEYWORD_ENGINE_STRUCTURE2";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE3: return "KEYWORD_ENGINE_STRUCTURE3";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE4: return "KEYWORD_ENGINE_STRUCTURE4";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE5: return "KEYWORD_ENGINE_STRUCTURE5";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE6: return "KEYWORD_ENGINE_STRUCTURE6";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE7: return "KEYWORD_ENGINE_STRUCTURE7";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE8: return "KEYWORD_ENGINE_STRUCTURE8";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE9: return "KEYWORD_ENGINE_STRUCTURE9";
+ case CSCRIPTCOMPILER_OPERATION_CONSTANT_OBJECT: return "CONSTANT_OBJECT";
+ case CSCRIPTCOMPILER_OPERATION_KEYWORD_VECTOR: return "KEYWORD_VECTOR";
+ case CSCRIPTCOMPILER_OPERATION_CONSTANT_VECTOR: return "CONSTANT_VECTOR";
+ case CSCRIPTCOMPILER_OPERATION_GLOBAL_VARIABLES: return "GLOBAL_VARIABLES";
+ case CSCRIPTCOMPILER_OPERATION_POST_INCREMENT: return "POST_INCREMENT";
+ case CSCRIPTCOMPILER_OPERATION_POST_DECREMENT: return "POST_DECREMENT";
+ case CSCRIPTCOMPILER_OPERATION_PRE_INCREMENT: return "PRE_INCREMENT";
+ case CSCRIPTCOMPILER_OPERATION_PRE_DECREMENT: return "PRE_DECREMENT";
+ case CSCRIPTCOMPILER_OPERATION_COND_BLOCK: return "COND_BLOCK";
+ case CSCRIPTCOMPILER_OPERATION_COND_CHOICE: return "COND_CHOICE";
+ case CSCRIPTCOMPILER_OPERATION_COND_CONDITION: return "COND_CONDITION";
+ case CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK: return "SWITCH_BLOCK";
+ case CSCRIPTCOMPILER_OPERATION_SWITCH_CONDITION: return "SWITCH_CONDITION";
+ case CSCRIPTCOMPILER_OPERATION_DEFAULT: return "DEFAULT";
+ case CSCRIPTCOMPILER_OPERATION_CASE: return "CASE";
+ case CSCRIPTCOMPILER_OPERATION_BREAK: return "BREAK";
+ case CSCRIPTCOMPILER_OPERATION_CONTINUE: return "CONTINUE";
+ case CSCRIPTCOMPILER_OPERATION_WHILE_CONTINUE: return "WHILE_CONTINUE";
+ case CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG: return "STATEMENT_NO_DEBUG";
+ case CSCRIPTCOMPILER_OPERATION_FOR_BLOCK: return "FOR_BLOCK";
+ case CSCRIPTCOMPILER_OPERATION_CONST_DECLARATION: return "CONST_DECLARATION";
+ case CSCRIPTCOMPILER_OPERATION_CONSTANT_JSON: return "CONSTANT_JSON";
+ case CSCRIPTCOMPILER_OPERATION_CONSTANT_LOCATION: return "CONSTANT_LOCATION";
+ }
+ return "(unknown operation)";
+}
+
diff --git a/src/Native Compiler/scriptcompfinalcode.cpp b/src/Native Compiler/scriptcompfinalcode.cpp
new file mode 100644
index 0000000..47ef2bc
--- /dev/null
+++ b/src/Native Compiler/scriptcompfinalcode.cpp
@@ -0,0 +1,7059 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Script Project
+//::
+//:: Copyright (c) 2001, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ScriptCompFinalCode.cpp
+//::
+//:: Implementation of changing the parse tree into a piece of code that we
+//:: can deal with.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: October 8, 2002
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: This file contains "ported" code (used when writing out floating point
+//:: numbers on the MacIntosh platforms).
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+// external header files
+#include "exobase.h"
+#include "scriptcomp.h"
+
+// internal header files
+#include "scriptinternal.h"
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Class CScriptCompiler
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GenerateCodeFromParseTree()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/26/2000
+// Description: Clears out the user defined identifiers.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::GenerateFinalCodeFromParseTree(CExoString sFileName)
+{
+
+ int nState;
+ int nRule;
+ int nTerm;
+ CScriptParseTreeNode *pCurrentTree;
+ CScriptParseTreeNode *pReturnTree;
+ CScriptParseTreeNode *pNewReturnTree; // after the global variables have been re-added.
+
+ PopSRStack(&nState,&nRule,&nTerm,&pCurrentTree,&pReturnTree);
+
+ m_nTotalCompileNodes = 1;
+
+ int32_t nReturnValue = InstallLoader();
+ pNewReturnTree = InsertGlobalVariablesInParseTree(pReturnTree);
+ if (nReturnValue >= 0)
+ {
+ nReturnValue = WalkParseTree(pNewReturnTree);
+ }
+ else
+ {
+ OutputWalkTreeError(nReturnValue, NULL);
+ }
+
+ if (nReturnValue < 0)
+ {
+ return CleanUpAfterCompile(nReturnValue,pNewReturnTree);
+ }
+ else
+ {
+ nReturnValue = DetermineLocationOfCode();
+ if (nReturnValue >= 0)
+ {
+ nReturnValue = ResolveLabels();
+ }
+ if (nReturnValue >= 0)
+ {
+ ResolveDebuggingInformation();
+
+ nReturnValue = WriteResolvedOutput();
+ }
+ if (nReturnValue >= 0)
+ {
+ nReturnValue = WriteDebuggerOutputToFile(sFileName);
+ }
+ if (nReturnValue < 0)
+ {
+ return CleanUpAfterCompile(nReturnValue,pNewReturnTree);
+ }
+ return CleanUpAfterCompile(0,pNewReturnTree);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::InitializeFinalCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/16/2001
+// Description: Sets up all of the data structures for the development of
+// the final game code.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::InitializeFinalCode()
+{
+ if (m_pchOutputCode == NULL)
+ {
+ m_pchOutputCode = new char[CSCRIPTCOMPILER_MAX_CODE_SIZE];
+ m_nOutputCodeSize = CSCRIPTCOMPILER_MAX_CODE_SIZE;
+ }
+
+ sprintf(m_pchOutputCode,"NCS V1.0");
+ m_nOutputCodeLength = CVIRTUALMACHINE_BINARY_SCRIPT_HEADER;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::FinalizeFinalCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/16/2001
+// Description: Finishes off the data structures for the development of
+// the final game code.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::FinalizeFinalCode()
+{
+ m_pchOutputCode[8] = (char) 'B';
+ m_pchOutputCode[9] = (char) ((m_nOutputCodeLength >> 24) & 0xff);
+ m_pchOutputCode[10] = (char) ((m_nOutputCodeLength >> 16) & 0xff);
+ m_pchOutputCode[11] = (char) ((m_nOutputCodeLength >> 8) & 0xff);
+ m_pchOutputCode[12] = (char) ((m_nOutputCodeLength) & 0xff);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::WriteFinalCodeToFile()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/16/2001
+// Description: Outputs the final code to the file for later use.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::WriteFinalCodeToFile(const CExoString &sFileName)
+{
+
+ CExoString sModifiedFileName;
+ sModifiedFileName.Format("%s:%s",m_sOutputAlias.CStr(),sFileName.CStr());
+
+ const int32_t ret = m_cAPI.ResManWriteToFile(
+ sModifiedFileName.CStr(), m_nResTypeCompiled,
+ (const uint8_t*) m_pchOutputCode, m_nOutputCodeLength, true);
+
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ if (m_bAutomaticCleanUpAfterCompiles == TRUE)
+ {
+ CExoString sDirectoryFileName;
+
+ sDirectoryFileName.Format("%s:",m_sOutputAlias.CStr());
+ m_cAPI.ResManUpdateResourceDirectory(sDirectoryFileName.CStr());
+
+ // Delete the code.
+ if (m_pchOutputCode != NULL)
+ {
+ delete[] m_pchOutputCode;
+ m_pchOutputCode = NULL;
+ }
+
+ m_nOutputCodeLength = 0;
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ClearUserDefinedIdentifiers()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/26/2000
+// Description: Clears out the user defined identifiers.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::ClearUserDefinedIdentifiers()
+{
+ for (int32_t count = m_nOccupiedIdentifiers - 1; count >= m_nMaxPredefinedIdentifierId; --count)
+ {
+ HashManagerDelete(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER, count);
+
+ m_pcIdentifierList[count].m_psIdentifier = "";
+ m_pcIdentifierList[count].m_nIdentifierLength = 0;
+ m_pcIdentifierList[count].m_nIdentifierHash = 0;
+ m_pcIdentifierList[count].m_nIdentifierType = 0;
+ m_pcIdentifierList[count].m_nReturnType = 0;
+ m_pcIdentifierList[count].m_bImplementationInPlace = FALSE;
+ m_pcIdentifierList[count].m_psStructureReturnName = "";
+
+ // For constants ...
+ m_pcIdentifierList[count].m_psStringData = "";
+ m_pcIdentifierList[count].m_nIntegerData = 0;
+ m_pcIdentifierList[count].m_fFloatData = 0.0;
+ // For identifiers ..
+ m_pcIdentifierList[count].m_nIdIdentifier = -1;
+ m_pcIdentifierList[count].m_nParameters = 0;
+ m_pcIdentifierList[count].m_nNonOptionalParameters = 0;
+ m_pcIdentifierList[count].m_nParameterSpace = 0;
+
+ if (m_pcIdentifierList[count].m_pchParameters)
+ {
+ delete[] m_pcIdentifierList[count].m_pchParameters;
+ m_pcIdentifierList[count].m_pchParameters = NULL;
+ }
+ if (m_pcIdentifierList[count].m_psStructureParameterNames)
+ {
+ delete[] m_pcIdentifierList[count].m_psStructureParameterNames;
+ m_pcIdentifierList[count].m_psStructureParameterNames = NULL;
+ }
+ if (m_pcIdentifierList[count].m_pbOptionalParameters)
+ {
+ delete[] m_pcIdentifierList[count].m_pbOptionalParameters;
+ m_pcIdentifierList[count].m_pbOptionalParameters = NULL;
+ }
+ if (m_pcIdentifierList[count].m_pnOptionalParameterIntegerData)
+ {
+ delete[] m_pcIdentifierList[count].m_pnOptionalParameterIntegerData;
+ m_pcIdentifierList[count].m_pnOptionalParameterIntegerData = NULL;
+ }
+ if (m_pcIdentifierList[count].m_pfOptionalParameterFloatData)
+ {
+ delete[] m_pcIdentifierList[count].m_pfOptionalParameterFloatData;
+ m_pcIdentifierList[count].m_pfOptionalParameterFloatData = NULL;
+ }
+ if (m_pcIdentifierList[count].m_psOptionalParameterStringData)
+ {
+ delete[] m_pcIdentifierList[count].m_psOptionalParameterStringData;
+ m_pcIdentifierList[count].m_psOptionalParameterStringData = NULL;
+ }
+ if (m_pcIdentifierList[count].m_poidOptionalParameterObjectData)
+ {
+ delete[] m_pcIdentifierList[count].m_poidOptionalParameterObjectData;
+ m_pcIdentifierList[count].m_poidOptionalParameterObjectData = NULL;
+ }
+ if (m_pcIdentifierList[count].m_pfOptionalParameterVectorData)
+ {
+ delete[] m_pcIdentifierList[count].m_pfOptionalParameterVectorData;
+ m_pcIdentifierList[count].m_pfOptionalParameterVectorData = NULL;
+ }
+
+
+ // For user-defined identifiers
+ m_pcIdentifierList[count].m_nBinarySourceStart = -1;
+ m_pcIdentifierList[count].m_nBinarySourceFinish = -1;
+ m_pcIdentifierList[count].m_nBinaryDestinationStart = -1;
+ m_pcIdentifierList[count].m_nBinaryDestinationFinish = -1;
+
+ }
+
+ m_nOccupiedIdentifiers = m_nMaxPredefinedIdentifierId;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ClearAllSymbolLists()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/26/2000
+// Description: Clears out the query and label symbol lists.
+///////////////////////////////////////////////////////////////////////////////
+
+
+void CScriptCompiler::ClearAllSymbolLists()
+{
+ if (m_pSymbolQueryList != NULL)
+ {
+ delete[] m_pSymbolQueryList;
+ m_pSymbolQueryList = NULL;
+ }
+
+ m_nSymbolQueryListSize = 0;
+ m_nSymbolQueryList = 0;
+
+ if (m_pSymbolLabelList != NULL)
+ {
+ delete[] m_pSymbolLabelList;
+ m_pSymbolLabelList = NULL;
+ }
+
+ m_nSymbolLabelListSize = 0;
+ m_nSymbolLabelList = 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CleanUpAfterCompile()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/26/2000
+// Description: This routine will delete all of the data associated with the
+// current compile tree.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::CleanUpAfterCompile(int32_t nReturnValue,CScriptParseTreeNode *pReturnTree)
+{
+ DeleteParseTree(FALSE, pReturnTree);
+ if (nReturnValue < 0)
+ {
+ if (m_bAutomaticCleanUpAfterCompiles == TRUE)
+ {
+ ClearCompiledScriptCode();
+ }
+ else
+ {
+ m_nOutputCodeLength = 0;
+ }
+ }
+ DeleteParseTree(FALSE, m_pGlobalVariableParseTree);
+ m_pGlobalVariableParseTree = NULL;
+ ClearUserDefinedIdentifiers();
+ ClearAllSymbolLists();
+ m_aOutputCodeInstructionBoundaries.resize(0);
+
+ // Reset the state of the ConditionalFile boolean.
+ if (m_bCompileConditionalOrMain == TRUE)
+ {
+ m_bCompileConditionalFile = m_bOldCompileConditionalFile;
+ }
+
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::OutputWalkTreeError()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/27/99
+// Description: This routine spews out an error message to the log file when
+// we encounter an error during the semantic phase of the
+// parsing (i.e. we're now walking the tree).
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::OutputWalkTreeError(int32_t nError, CScriptParseTreeNode *pNode)
+{
+ CExoString strRes = m_cAPI.TlkResolve(-nError);
+
+ CExoString *psFileName;
+ if (pNode != NULL && pNode->m_nFileReference != -1)
+ {
+ psFileName = m_ppsParseTreeFileNames[pNode->m_nFileReference];
+ }
+ else
+ {
+ psFileName = &(m_pcIncludeFileStack[m_nCompileFileLevel].m_sCompiledScriptName);
+ }
+
+ int32_t nLine;
+ if (pNode != NULL)
+ {
+ nLine = pNode->nLine;
+ }
+ else
+ {
+ nLine = 0;
+ }
+
+ OutputError(nError,psFileName,nLine,strRes);
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_ALREADY_PRINTED;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::InsertGlobalVariablesInParseTree()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/09/2001
+// Description: Adds the global variable tree into the main compile tree.
+///////////////////////////////////////////////////////////////////////////////
+
+CScriptParseTreeNode *CScriptCompiler::InsertGlobalVariablesInParseTree(CScriptParseTreeNode *pOldTree)
+{
+ // If there's nothing to add, why are we here?
+ if (m_pGlobalVariableParseTree == NULL)
+ {
+ return pOldTree;
+ }
+
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_FUNCTIONAL_UNIT,m_pGlobalVariableParseTree,pOldTree);
+ m_pGlobalVariableParseTree = NULL;
+
+ return pNewNode;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::InstallLoader()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: A quick utility ... this routine should be run before we
+// start compiling code, because this will add the important
+// JSR FE_main/RET pair that closes out a script.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::InstallLoader()
+{
+ // Mark instruction boundary before the first JSR instruction.
+ // This is immediately after the header and is always at offset 13
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Verify "main" is a void-returning function that is actually
+ // declared within this script.
+
+ int32_t nMainIdentifier;
+
+ if (m_bCompileConditionalOrMain == TRUE)
+ {
+ // Save the state of the CompileConditionalFile flag.
+ // It will be restored in CleanUpAfterCompile!
+ m_bOldCompileConditionalFile = m_bCompileConditionalFile;
+
+ nMainIdentifier = GetIdentifierByName("main");
+ if (nMainIdentifier >= 0)
+ {
+ // This is a void main() script, and should compile!
+ m_bCompileConditionalFile = FALSE;
+ }
+ else
+ {
+ nMainIdentifier = GetIdentifierByName("StartingConditional");
+ if (nMainIdentifier >= 0)
+ {
+ // This is a conditional script, and should compile!
+ m_bCompileConditionalFile = TRUE;
+ }
+ else
+ {
+ // Neither are present, so we're going to error just as
+ // if we are expecting a void main() function!
+ m_bCompileConditionalFile = FALSE;
+ }
+ }
+ }
+
+ if (m_bCompileConditionalFile == FALSE)
+ {
+ nMainIdentifier = GetIdentifierByName("main");
+ if (nMainIdentifier < 0)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_NO_FUNCTION_MAIN_IN_SCRIPT;
+ }
+
+ if (m_pcIdentifierList[nMainIdentifier].m_nReturnType != CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_MAIN_MUST_HAVE_VOID_RETURN_VALUE;
+ }
+
+ if (m_pcIdentifierList[nMainIdentifier].m_nParameters != 0)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_MAIN_MUST_HAVE_NO_PARAMETERS;
+ }
+ }
+ else
+ {
+ // If m_bCompileConditionalFile == TRUE, then the only possible choice
+ // for what to compile is int StartingConditional()
+
+ nMainIdentifier = GetIdentifierByName("StartingConditional");
+ if (nMainIdentifier < 0)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_NO_FUNCTION_INTSC_IN_SCRIPT;
+ }
+
+ if (m_pcIdentifierList[nMainIdentifier].m_nReturnType != CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_INTSC_MUST_HAVE_VOID_RETURN_VALUE;
+ }
+
+ if (m_pcIdentifierList[nMainIdentifier].m_nParameters != 0)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_INTSC_MUST_HAVE_NO_PARAMETERS;
+ }
+ }
+
+
+ BOOL bGlobalVariablesPresent = FALSE;
+ if (m_pGlobalVariableParseTree != NULL)
+ {
+ bGlobalVariablesPresent = TRUE;
+ }
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psIdentifier = "#loader";
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierHash = HashString("#loader");
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierLength = 7;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceStart = m_nOutputCodeLength;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationStart = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationFinish = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nParameters = 0;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER;
+ HashManagerAdd(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER, m_nOccupiedIdentifiers);
+
+ // Add the JSR FE_main OR FE_#globals instruction, depending on whether
+ // there are global variables or not.
+ //
+ // Here, we will need to write a symbol into the code and
+ // mark the location for updating during the label generation pass.
+
+ if (m_pcIdentifierList[nMainIdentifier].m_nReturnType == CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER;
+
+ ++m_nOccupiedVariables;
+
+ ++m_nVarStackRecursionLevel;
+ ++m_nGlobalVariables;
+
+
+ m_pcVarStackList[m_nOccupiedVariables].m_psVarName = "#retval";
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarLevel = m_nVarStackRecursionLevel;
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarRunTimeLocation = m_nStackCurrentDepth * 4;
+
+ int32_t nOccupiedVariables = m_nOccupiedVariables;
+ int32_t nStackCurrentDepth = m_nStackCurrentDepth;
+ int32_t nGlobalVariableSize = m_nGlobalVariableSize;
+
+ // Now, we can add the variable to the run time stack (to write the code), and then
+ // immediately remove it. This makes NO sense whatsoever, right? Well, imagine this ...
+ // what happens if we already have a spot allocated from the calling function for this
+ // return variable?
+
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT, NULL, TRUE);
+ AddToSymbolTableVarStack(nOccupiedVariables,nStackCurrentDepth,nGlobalVariableSize);
+
+ --m_nStackCurrentDepth;
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JSR;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // There is no point in expressing this yet, because we haven't decided on the
+ // locations of any of the final functions in the executable. So, write
+ // the symbol into the table.
+
+ //CExoString sSymbolName;
+ int32_t nSymbolSubType1 = 0;
+ int32_t nSymbolSubType2 = 0;
+ if (bGlobalVariablesPresent)
+ {
+ //sSymbolName.Format("FE_#globals");
+ nSymbolSubType2 = 1;
+ }
+ else
+ {
+ nSymbolSubType2 = 2;
+ /*
+ if (m_bCompileConditionalFile == TRUE)
+ {
+ sSymbolName.Format("FE_StartingConditional");
+ }
+ else
+ {
+ sSymbolName.Format("FE_main");
+ }
+ */
+ }
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,
+ nSymbolSubType1,nSymbolSubType2);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RET;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Last, but not least, add a function to the user-defined identifier list
+ // that specifies where this code is located.
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceFinish = m_nOutputCodeLength;
+
+ ++m_nOccupiedIdentifiers;
+ if (m_nOccupiedIdentifiers >= CSCRIPTCOMPILER_MAX_IDENTIFIERS)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_IDENTIFIER_LIST_FULL, NULL);
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::DetermineLocationOfCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: This function is responsible for determining which functions
+// are required in the script, and which ones will be left out.
+// Calls ValidateLocationOfIdentifier (recursively) to determine
+// all of this.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::DetermineLocationOfCode()
+{
+ if (m_nOptimizationFlags & CSCRIPTCOMPILER_OPTIMIZE_DEAD_FUNCTIONS)
+ {
+ // Here, we have to compress the language into something that
+ // we can deal with on a small level.
+ m_nFinalBinarySize = CVIRTUALMACHINE_BINARY_SCRIPT_HEADER;
+ return ValidateLocationOfIdentifier("#loader");
+
+ }
+ else
+ {
+ m_nFinalBinarySize = m_nOutputCodeLength;
+
+ for (int32_t count2 = m_nMaxPredefinedIdentifierId; count2 < m_nOccupiedIdentifiers; count2++)
+ {
+ if (m_pcIdentifierList[count2].m_nBinarySourceStart != -1)
+ {
+ m_pcIdentifierList[count2].m_nBinaryDestinationStart = m_pcIdentifierList[count2].m_nBinarySourceStart;
+ m_pcIdentifierList[count2].m_nBinaryDestinationFinish = m_pcIdentifierList[count2].m_nBinarySourceFinish;
+ }
+ }
+
+ return 0;
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ValidateLocationOfIdentifier()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: This function is responsible for determining which functions
+// are required in the script, and which ones will be left out.
+// Calls itself recursively on all of the functions that are
+// called within this function to see if they're already in the
+// script, and add them if they aren't.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ValidateLocationOfIdentifier(const CExoString &sFunctionName)
+{
+ int32_t nIdentifier = GetIdentifierByName(sFunctionName);
+
+ if (nIdentifier < 0)
+ {
+ return OutputIdentifierError(sFunctionName,nIdentifier,0);
+ }
+
+ if (m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart != -1)
+ {
+ return 0;
+ }
+
+ int32_t nFunctionSize = m_pcIdentifierList[nIdentifier].m_nBinarySourceFinish -
+ m_pcIdentifierList[nIdentifier].m_nBinarySourceStart;
+
+ m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart = m_nFinalBinarySize;
+ m_pcIdentifierList[nIdentifier].m_nBinaryDestinationFinish = m_nFinalBinarySize + nFunctionSize;
+
+ m_nFinalBinarySize += nFunctionSize;
+
+ // Now, this is where it gets EXCITING. We reference all of the
+ // functions that this routine could potentially call, and add
+ // them to the list, too!
+
+ CExoString sNewFunctionName;
+ int32_t nReturnValue;
+
+ for (int32_t count = 0; count < m_nSymbolQueryList; count++)
+ {
+ if (m_pSymbolQueryList[count].m_nLocationPointer >= m_pcIdentifierList[nIdentifier].m_nBinarySourceStart &&
+ m_pSymbolQueryList[count].m_nLocationPointer < m_pcIdentifierList[nIdentifier].m_nBinarySourceFinish)
+ {
+ // Make sure the query is for a function label, and NOT a switch or continue statement.
+ if (m_pSymbolQueryList[count].m_nSymbolType == CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY)
+ {
+ sNewFunctionName = GetFunctionNameFromSymbolSubTypes(m_pSymbolQueryList[count].m_nSymbolSubType1,
+ m_pSymbolQueryList[count].m_nSymbolSubType2);
+
+ // Get the function name!
+ //sNewFunctionName = m_pSymbolQueryList[count].m_sSymbolName.Right(m_pSymbolQueryList[count].m_sSymbolName.GetLength() - 3);
+ nReturnValue = ValidateLocationOfIdentifier(sNewFunctionName);
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::OutputIdentifierError()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: Spits out the error when accessing things in the resolution
+// identifiers (nLine and nChar aren't really available at this
+// point, so it makes sense to just refer to the function.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::OutputIdentifierError(const CExoString &sFunctionName, int32_t nError, int32_t nFileStackDrop)
+{
+ CExoString strRes = m_cAPI.TlkResolve(-nError);
+
+ //g_pTlkTable->Fetch(-nError, strRes);
+ int32_t nFileStackEntry = m_nCompileFileLevel - nFileStackDrop;
+ if (nFileStackEntry < 0)
+ {
+ nFileStackEntry = 0;
+ }
+
+ CExoString *psFileName = &(m_pcIncludeFileStack[nFileStackEntry].m_sCompiledScriptName);
+ CExoString sErrorText;
+ sErrorText.Format("%s (%s)",strRes.CStr(),sFunctionName.CStr());
+ OutputError(nError,psFileName,0,sErrorText);
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_ALREADY_PRINTED;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ResolveLabels()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: This function will resolve all of the labels, based on the
+// final location of the functions within the script.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ResolveLabels()
+{
+
+ CExoString sFunctionName;
+ BOOL bFoundLabel;
+ BOOL bFoundIdentifier;
+
+ for (int32_t count = 0; count < m_nSymbolQueryList; count++)
+ {
+
+ // Resolve the location of where we will be writing the address
+ // for the label we're lookin' for.
+ int32_t nResolvedLocationOfAddress = m_pSymbolQueryList[count].m_nLocationPointer;
+
+ int32_t nQueryIdentifier = 0;
+ int32_t count2;
+ bFoundIdentifier = FALSE;
+ for (count2 = m_nMaxPredefinedIdentifierId; count2 < m_nOccupiedIdentifiers; count2++)
+ {
+ if (nResolvedLocationOfAddress >= m_pcIdentifierList[count2].m_nBinarySourceStart &&
+ nResolvedLocationOfAddress < m_pcIdentifierList[count2].m_nBinarySourceFinish)
+ {
+ bFoundIdentifier = TRUE;
+ nQueryIdentifier = count2;
+ }
+ }
+
+ // If this happens, we're in REAL trouble, but we'll return out of
+ // this routine in any case (the query had to be derived from ONE
+ // of the functions!)
+
+ if (bFoundIdentifier == FALSE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER, NULL);
+ }
+
+ // Now, check to see if the query even BELONGS in the final file.
+ // If it does, follow up and generate a value for it.
+
+ if (m_pcIdentifierList[nQueryIdentifier].m_nBinaryDestinationStart != -1)
+ {
+
+ nResolvedLocationOfAddress += (m_pcIdentifierList[nQueryIdentifier].m_nBinaryDestinationStart -
+ m_pcIdentifierList[nQueryIdentifier].m_nBinarySourceStart);
+
+ // Now, we actually dig out where the "label" has been moved to
+ // in the code.
+
+ bFoundLabel = FALSE;
+ int32_t nQueryHash = m_pSymbolQueryList[count].m_nSymbolSubType1 & 0x01ff;
+
+ count2 = m_pSymbolLabelStartEntry[nQueryHash];
+
+ while (count2 != -1 && bFoundLabel == FALSE)
+ {
+ if (m_pSymbolQueryList[count].m_nSymbolSubType1 == m_pSymbolLabelList[count2].m_nSymbolSubType1 &&
+ m_pSymbolQueryList[count].m_nSymbolSubType2 == m_pSymbolLabelList[count2].m_nSymbolSubType2 &&
+ m_pSymbolQueryList[count].m_nSymbolType == m_pSymbolLabelList[count2].m_nSymbolType)
+ {
+ int32_t nIdentifier;
+ if (m_pSymbolQueryList[count].m_nSymbolType == CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY ||
+ m_pSymbolQueryList[count].m_nSymbolType == CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_EXIT)
+ {
+ if (m_pSymbolQueryList[count].m_nSymbolSubType2 == 0 &&
+ m_pSymbolQueryList[count].m_nSymbolSubType1 != 0)
+ {
+ nIdentifier = m_pSymbolQueryList[count].m_nSymbolSubType1;
+ }
+ else
+ {
+ // For main, StartingConditional and #globals, we should go through these hoops.
+ CExoString sNewFunctionName = GetFunctionNameFromSymbolSubTypes(m_pSymbolQueryList[count].m_nSymbolSubType1,
+ m_pSymbolQueryList[count].m_nSymbolSubType2);
+ nIdentifier = GetIdentifierByName(sNewFunctionName);
+ if (nIdentifier < 0)
+ {
+ if (sNewFunctionName == "")
+ {
+ // Sorry, dude ... this shouldn't have happened under any circumstance.
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER, NULL);
+ }
+
+ return OutputIdentifierError(sNewFunctionName,nIdentifier,0);
+ }
+ }
+ }
+ else
+ {
+ // The label does not contain a function name, so it is more than likely within the same function as the query.
+ nIdentifier = nQueryIdentifier;
+ }
+
+ int32_t nResolvedAddress = m_pSymbolLabelList[count2].m_nLocationPointer + (m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart - m_pcIdentifierList[nIdentifier].m_nBinarySourceStart);
+
+ // Now that we have the two, we can subtract the two from
+ // one another, and write that relative JMP into the code.
+
+ // DON'T FORGET TO REMOVE THE OPERATION_BASE_SIZE, TOO!
+ // Without it, you won't have the true instruction pointer,
+ // since the label only stores where the label belongs in
+ // the source code!
+
+ int32_t nJmpLength = nResolvedAddress - (nResolvedLocationOfAddress - CVIRTUALMACHINE_OPERATION_BASE_SIZE);
+
+ // ... and write it into its appropriate location.
+ m_pchOutputCode[m_pSymbolQueryList[count].m_nLocationPointer] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[m_pSymbolQueryList[count].m_nLocationPointer + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[m_pSymbolQueryList[count].m_nLocationPointer + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[m_pSymbolQueryList[count].m_nLocationPointer + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ bFoundLabel = TRUE;
+ }
+
+ count2 = m_pSymbolLabelList[count2].m_nNextEntryPointer;
+ }
+
+ if (bFoundLabel == FALSE)
+ {
+ CExoString sNewFunctionName = GetFunctionNameFromSymbolSubTypes(m_pSymbolQueryList[count].m_nSymbolSubType1,
+ m_pSymbolQueryList[count].m_nSymbolSubType2);
+ if (sNewFunctionName == "")
+ {
+ // Sorry, dude ... this shouldn't have happened under any circumstance.
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER, NULL);
+ }
+
+ return OutputIdentifierError(sFunctionName,STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER,0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::InitializeSwitchLabelList()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/25/2000
+// Description: This function will resolve the labels within this level of
+// switch statement.
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::InitializeSwitchLabelList()
+{
+ m_bSwitchLabelDefault = FALSE;
+ m_nSwitchLabelNumber = 0;
+ m_nSwitchLabelArraySize = 16;
+ m_pnSwitchLabelStatements = new int32_t[m_nSwitchLabelArraySize];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::TraverseTreeForSwitchLabels()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/25/2000
+// Description: This function will resolve the labels within this level of
+// switch statement.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::TraverseTreeForSwitchLabels(CScriptParseTreeNode *pNode)
+{
+ // First, we scan to see if there are multiple labels of the same type.
+ int nReturnValue;
+
+ if (pNode == NULL)
+ {
+ return 0;
+ }
+ // First of all, if we are about to go into another switch block, abort!
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK)
+ {
+ return 0;
+ }
+
+ nReturnValue = TraverseTreeForSwitchLabels(pNode->pLeft);
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DEFAULT)
+ {
+ if (m_bSwitchLabelDefault == TRUE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_MULTIPLE_DEFAULT_STATEMENTS_WITHIN_SWITCH, pNode);
+ }
+ m_bSwitchLabelDefault = TRUE;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CASE)
+ {
+ int32_t nCaseValue;
+
+ ConstantFoldNode(pNode->pLeft, TRUE);
+ // Evaluate the constant value that is contained.
+ if (pNode->pLeft != NULL &&
+ pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_NEGATION &&
+ pNode->pLeft->pLeft != NULL &&
+ pNode->pLeft->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ nCaseValue = -pNode->pLeft->pLeft->nIntegerData;
+ }
+ else if (pNode->pLeft != NULL &&
+ pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ nCaseValue = pNode->pLeft->nIntegerData;
+ }
+ else if (pNode->pLeft != NULL &&
+ pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING)
+ {
+ nCaseValue = pNode->pLeft->m_psStringData->GetHash();
+ }
+ else
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_CASE_PARAMETER_NOT_A_CONSTANT_INTEGER,pNode);
+ }
+
+ // Now, we have to check if any of the previous case statements have the same value.
+ int nCount;
+
+ for (nCount = 0; nCount < m_nSwitchLabelNumber; ++nCount)
+ {
+ if (m_pnSwitchLabelStatements[nCount] == nCaseValue)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_MULTIPLE_CASE_CONSTANT_STATEMENTS_WITHIN_SWITCH,pNode);
+ }
+ }
+
+ // Add the case statement to the list.
+ if (m_nSwitchLabelNumber >= m_nSwitchLabelArraySize)
+ {
+ int32_t *pNewIntArray = new int32_t[m_nSwitchLabelArraySize * 2];
+ for (nCount = 0; nCount < m_nSwitchLabelNumber; ++nCount)
+ {
+ pNewIntArray[nCount] = m_pnSwitchLabelStatements[nCount];
+ }
+ m_nSwitchLabelArraySize *= 2;
+ delete[] m_pnSwitchLabelStatements;
+ m_pnSwitchLabelStatements = pNewIntArray;
+ }
+
+ m_pnSwitchLabelStatements[m_nSwitchLabelNumber] = nCaseValue;
+ ++m_nSwitchLabelNumber;
+
+ // Now, we add the pseudocode:
+ // COPYTOP fffffffc,0004 // copies the switch result so that we can use it.
+ // CONSTI nCaseValue // adds the constant that we're to compare against.
+ // EQUALII // compares the two, leaving the result on the stack.
+ // JNZ _SC_nCaseValue_nSwitchIdentifier // result goes away, jump executed.
+
+ // CODE GENERATION
+ // Here, we would dump the "appropriate" data from the run-time stack
+ // on to the top of the stack, making a copy of it ... that's why
+ // we're adding one to the appropriate run time stack.
+
+ int32_t nStackElementsDown = -4;
+ int32_t nSize = 4;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // CODE GENERATION
+ // Here, we have a "constant integer" op-code that would be added.
+ int32_t nIntegerData = nCaseValue;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+
+ // Enter the integer constant.
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // CODE GENERATION
+ // Write an "condition EQUALII" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EQUAL;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // CODE GENERATION
+ // Add the "JNZ _SC_nCaseValue_nSwitchIdentifier" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JNZ;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_SC_%08x_%08x",nCaseValue,m_nSwitchIdentifier); */
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_SWITCH_CASE,
+ nCaseValue,m_nSwitchIdentifier);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ }
+
+ nReturnValue = TraverseTreeForSwitchLabels(pNode->pRight);
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ClearSwitchLabelList()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/25/2000
+// Description: This function will resolve the labels within this level of
+// switch statement.
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::ClearSwitchLabelList()
+{
+ // Finally, don't forget the last piece of code, where we jump to the
+ // default label, if it exists.
+
+ if (m_bSwitchLabelDefault == TRUE)
+ {
+ // There is a default statement ... we jump there immediately.
+
+ // CODE GENERATION
+ // Add the "JMP _SC_DEFAULT_nSwitchIdentifier" operation.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_SC_DEFAULT_%08x",m_nSwitchIdentifier); */
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_SWITCH_DEFAULT,
+ m_nSwitchIdentifier,0);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+ else
+ {
+ // There is no default statement ... we jump over the entire switch once
+ // we've evaded all of the case statements.
+
+ // CODE GENERATION
+ // Add the "JMP _BR_nSwitchIdentifier" operation.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ /*CExoString sSymbolName;
+ sSymbolName.Format("_BR_%08x",m_nSwitchIdentifier);*/
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_BREAK,
+ m_nSwitchIdentifier,0);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+
+
+ m_bSwitchLabelDefault = FALSE;
+ m_nSwitchLabelNumber = 0;
+ m_nSwitchLabelArraySize = 16;
+ delete[] m_pnSwitchLabelStatements;
+ m_pnSwitchLabelStatements = NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GenerateIdentifiersFromConstantVariables()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Nov. 27, 2002
+// Description: This function will resolve all of the constant declarations
+// into "identifiers" that can be used in case statements.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::GenerateIdentifiersFromConstantVariables(CScriptParseTreeNode *pNode)
+{
+ if (pNode != NULL)
+ {
+ if (pNode != NULL &&
+ pNode->pLeft != NULL &&
+ pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION &&
+ pNode->pLeft->pRight != NULL &&
+ pNode->pLeft->pRight->pLeft != NULL)
+ {
+ int32_t nVariableTypeOperation = pNode->pLeft->pLeft->nOperation;
+ CScriptParseTreeNode *pNodeVariableName = pNode->pLeft->pRight->pLeft;
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierType = 0;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psIdentifier = *(pNodeVariableName->m_psStringData);
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierHash = HashString(pNodeVariableName->m_psStringData->CStr());
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierLength = pNodeVariableName->m_psStringData->GetLength();
+
+ // MGB - If a previous declaration and implementation match, an identifier
+ // gets removed from the stack. Thus, m_nOccupiedIdentifiers should be cleared.
+ // This is the biggest "remaining" bug, since it prevents a future function from
+ // compiling.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nParameters = 0;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nNonOptionalParameters = 0;
+
+ if (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER;
+ }
+ else if (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER;
+ }
+ else if (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER;
+ }
+ else
+ {
+ // MGB - Nov. 22, 2002 - It should not have been possible to get to here without
+ // going through an integer, floating point or string constant, so UNKNOWN_STATE
+ // makes perfect sense.
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNodeVariableName);
+ }
+
+ // If there is an assignment ... then we should do something about this!
+ if (pNode->pRight != NULL &&
+ pNode->pRight->pLeft != NULL &&
+ pNode->pRight->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_ASSIGNMENT &&
+ pNode->pRight->pLeft->pLeft != NULL &&
+ pNode->pRight->pLeft->pLeft->pLeft != NULL)
+ {
+ CScriptParseTreeNode *pNodeConstant = pNode->pRight->pLeft->pLeft->pLeft;
+ ConstantFoldNode(pNodeConstant, TRUE);
+
+ int32_t nConstantOperation = pNodeConstant->nOperation;
+ int32_t nSign = 1;
+
+ if (nConstantOperation == CSCRIPTCOMPILER_OPERATION_NEGATION)
+ {
+ if (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INVALID_VALUE_ASSIGNED_TO_CONSTANT,pNodeConstant);
+ }
+ nSign = -1;
+ pNodeConstant = pNodeConstant->pLeft;
+ nConstantOperation = pNodeConstant->nOperation;
+ }
+
+ if ((nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT &&
+ nConstantOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER) ||
+ (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT &&
+ nConstantOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT) ||
+ (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING &&
+ nConstantOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INVALID_VALUE_ASSIGNED_TO_CONSTANT,pNodeConstant);
+ }
+
+ // Fill in data for the constant.
+ if (nConstantOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIntegerData = nSign * pNodeConstant->nIntegerData;
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStringData).Format("%d",m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIntegerData);
+ }
+ else if (nConstantOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING)
+ {
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStringData).Format("%s",pNodeConstant->m_psStringData->CStr());
+ }
+ else if (nConstantOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_fFloatData = (float) nSign * pNodeConstant->fFloatData;
+ if (nSign == -1)
+ {
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStringData).Format("-%f",pNodeConstant->fFloatData);
+ }
+ else
+ {
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStringData).Format("%f",pNodeConstant->fFloatData);
+ }
+ }
+ }
+ else
+ {
+ // No initialization, or it is so malformed, that the parse tree code
+ // doesn't recognize it ... so we're going to set it equal to its default
+ // value.
+ if (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIntegerData = 0;
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStringData) = "0";
+ }
+ else if (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStringData) = "";
+ }
+ else if (nVariableTypeOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_fFloatData = 0.0f;
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStringData) = "0.0f";
+ }
+ }
+ HashManagerAdd(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER, m_nOccupiedIdentifiers);
+ ++m_nOccupiedIdentifiers;
+ }
+ int32_t nReturnValue = GenerateIdentifiersFromConstantVariables(pNode->pRight);
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GenerateCodeForSwitchLabels()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/25/2000
+// Description: This function will resolve the labels within this level of
+// switch statement.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::GenerateCodeForSwitchLabels(CScriptParseTreeNode *pNode)
+{
+ int32_t nReturnValue = 0;
+
+ InitializeSwitchLabelList();
+ if (pNode != NULL)
+ {
+ nReturnValue = TraverseTreeForSwitchLabels(pNode->pRight);
+ }
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ ClearSwitchLabelList();
+
+ // MGB - For Script Debugger
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::WriteResolvedOutput()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: This function will resolve all of the labels, based on the
+// final location of the functions within the script.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::WriteResolvedOutput()
+{
+
+ if (m_pchResolvedOutputBuffer == NULL ||
+ m_nResolvedOutputBufferSize < m_nFinalBinarySize)
+ {
+ if (m_pchResolvedOutputBuffer != NULL)
+ {
+ delete[] m_pchResolvedOutputBuffer;
+ }
+ // The * 2 is intentional (so we avoid calling this
+ // each time the compiled file increases by a few bytes!)
+ m_pchResolvedOutputBuffer = new char[m_nFinalBinarySize * 2];
+ m_nResolvedOutputBufferSize = m_nFinalBinarySize;
+ }
+
+ memset(m_pchResolvedOutputBuffer,0,m_nResolvedOutputBufferSize);
+
+ memcpy(m_pchResolvedOutputBuffer,m_pchOutputCode,CVIRTUALMACHINE_BINARY_SCRIPT_HEADER * sizeof(char));
+
+ for (int32_t count = m_nMaxPredefinedIdentifierId; count < m_nOccupiedIdentifiers; count++)
+ {
+ if (m_pcIdentifierList[count].m_nBinaryDestinationStart != -1)
+ {
+ int32_t nSize = (m_pcIdentifierList[count].m_nBinaryDestinationFinish - m_pcIdentifierList[count].m_nBinaryDestinationStart) * sizeof (char);
+ memcpy(m_pchResolvedOutputBuffer + m_pcIdentifierList[count].m_nBinaryDestinationStart,
+ m_pchOutputCode + m_pcIdentifierList[count].m_nBinarySourceStart,
+ nSize);
+ }
+ }
+
+ // Now, we copy it back into the output code buffer!
+ memcpy(m_pchOutputCode,m_pchResolvedOutputBuffer,m_nFinalBinarySize);
+ m_nOutputCodeLength = m_nFinalBinarySize;
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::PreVisitGenerateCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: This routine will generate code to be spat out into the
+// necessary file. Will return 0 if the operation is okay,
+// and will return a negative number if it isn't.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::PreVisitGenerateCode(CScriptParseTreeNode *pNode)
+{
+ // MGB - For Script Debugger
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT)
+ {
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ StartLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_NON_VOID_EXPRESSION ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_INTEGER_EXPRESSION)
+ {
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT)
+ {
+ m_nVarStackRecursionLevel++;
+ }
+
+ // Save the state of the run-time stacks, so that we can check 'em at the
+ // end. This way, we can verify if we're following the code correctly.
+
+ pNode->m_nStackPointer = m_nStackCurrentDepth;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FUNCTION)
+ {
+ m_bFunctionImp = FALSE;
+ if (pNode->pRight != NULL)
+ {
+ m_bFunctionImp = TRUE;
+ }
+
+ if (m_bFunctionImp == TRUE)
+ {
+
+ m_nVarStackRecursionLevel++;
+
+ m_sFunctionImpName = *(pNode->pLeft->pLeft->m_psStringData);
+
+ int32_t nIdentifier = GetIdentifierByName(m_sFunctionImpName);
+
+ if (nIdentifier < 0)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ m_pcIdentifierList[nIdentifier].m_nBinarySourceStart = m_nOutputCodeLength;
+ m_pcIdentifierList[nIdentifier].m_nBinarySourceFinish = -1;
+ m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart = -1;
+ m_pcIdentifierList[nIdentifier].m_nBinaryDestinationFinish = -1;
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("FE_%s",m_sFunctionImpName.CStr()); */
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,
+ nIdentifier,0);
+
+ int32_t nIdentifierLength = m_sFunctionImpName.GetLength();
+
+ if (m_bCompileConditionalFile == 0)
+ {
+ if (m_sFunctionImpName.GetLength() == 4 &&
+ strncmp(m_sFunctionImpName.CStr(),"main",4) == 0)
+ {
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,
+ 0,2);
+ }
+ }
+ else
+ {
+ if (nIdentifierLength == 19 &&
+ strncmp(m_sFunctionImpName.CStr(),"StartingConditional",19) == 0)
+ {
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,
+ 0,2);
+ }
+ }
+
+ //m_bFunctionImpHasReturn = FALSE;
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_GLOBAL_VARIABLES)
+ {
+ m_bFunctionImp = FALSE;
+ if (pNode->pRight != NULL)
+ {
+ m_bFunctionImp = TRUE;
+ }
+
+ if (m_bFunctionImp == TRUE)
+ {
+ m_nVarStackRecursionLevel++;
+
+ if (m_bGlobalVariableDefinition != FALSE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ m_bGlobalVariableDefinition = TRUE;
+ // MGB - September 13, 2001 - This can't be called
+ // when you are using an integer-returning function. This is bad.
+ /*
+ m_nGlobalVariables = 0;
+ m_nGlobalVariableSize = 0;
+ */
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psIdentifier = "#globals";
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierHash = HashString("#globals");
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierLength = 8;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceStart = m_nOutputCodeLength;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationStart = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationFinish = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nParameters = 0;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER;
+ HashManagerAdd(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER, m_nOccupiedIdentifiers);
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("FE_#globals"); */
+
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,
+ m_nOccupiedIdentifiers,0);
+
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,
+ 0,1);
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CASE)
+ {
+ int32_t nCaseValue;
+
+ ConstantFoldNode(pNode->pLeft, TRUE);
+ // Evaluate the constant value that is contained.
+ if (pNode->pLeft != NULL &&
+ pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_NEGATION &&
+ pNode->pLeft->pLeft != NULL &&
+ pNode->pLeft->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ nCaseValue = -pNode->pLeft->pLeft->nIntegerData;
+ }
+ else if (pNode->pLeft != NULL &&
+ pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ nCaseValue = pNode->pLeft->nIntegerData;
+ }
+ else if (pNode->pLeft != NULL &&
+ pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING)
+ {
+ nCaseValue = pNode->pLeft->m_psStringData->GetHash();
+ }
+ else
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_CASE_PARAMETER_NOT_A_CONSTANT_INTEGER,pNode);
+ }
+
+ // Generate a label for the jump caused by the switch
+ /*CExoString sSymbolName;
+ sSymbolName.Format("_SC_%08x_%08x",nCaseValue,m_nSwitchIdentifier); */
+
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_SWITCH_CASE,
+ nCaseValue,m_nSwitchIdentifier);
+
+ if (m_nSwitchStackDepth + 1 != m_nStackCurrentDepth)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_JUMPING_OVER_DECLARATION_STATEMENTS_CASE_DISALLOWED,pNode);
+ }
+
+ // Do not allow the tree to continue parsing ... we've done everything required.
+ return 1;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STRUCTURE_DEFINITION)
+ {
+ // We should be in the variable-processing stage of the strucutre
+ // definition at this point.
+
+ if (m_nStructureDefinition != 0)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ m_nStructureDefinition = 1;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ACTION_PARAMETER)
+ {
+ // CODE GENERATION
+ // This is a "action parameter" instruction. Thus, we don't intend
+ // on running the instruction contained by this part of the compile tree
+ // right away. Therefore, what we're going to do is store the state of
+ // the instruction pointer, and keep cruisin'. This will give us a
+ // fighting chance of identifying the start of the action when someone
+ // wishes to rerun this action.
+
+ //
+ // First, we add the STORE_IP instruction.
+ //
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_STORE_STATE;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = (CVIRTUALMACHINE_OPERATION_BASE_SIZE * 2 + 12);
+
+ int32_t nIntegerData = m_nGlobalVariableSize;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nIntegerData)) & 0x0ff);
+
+ nIntegerData = m_nStackCurrentDepth * 4 - m_nGlobalVariableSize;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+6] = (char) (((nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+7] = (char) (((nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 8;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ //
+ // Next, we add the JMP instruction.
+ //
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // Save the current state of the binary code length for the purpose
+ // of generating a good jump over the code within this instruction in
+ // the PostVisitGenerateCode() call.
+
+ pNode->nIntegerData = m_nOutputCodeLength;
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ACTION)
+ {
+ //if (m_bGlobalVariableDefinition == TRUE)
+ //{
+ // return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ //}
+
+ // Determine, based on the ID of the function, whether we're
+ // dealing with a function of the user's creation, or one of our
+ // own. This makes a difference to the code that we generate.
+
+ if (pNode->pRight != NULL)
+ {
+ int32_t nCount = GetIdentifierByName(*(pNode->pRight->m_psStringData));
+ if (nCount == STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ pNode->pRight->nIntegerData = nCount;
+ {
+ if (nCount >= m_nMaxPredefinedIdentifierId)
+ {
+ pNode->nIntegerData = 1;
+
+ // Because this is a user-defined identifier, we
+ // have to reserve space on the runtime stack
+ // right away for the return type, if it is non-void
+ // (of course!)
+
+ int32_t nReturnType = 0;
+ CExoString sStructureName = "";
+
+ if (m_pcIdentifierList[nCount].m_nReturnType != CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER)
+ {
+ if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER)
+ {
+ nReturnType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER)
+ {
+ nReturnType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER)
+ {
+ nReturnType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER)
+ {
+ nReturnType = CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER)
+ {
+ nReturnType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ sStructureName = m_pcIdentifierList[nCount].m_psStructureReturnName;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType >= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER &&
+ m_pcIdentifierList[nCount].m_nReturnType <= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER)
+ {
+ nReturnType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 + (m_pcIdentifierList[nCount].m_nReturnType - CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER);
+ }
+ else
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ AddVariableToStack(nReturnType, &sStructureName, TRUE);
+ }
+ }
+ else
+ {
+ pNode->nIntegerData = 0;
+ }
+
+ // This part of the code attempts to precompile all optional parameters.
+ // It is incredibly similar to the code in PostVisit
+ CScriptParseTreeNode *pTracePtr;
+ int nParameters = 0;
+
+ pTracePtr = pNode->pLeft;
+
+ while (pTracePtr != NULL)
+ {
+ nParameters++;
+ pTracePtr = pTracePtr->pLeft;
+ }
+
+ int nCount = pNode->pRight->nIntegerData;
+ BOOL bMatch = TRUE;
+
+ if (nParameters > m_pcIdentifierList[nCount].m_nParameters)
+ {
+ bMatch = FALSE;
+ }
+
+ if (nParameters < m_pcIdentifierList[nCount].m_nNonOptionalParameters)
+ {
+ bMatch = FALSE;
+ }
+
+ if (bMatch == TRUE)
+ {
+ if (nParameters != m_pcIdentifierList[nCount].m_nParameters)
+ {
+ int32_t nCount2;
+ for (nCount2 = m_pcIdentifierList[nCount].m_nParameters - 1; nCount2 >= nParameters; --nCount2)
+ {
+ if (m_pcIdentifierList[nCount].m_pbOptionalParameters[nCount2] != TRUE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_DECLARATION_DOES_NOT_MATCH_PARAMETERS,pNode);
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] != CSCRIPTCOMPILER_TOKEN_KEYWORD_INT &&
+ m_pcIdentifierList[nCount].m_pchParameters[nCount2] != CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT &&
+ m_pcIdentifierList[nCount].m_pchParameters[nCount2] != CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING &&
+ m_pcIdentifierList[nCount].m_pchParameters[nCount2] != CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT &&
+ m_pcIdentifierList[nCount].m_pchParameters[nCount2] != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2 /* location */ &&
+ m_pcIdentifierList[nCount].m_pchParameters[nCount2] != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7 /* json */ &&
+ (m_pcIdentifierList[nCount].m_pchParameters[nCount2] != CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT ||
+ m_pcIdentifierList[nCount].m_psStructureParameterNames[nCount2] != "vector"))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_TYPE_DOES_NOT_HAVE_AN_OPTIONAL_PARAMETER,pNode);
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant integer" op-code that would be added.
+ int32_t nIntegerData = m_pcIdentifierList[nCount].m_pnOptionalParameterIntegerData[nCount2];
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+
+ // Enter the integer constant.
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ ++m_nStackCurrentDepth;
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant float" op-code that would be added.
+
+ float fFloatData = m_pcIdentifierList[nCount].m_pfOptionalParameterFloatData[nCount2];
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+
+ // Enter the floating point constant.
+
+ ///////////////////////////////////////////////////////////////////////////
+ // This may need some explaining. The MacIntosh deals with floating point
+ // numbers in the same way as integers ... it reverses the bytes. Thus, if
+ // we want to avoid doing byte swaps, what we should do is write the data
+ // out in the specified byte order, and then read it back in with the
+ // specified byte order. However, you can't just "shift left" on floats,
+ // so we cast the data to an integer, and then write that out! Tricky, but
+ // it should work.
+ //
+ // -- Mark Brockington, 01/22/2000
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ int32_t *pFloatAsInt = (int32_t *) &fFloatData;
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((*pFloatAsInt) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((*pFloatAsInt) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((*pFloatAsInt) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((*pFloatAsInt)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+ ++m_nStackCurrentDepth;
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT &&
+ m_pcIdentifierList[nCount].m_psStructureParameterNames[nCount2] == "vector")
+ {
+ // CODE GENERATION
+ // Here, we have a "constant float" op-code that would be added.
+
+ for (int32_t temp = 0; temp < 3; ++temp)
+ {
+ float fFloatData = m_pcIdentifierList[nCount].m_pfOptionalParameterVectorData[nCount2 * 3 + temp];
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+
+ // Enter the floating point constant.
+
+ int32_t *pFloatAsInt = (int32_t *) &fFloatData;
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((*pFloatAsInt) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((*pFloatAsInt) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((*pFloatAsInt) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((*pFloatAsInt)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+ ++m_nStackCurrentDepth;
+ }
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant string" op-code that would be added.
+
+ CExoString sStringData = m_pcIdentifierList[nCount].m_psOptionalParameterStringData[nCount2];
+ int nLength = sStringData.GetLength();
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_STRING;
+
+ // Enter the string constant.
+
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((nLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nLength)) & 0x0ff);
+
+ int nCount3;
+ for (nCount3 = 0; nCount3 < nLength; nCount3++)
+ {
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+nCount3+2] = (sStringData.CStr())[nCount3];
+ }
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + nLength + 2;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_STRING;
+ ++m_nStackCurrentDepth;
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant object" op-code that would be added.
+ OBJECT_ID oidObjectData = m_pcIdentifierList[nCount].m_poidOptionalParameterObjectData[nCount2];
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_OBJECT;
+
+ // Enter the integer constant.
+ int32_t nIntegerData = (int32_t) oidObjectData;
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_OBJECT;
+ ++m_nStackCurrentDepth;
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2) // location
+ {
+ // Encode the location as a int for now.
+
+ int32_t nIntegerData = m_pcIdentifierList[nCount].m_pnOptionalParameterIntegerData[nCount2];
+
+ // only LOCATION_INVALID supported for now
+ if (nIntegerData != 0)
+ {
+ return OutputWalkTreeError(STRREF_CVIRTUALMACHINE_ERROR_INVALID_EXTRA_DATA_ON_OP_CODE, pNode);
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST2;
+
+ // Enter the integer constant.
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST2;
+ ++m_nStackCurrentDepth;
+ }
+
+ if (m_pcIdentifierList[nCount].m_pchParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7) // json
+ {
+ // encode the json as a variable-size payload string
+
+ CExoString sStringData = m_pcIdentifierList[nCount].m_psOptionalParameterStringData[nCount2];
+ EXOASSERT(sStringData.GetLength() <= 0xffff);
+ if (sStringData.GetLength() > 0xffff)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG,pNode);
+ }
+
+ const uint16_t nLength = sStringData.GetLength();
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST7;
+
+ // Enter the jsonified string constant.
+
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((nLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nLength)) & 0x0ff);
+
+ int nCount3;
+ for (nCount3 = 0; nCount3 < nLength; nCount3++)
+ {
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+nCount3+2] = (sStringData.CStr())[nCount3];
+ }
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + nLength + 2;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST7;
+ ++m_nStackCurrentDepth;
+
+ }
+
+
+
+ }
+ }
+
+
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_DECLARATION_DOES_NOT_MATCH_PARAMETERS,pNode);
+ }
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK)
+ {
+
+ // Set the label for continue jumps.
+ pNode->nIntegerData3 = m_nLoopIdentifier;
+ pNode->nIntegerData4 = m_nLoopStackDepth;
+ m_nLoopIdentifier = m_nOutputCodeLength;
+ m_nLoopStackDepth = m_nStackCurrentDepth;
+
+ // First things first, we may need to jump all the way back to
+ // this point in the code, so we should save the location of this
+ // part of the code.
+
+ pNode->nIntegerData = m_nOutputCodeLength;
+
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ StartLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK)
+ {
+ ++m_nSwitchLevel;
+
+ // Store the old value of the switch identifier, and then
+ // create our own value for the switch identifier.
+
+ pNode->nIntegerData2 = m_nSwitchIdentifier;
+ pNode->nIntegerData3 = m_nSwitchStackDepth;
+ m_nSwitchIdentifier = m_nOutputCodeLength;
+ m_nSwitchStackDepth = m_nStackCurrentDepth;
+
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ StartLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK)
+ {
+
+ // Set label for continue/break jumps.
+ pNode->nIntegerData3 = m_nLoopIdentifier;
+ pNode->nIntegerData4 = m_nLoopStackDepth;
+ m_nLoopIdentifier = m_nOutputCodeLength;
+ m_nLoopStackDepth = m_nStackCurrentDepth;
+
+ // First things first, we may need to jump all the way back to
+ // this point in the code, so we should save the location of this
+ // part of the code.
+
+ pNode->nIntegerData = m_nOutputCodeLength;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_CHOICE)
+ {
+ // First things first, we may need to jump all the way back to
+ // this point in the code, so we should save the location of this
+ // part of the code.
+
+ pNode->nIntegerData = m_nOutputCodeLength;
+
+ if (m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INTEGER_NOT_AT_TOP_OF_STACK,pNode);
+ }
+ --m_nStackCurrentDepth;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JZ;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // Save the current state of the binary code length for the purpose
+ // of generating a good jump over the code within this instruction in
+ // the PostVisitGenerateCode() call.
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COND_CHOICE)
+ {
+ // First things first, we may need to jump all the way back to
+ // this point in the code, so we should save the location of this
+ // part of the code.
+
+ pNode->nIntegerData = m_nOutputCodeLength;
+
+ if (m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INTEGER_NOT_AT_TOP_OF_STACK,pNode);
+ }
+ --m_nStackCurrentDepth;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JZ;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // Save the current state of the binary code length for the purpose
+ // of generating a good jump over the code within this instruction in
+ // the PostVisitGenerateCode() call.
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_CONDITION)
+ {
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ StartLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_PRE_INCREMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_PRE_DECREMENT)
+ {
+ // Here we write the code for doing a pre-increment or a pre-decrement, and
+ // we actually do all the checking (and filling in the address) in the
+ // PostVisitGenerateCode() call. Makes sense? I sure hope so when I have
+ // to look at this four months down the road. :-)
+
+ // For writing out the code, just store a blank location.
+ int32_t nStackElementsDown = 0;
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_PRE_INCREMENT)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_INCREMENT;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_DECREMENT;
+ }
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ // The address for the "blank" address should be stored in pNode->nIntegerData2;
+ pNode->nIntegerData2 = m_nOutputCodeLength;
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ return 0;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::InVisitGenerateCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: This routine will generate code to be spat out into the
+// necessary file. Will return 0 if the operation is okay,
+// and will return a negative number if it isn't.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::InVisitGenerateCode(CScriptParseTreeNode *pNode)
+{
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STRUCTURE_DEFINITION)
+ {
+ // We should be in the variable-processing stage of the strucutre
+ // definition at this point.
+
+ if (m_nStructureDefinition != 1)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ m_nStructureDefinition = 2;
+
+ if (pNode->pLeft == NULL || pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ int32_t count;
+ for (count = 0; count < m_nMaxStructures; count++)
+ {
+ if (*(pNode->pLeft->m_psStringData) == m_pcStructList[count].m_psName)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_STRUCTURE_REDEFINED,pNode);
+ }
+ }
+
+ m_pcStructList[m_nMaxStructures].m_psName = *(pNode->pLeft->m_psStringData);
+ m_pcStructList[m_nMaxStructures].m_nByteSize = 0;
+ m_pcStructList[m_nMaxStructures].m_nFieldStart = m_nMaxStructureFields;
+ m_pcStructList[m_nMaxStructures].m_nFieldEnd = -1;
+
+ m_nStructureDefinitionFieldStart = m_nMaxStructureFields;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ASSIGNMENT)
+ {
+ if (pNode->pRight != NULL && pNode->pLeft != NULL)
+ {
+ // Is the storage location a valid LValue?
+ if (pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE || pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART)
+ {
+ m_bAssignmentToVariable = TRUE;
+ return 0;
+ }
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INVALID_PARAMETERS_FOR_ASSIGNMENT,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG)
+ {
+
+ // Do NOTHING on a normal keyword declaration statement ... leave it as a
+ // statement, since this is equivalent to a STATEMENT_VOID. Also, we can add
+ // a whole pile of variables in one statement, and we don't want to remove them.
+ // So, we should bail out of the routine right now if we're dealing with a
+ // declaration keyword.
+ //
+ // Note that we also have complex chains of statements within a "statement list"
+ // (since we now allow these to be statically initialized). Hence, the really
+ // gruesome looking second condition.
+
+ if ((pNode->pLeft != NULL && pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION) ||
+ //(pNode->pLeft != NULL && pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_RETURN) ||
+ (pNode->pLeft != NULL && pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST &&
+ ((pNode->pLeft->pLeft != NULL && pNode->pLeft->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT) || (pNode->pLeft->pLeft != NULL && pNode->pLeft->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG)) &&
+ pNode->pLeft->pLeft->pLeft != NULL && pNode->pLeft->pLeft->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION))
+ {
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT)
+ {
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+ return 0;
+ }
+
+ // Update the state of the stack to where it should be. We will
+ // be writing out the code to do this here.
+ pNode->nIntegerData = (pNode->m_nStackPointer - m_nStackCurrentDepth) * 4;
+ m_nStackCurrentDepth = pNode->m_nStackPointer;
+
+ // CODE GENERATION
+ // Move the stack to update the current location of the code.
+
+ if (pNode->nIntegerData != 0)
+ {
+ EmitModifyStackPointer(pNode->nIntegerData);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT)
+ {
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK)
+ {
+ return GenerateCodeForSwitchLabels(pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK)
+ {
+ //
+ // Set up our conditional jump at this point in the code. We may
+ // also need to reference this location at a later time to add the
+ // address of where to jump to!
+
+ pNode->nIntegerData2 = m_nOutputCodeLength;
+
+ if (m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INTEGER_NOT_AT_TOP_OF_STACK,pNode);
+ }
+ --m_nStackCurrentDepth;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JZ;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // Save the current state of the binary code length for the purpose
+ // of generating a good jump over the code within this instruction in
+ // the PostVisitGenerateCode() call.
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_CHOICE)
+ {
+ pNode->nIntegerData2 = m_nOutputCodeLength;
+
+ // Here, we implement the skip-ahead to _I2_ and install the
+ // label at _I1_.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JZ command we gave earlier during
+ // the PreVisit() [code located at pNode->nIntegerdata].
+ // This is an awfully good thing to do.
+
+ int32_t nJmpLength = m_nOutputCodeLength - pNode->nIntegerData;
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ // MGB - For Script Debugger
+ if (pNode->pRight != NULL)
+ {
+
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ StartLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NO_OPERATION;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+
+ }
+
+
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COND_CHOICE)
+ {
+
+ pNode->nIntegerData2 = m_nOutputCodeLength;
+
+ // Here, we implement the skip-ahead to _CH2_ and install the
+ // label at _CH1_.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JZ command we gave earlier during
+ // the PreVisit() [code located at pNode->nIntegerdata].
+ // This is an awfully good thing to do.
+
+ int32_t nJmpLength = m_nOutputCodeLength - pNode->nIntegerData;
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ // NOTE: We've got to get rid of the first thing on the stack here, otherwise, we're
+ // TOTALLY boned when using variables in the second part.
+
+ int32_t nElementsToDelete = 4;
+ if (pNode->pLeft && pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nElementsToDelete = GetStructureSize(*(pNode->pLeft->m_psTypeName));
+ }
+
+ m_nStackCurrentDepth -= (nElementsToDelete >> 2);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FUNCTION && m_bFunctionImp == TRUE)
+ {
+ // Get the current stack pointer, now that we've added fake
+ // versions of all of the variables on to the stack. Woo-hoo!
+
+ pNode->m_nStackPointer = m_nStackCurrentDepth;
+
+ // Store it for use by the RETURN command, too!
+ m_nFunctionImpAbortStackPointer = m_nStackCurrentDepth;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_LOGICAL_AND)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ // Okay, this is the scoop. If the top value is zero, we should
+ // just ignore the code that does the rest of the "if choice".
+
+ // ... the integer at the top of the stack.
+
+ // CODE GENERATION
+ // Here, we would dump the "appropriate" data from the run-time stack
+ // on to the top of the stack, making a copy of it ... that's why
+ // we're adding one to the appropriate run time stack.
+
+ int32_t nStackElementsDown = -4;
+ int32_t nSize = 4;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT, NULL, FALSE);
+
+ //
+ // ... and a JZ to skip the right branch.
+ //
+
+ pNode->nIntegerData = m_nOutputCodeLength;
+ if (m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INTEGER_NOT_AT_TOP_OF_STACK,pNode);
+ }
+ --m_nStackCurrentDepth;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JZ;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // The jump length is over this instruction and the jmp instruction, both of
+ // which are OPERATION_BASE_SIZE + 4 (for the address).
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_LOGICAL_OR)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ // Okay, this is the scoop. If the top value is zero, we should
+ // just ignore the code that does the rest of the "if choice".
+
+ // ... the integer at the top of the stack.
+
+ // CODE GENERATION
+ // Here, we would dump the "appropriate" data from the run-time stack
+ // on to the top of the stack, making a copy of it ... that's why
+ // we're adding one to the appropriate run time stack.
+
+ int32_t nStackElementsDown = -4;
+ int32_t nSize = 4;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT, NULL, FALSE);
+
+ //
+ // ... and a JZ to skip to the right branch!
+ //
+
+ if (m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INTEGER_NOT_AT_TOP_OF_STACK,pNode);
+ }
+ --m_nStackCurrentDepth;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JZ;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // The jump length is over this instruction and the jmp instruction, and
+ // the copy top instruction (an additional 4+6+4 bytes above the BASE_SIZE
+ // operations).
+
+ int32_t nJmpLength = (CVIRTUALMACHINE_OPERATION_BASE_SIZE * 3) + 4 + 6 + 4;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nJmpLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nJmpLength)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // .... the integer at the top of the stack.
+
+ // CODE GENERATION
+ // Here, we would dump the "appropriate" data from the run-time stack
+ // on to the top of the stack, making a copy of it ... that's why
+ // we're adding one to the appropriate run time stack.
+
+ nStackElementsDown = -4;
+ nSize = 4;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // IMPORTANT NOTE: It is absolutely vital to NOT add this variable to the
+ // stack, since this path is completely optional ... and the right branch
+ // will be adding an integer anyway!
+
+ pNode->nIntegerData = m_nOutputCodeLength;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // The jump length is over this instruction and the jmp instruction, both of
+ // which are OPERATION_BASE_SIZE + 4 (for the address).
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+
+ }
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART)
+ {
+ m_bInStructurePart = TRUE;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK)
+ {
+ // Generate a label for the continue keyword.
+
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ StartLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_CN_%08x",m_nLoopIdentifier); */
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_CONTINUE,
+ m_nLoopIdentifier);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT)
+ {
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::PostVisitGenerateCode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: This routine will generate code to be spat out into the
+// necessary file. Will return 0 if the operation is okay,
+// and will return a negative number if it isn't.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::PostVisitGenerateCode(CScriptParseTreeNode *pNode)
+{
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ASSIGNMENT)
+ {
+ if (pNode->pRight != NULL && pNode->pLeft != NULL)
+ {
+ // Variable is referred to in an expression.
+ // Look for the variable in the list. When we find it, generate its op-code.
+
+ if (pNode->pRight->nType == pNode->pLeft->nType)
+ {
+ if (pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT &&
+ *(pNode->pRight->m_psTypeName) != *(pNode->pLeft->m_psTypeName))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_MISMATCHED_TYPES,pNode);
+ }
+
+ pNode->nType = pNode->pRight->nType;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+ (pNode->m_psTypeName) = new CExoString(pNode->pLeft->m_psTypeName->CStr());
+ }
+
+ // CODE GENERATION
+ // We should generate a op-code that is consistent with the
+ // type of assignment that is taking place (i.e. integer,
+ // float, string or object). This operation has no effect
+ // on the run time stacks, but copies the code from the top
+ // of the stack to the code.
+
+ int32_t nStackElementsDown = pNode->pRight->nIntegerData - (m_nStackCurrentDepth * 4);
+ int32_t nSize = 4;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nSize = GetStructureSize(*(pNode->m_psTypeName));
+ }
+
+ // MGB - August 10, 2001 - Determine whether we are going to operate on
+ // the stack pointer (for a locally defined variable), or the base pointer
+ // (for a global variable).
+
+ int32_t bOperateOnStackPointer = TRUE;
+ if (pNode->pRight->nIntegerData < m_nGlobalVariableSize && m_bGlobalVariableDefinition == FALSE)
+ {
+ bOperateOnStackPointer = FALSE;
+ nStackElementsDown = pNode->pRight->nIntegerData - (m_nGlobalVariableSize);
+ }
+
+ if (bOperateOnStackPointer == TRUE)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_ASSIGNMENT;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_ASSIGNMENT_BASE;
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ m_bAssignmentToVariable = FALSE;
+ return 0;
+ }
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_MISMATCHED_TYPES,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID)
+ {
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT)
+ {
+ m_nVarStackVariableType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT)
+ {
+ m_nVarStackVariableType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ m_nVarStackVariableType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT)
+ {
+ m_nVarStackVariableType = CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT;
+ return 0;
+ }
+
+ if (pNode->nOperation >= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0 &&
+ pNode->nOperation <= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ m_nVarStackVariableType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 + (pNode->nOperation - CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0);
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT)
+ {
+ // When structure definition is 1, then we're in the
+ // process of defining a structure name, and it's not
+ // necessary to set these variables ... only when we're
+ // actually defining a structure as a variable to be
+ // used somewhere else. Thus, we do it here.
+
+ if (m_nStructureDefinition != 1)
+ {
+ m_nVarStackVariableType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ m_sVarStackVariableTypeName = *(pNode->m_psStringData);
+ }
+
+ return 0;
+ }
+
+ int32_t nCount, nCount2;
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+
+ // There are only two occasions where we should get a variable as a "terminal"
+ // within the compile tree: as a branch from a variable list node (in the
+ // declaration part of the tree) or as a part of an expression. The first
+ // case is determined within this phase by checking to see if m_nVarStackVariableType
+ // is not equal to OPERATION_KEYWORD_DECLARATION, because the type in this
+ // variable specifies that we're in the middle of handling a declaration list!
+
+ // There is a third case where a variable is handled as a terminal node, but the
+ // assignment to a variable is handled in the case just above this one ... so
+ // we don't have to worry about generating a value here.
+
+ if (m_nVarStackVariableType != CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION)
+ {
+ if (m_nStructureDefinition == 0)
+ {
+ for (nCount = m_nOccupiedVariables; nCount >= 0; --nCount)
+ {
+ if (m_pcVarStackList[nCount].m_psVarName == *(pNode->m_psStringData) &&
+ m_pcVarStackList[nCount].m_nVarLevel == m_nVarStackRecursionLevel)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_VARIABLE_ALREADY_USED_WITHIN_SCOPE,pNode);
+ }
+ }
+
+ ++m_nOccupiedVariables;
+ if (m_bGlobalVariableDefinition)
+ {
+ ++m_nGlobalVariables;
+ if (m_nVarStackVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_nGlobalVariableSize += GetStructureSize(m_sVarStackVariableTypeName);
+ }
+ else
+ {
+ m_nGlobalVariableSize += 4;
+ }
+
+ }
+
+ m_pcVarStackList[m_nOccupiedVariables].m_psVarName = *(pNode->m_psStringData);
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarType = m_nVarStackVariableType;
+ if (m_nVarStackVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_pcVarStackList[m_nOccupiedVariables].m_sVarStructureName = m_sVarStackVariableTypeName;
+
+ int32_t count;
+ BOOL bFoundStructure = FALSE;
+ for (count = 0; count < m_nMaxStructures; count++)
+ {
+ if (m_sVarStackVariableTypeName == m_pcStructList[count].m_psName)
+ {
+ bFoundStructure = TRUE;
+ }
+ }
+ if (bFoundStructure == FALSE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_STRUCTURE,pNode);
+ }
+
+ }
+ else
+ {
+ m_sVarStackVariableTypeName = "";
+ }
+
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarLevel = m_nVarStackRecursionLevel;
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarRunTimeLocation = m_nStackCurrentDepth * 4;
+
+
+
+ int32_t nOccupiedVariables = m_nOccupiedVariables;
+ int32_t nStackCurrentDepth = m_nStackCurrentDepth;
+ int32_t nGlobalVariableSize = m_nGlobalVariableSize;
+
+ // Now, we can add the variable to the stack!
+ AddVariableToStack(m_nVarStackVariableType, &m_sVarStackVariableTypeName, TRUE);
+
+ //AddToSymbolTableVarStack(nOccupiedVariables,nStackCurrentDepth,nGlobalVariableSize);
+ if (m_bGlobalVariableDefinition)
+ {
+ // Global variables are always at the bottom of the stack,
+ // so we fake out the SymbolTableVarStack to think that this
+ // is its own stack context (even though we're in the middle
+ // of building it!)
+ AddToSymbolTableVarStack(nOccupiedVariables, nStackCurrentDepth, 0);
+ }
+ else
+ {
+ AddToSymbolTableVarStack(nOccupiedVariables, nStackCurrentDepth, nGlobalVariableSize);
+ }
+
+ }
+ else
+ {
+ // This part checks instantiates variables within a structure
+ // definition. Thus, we really don't need to worry about writing
+ // code out at this point ... we're just worried about semantic
+ // checking of the various parts.
+
+ // First, we should check to see if this name is used in any other
+ // field within this structure
+ for (nCount = m_nStructureDefinitionFieldStart; nCount < m_nMaxStructureFields; nCount++)
+ {
+ if (m_pcStructFieldList[nCount].m_psVarName == *(pNode->m_psStringData))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_VARIABLE_USED_TWICE_IN_SAME_STRUCTURE,pNode);
+ }
+ }
+
+ // Okay, now we're done ... store the structure field in its
+ // proper location.
+
+ m_pcStructFieldList[m_nMaxStructureFields].m_pchType = (char) m_nVarStackVariableType;
+ if (m_nVarStackVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_pcStructFieldList[m_nMaxStructureFields].m_psStructureName = m_sVarStackVariableTypeName;
+ }
+ m_pcStructFieldList[m_nMaxStructureFields].m_psVarName = *(pNode->m_psStringData);
+ m_pcStructFieldList[m_nMaxStructureFields].m_nLocation = 0;
+
+ ++m_nMaxStructureFields;
+ }
+ }
+ else
+ {
+ // Variable is referred to in an expression.
+
+ // Look for the variable in the list. When we find it, generate its op-code.
+ // The first part of this handles the case where the variable is used within
+ // an expression. In some cases, (i.e. an assignment to a variable), one
+ // does not want this copy to happen. Thus, we actually avoid writing out
+ // any code in the case where we don't have to copy data up.
+
+ if (m_bInStructurePart == TRUE)
+ {
+ return 0;
+ }
+
+ for (nCount = m_nOccupiedVariables; nCount >= 0; --nCount)
+ {
+ if (m_pcVarStackList[nCount].m_psVarName == *(pNode->m_psStringData))
+ {
+ // Now, we can get rid of the data.
+ delete (pNode->m_psStringData);
+ pNode->m_psStringData = NULL;
+
+ pNode->nType = m_pcVarStackList[nCount].m_nVarType;
+
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ pNode->m_psTypeName = new CExoString(m_pcVarStackList[nCount].m_sVarStructureName.CStr());
+ }
+ else
+ {
+ pNode->m_psTypeName = NULL;
+ }
+
+ // For the purposes of writing out code, we need to do this operation.
+ pNode->nIntegerData = m_pcVarStackList[nCount].m_nVarRunTimeLocation;
+
+
+ if (m_bAssignmentToVariable == FALSE)
+ {
+
+ // CODE GENERATION
+ // Here, we would dump the "appropriate" data from the run-time stack
+ // on to the top of the stack, making a copy of it ... that's why
+ // we're adding one to the appropriate run time stack.
+
+ int32_t nStackElementsDown = pNode->nIntegerData - (m_nStackCurrentDepth * 4);
+ int32_t nSize = 4;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nSize = GetStructureSize(*(pNode->m_psTypeName));
+ }
+
+ // MGB - August 10, 2001 - Determine whether we are going to operate on
+ // the stack pointer (for a locally defined variable), or the base pointer
+ // (for a global variable).
+
+ int32_t bOperateOnStackPointer = TRUE;
+ if (pNode->nIntegerData < m_nGlobalVariableSize && m_bGlobalVariableDefinition == FALSE)
+ {
+ bOperateOnStackPointer = FALSE;
+ nStackElementsDown = pNode->nIntegerData - (m_nGlobalVariableSize);
+ }
+
+ if (bOperateOnStackPointer == TRUE)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY_BASE;
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+
+ // Add variable on to the stack, too.
+ AddVariableToStack(pNode->nType, pNode->m_psTypeName, FALSE);
+
+ }
+
+ return 0;
+ }
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_VARIABLE_DEFINED_WITHOUT_TYPE,pNode);
+
+ }
+ return 0;
+
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant integer" op-code that would be added.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+
+ // Enter the integer constant.
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((pNode->nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((pNode->nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((pNode->nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((pNode->nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ ++m_nStackCurrentDepth;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_OBJECT)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant object" op-code that would be added.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_OBJECT;
+
+ // Enter the integer constant, since that is where we stored
+ // the value. :-)
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((pNode->nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((pNode->nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((pNode->nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((pNode->nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT;
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_OBJECT;
+ ++m_nStackCurrentDepth;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant float" op-code that would be added.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+
+ // Enter the floating point constant.
+
+ ///////////////////////////////////////////////////////////////////////////
+ // This may need some explaining. The MacIntosh deals with floating point
+ // numbers in the same way as integers ... it reverses the bytes. Thus, if
+ // we want to avoid doing byte swaps, what we should do is write the data
+ // out in the specified byte order, and then read it back in with the
+ // specified byte order. However, you can't just "shift left" on floats,
+ // so we cast the data to an integer, and then write that out! Tricky, but
+ // it should work.
+ //
+ // -- Mark Brockington, 01/22/2000
+ ///////////////////////////////////////////////////////////////////////////
+
+ int32_t *pFloatAsInt = (int32_t *) &pNode->fFloatData;
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((*pFloatAsInt) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((*pFloatAsInt) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((*pFloatAsInt) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((*pFloatAsInt)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+ ++m_nStackCurrentDepth;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_VECTOR)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant float" op-code that would be added.
+
+ for (int32_t nCount = 0; nCount < 3; nCount++)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+
+ // Enter the floating point constant.
+
+ ///////////////////////////////////////////////////////////////////////////
+ // This may need some explaining. The MacIntosh deals with floating point
+ // numbers in the same way as integers ... it reverses the bytes. Thus, if
+ // we want to avoid doing byte swaps, what we should do is write the data
+ // out in the specified byte order, and then read it back in with the
+ // specified byte order. However, you can't just "shift left" on floats,
+ // so we cast the data to an integer, and then write that out! Tricky, but
+ // it should work.
+ //
+ // -- Mark Brockington, 01/22/2000
+ ///////////////////////////////////////////////////////////////////////////
+
+ int32_t *pFloatAsInt = (int32_t *) &(pNode->fVectorData[nCount]);
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((*pFloatAsInt) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((*pFloatAsInt) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((*pFloatAsInt) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((*pFloatAsInt)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+ ++m_nStackCurrentDepth;
+ }
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ pNode->m_psTypeName = new CExoString("vector");
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant string" op-code that would be added.
+
+ int nLength = pNode->m_psStringData->GetLength();
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_STRING;
+
+ // Enter the string constant.
+
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((nLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nLength)) & 0x0ff);
+
+ for (nCount = 0; nCount < nLength; nCount++)
+ {
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+nCount+2] = (pNode->m_psStringData->CStr())[nCount];
+ }
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + nLength + 2;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_STRING;
+ ++m_nStackCurrentDepth;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_LOCATION)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant location" op-code that would be added.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST2;
+
+ // Enter the integer constant.
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((pNode->nIntegerData) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((pNode->nIntegerData) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((pNode->nIntegerData) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((pNode->nIntegerData)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2;
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST2;
+ ++m_nStackCurrentDepth;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_JSON)
+ {
+ // CODE GENERATION
+ // Here, we have a "constant json" op-code that would be added.
+
+ int nLength = pNode->m_psStringData->GetLength();
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_CONSTANT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST7;
+
+ // Enter the string constant.
+
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((nLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nLength)) & 0x0ff);
+
+ for (nCount = 0; nCount < nLength; nCount++)
+ {
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+nCount+2] = (pNode->m_psStringData->CStr())[nCount];
+ }
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + nLength + 2;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7;
+ m_pchStackTypes[m_nStackCurrentDepth] = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST7;
+ ++m_nStackCurrentDepth;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION)
+ {
+ // This is simply for the purposes of "declaring" that we're out of this
+ // one for defining variables. This doesn't need to be carried over into
+ // code, since each of the variables has the type appended on to it, but
+ // the name isn't stored anywhere.
+
+ m_nVarStackVariableType = CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION;
+ pNode->nType = 0;
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE_LIST ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST)
+ {
+ pNode->nType = 0;
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ACTION_ARG_LIST)
+ {
+ // FOR TESTING PURPOSES
+ // Transfer the type of the argument up to this level, so that when
+ // we test the action's parameters, we need only travel down "left"
+ // branches of ACTION_ARG_LIST calls.
+ if (pNode->pRight != NULL)
+ {
+ pNode->nType = pNode->pRight->nType;
+
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ (pNode->m_psTypeName) = new CExoString(pNode->pRight->m_psTypeName->CStr());
+ }
+ }
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ACTION_PARAMETER)
+ {
+ // CODE GENERATION
+
+ // The first instruction that we need to run is a RETURN command.
+ // since we have to abort out of whatever statement we're in the middle
+ // of.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RET;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JMP command we gave earlier. This is an awfully good
+ // thing to do.
+
+ int32_t nJmpLength = m_nOutputCodeLength - pNode->nIntegerData;
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ // FOR TESTING PURPOSES
+ // Transfer the type of the argument through the node, so that we can
+ // pass it up to the ACTION_ARG_LIST call.
+
+ if (pNode->pLeft != NULL)
+ {
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION;
+ }
+
+ // ++m_nRunTimeActions;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ACTION_ID)
+ {
+ pNode->nIntegerData = GetIdentifierByName(*(pNode->m_psStringData));
+
+ if (pNode->nIntegerData < 0)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ACTION)
+ {
+ // FOR TESTING PURPOSES
+ // This code is responsible for checking the types of the parameters
+ // and verifying that we've got a viable parameter list for the given
+ // ID.
+
+ if (pNode->pRight != NULL)
+ {
+ CScriptParseTreeNode *pTracePtr;
+ int nParameters = 0;
+
+ pTracePtr = pNode->pLeft;
+
+ while (pTracePtr != NULL)
+ {
+ if (pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE1 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE3 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE4 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE5 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE6 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE8 ||
+ pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ m_pchActionParameters[nParameters] = (char) pTracePtr->nType;
+
+ if (pTracePtr->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ CExoString sTypeName = *(pTracePtr->m_psTypeName);
+ m_pchActionParameterStructureNames[nParameters] = sTypeName;
+ int32_t nSize = GetStructureSize(sTypeName) >> 2;
+ m_nStackCurrentDepth -= nSize;
+ }
+ else if (pTracePtr->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION)
+ {
+ --m_nStackCurrentDepth;
+ }
+ }
+ else
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ nParameters++;
+ pTracePtr = pTracePtr->pLeft;
+ }
+
+ int nCount = pNode->pRight->nIntegerData;
+ BOOL bMatch = TRUE;
+
+ if (nParameters > m_pcIdentifierList[nCount].m_nParameters)
+ {
+ bMatch = FALSE;
+ }
+
+ if (nParameters < m_pcIdentifierList[nCount].m_nNonOptionalParameters)
+ {
+ bMatch = FALSE;
+ }
+
+ for (nCount2 = 0; nCount2 < nParameters; nCount2++)
+ {
+ if ((m_pchActionParameters[nCount2] != m_pcIdentifierList[nCount].m_pchParameters[nCount2]) ||
+ (m_pchActionParameters[nCount2] == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT &&
+ m_pchActionParameterStructureNames[nCount2] != m_pcIdentifierList[nCount].m_psStructureParameterNames[nCount2]))
+ {
+ bMatch = FALSE;
+ }
+ }
+
+ if (bMatch == TRUE)
+ {
+ // Remove all of the optional parameters that haven't been specified,
+ // but were added the PreVisitGenerateCode.
+
+ if (nParameters < m_pcIdentifierList[nCount].m_nParameters)
+ {
+ for (int32_t cnt = nParameters; cnt < m_pcIdentifierList[nCount].m_nParameters; cnt++)
+ {
+ if (m_pcIdentifierList[nCount].m_pchParameters[cnt] == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_pchActionParameterStructureNames[nParameters] = m_pcIdentifierList[nCount].m_psStructureParameterNames[cnt];
+ int32_t nSize = GetStructureSize(m_pcIdentifierList[nCount].m_psStructureParameterNames[cnt]) >> 2;
+ m_nStackCurrentDepth -= nSize;
+ }
+ else if (m_pcIdentifierList[nCount].m_pchParameters[cnt] != CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION)
+ {
+ --m_nStackCurrentDepth;
+ }
+ }
+ }
+
+ // pNode->pRight->nIntegerData = nCount;
+ // Based on the return type, add a value to the stack.
+
+ // We've already added the return value to the stack ... so
+ // why do we need to do it here?
+
+
+ if (m_pcIdentifierList[nCount].m_nReturnType != CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+ pNode->m_psTypeName = NULL;
+
+ if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER)
+ {
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER)
+ {
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER)
+ {
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER)
+ {
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType >= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER &&
+ m_pcIdentifierList[nCount].m_nReturnType <= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER)
+ {
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 + (m_pcIdentifierList[nCount].m_nReturnType - CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER);
+ }
+ else if (m_pcIdentifierList[nCount].m_nReturnType == CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER)
+ {
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ pNode->m_psTypeName = new CExoString(m_pcIdentifierList[nCount].m_psStructureReturnName.CStr());
+ }
+
+ if (pNode->nIntegerData == 0)
+ {
+ AddVariableToStack(pNode->nType,pNode->m_psTypeName,FALSE);
+ }
+ }
+
+
+ // CODE GENERATION
+ // Generate "execute action" code here, now that we know the id.
+
+ if (pNode->nIntegerData == 0)
+ {
+ int32_t nIdentifierOrder = m_pcIdentifierList[nCount].m_nIdIdentifier;
+
+ // Write the command that calls a predefined function.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EXECUTE_COMMAND;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // Enter the integer constant.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) ((nIdentifierOrder >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (nIdentifierOrder & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (m_pcIdentifierList[nCount].m_nParameters & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 3;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+ else
+ {
+ // Write the command that calls a user-defined function.
+
+ // Here, we will need to write a symbol into the code and
+ // mark the location for updating during the label generation pass.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JSR;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // There is no point in expressing this yet, because we haven't decided on the
+ // locations of any of the final functions in the executable. So, write
+ // the symbol into the table.
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("FE_%s",m_pcIdentifierList[nCount].m_psIdentifier.CStr()); */
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,
+ nCount,0);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_DECLARATION_DOES_NOT_MATCH_PARAMETERS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG)
+ {
+ // Handled in the InVisit call, so we don't need to do anything
+ // here to handle this case.
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FOR_BLOCK)
+ {
+ // This instruction is a placeholder for script debugging when
+ // we don't include compound statements on the inside of FOR loops.
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT)
+ {
+
+ // We keep track of all of the variables added at this recursion level, and
+ // peel them off one by one. This is actually done within the script itself
+ // as well, since we need to keep track of what's happening. However, we
+ // don't need to worry about the address of a variable.
+
+ int32_t nStackAtStart = m_nStackCurrentDepth;
+
+ while (m_nOccupiedVariables >= 0 &&
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarLevel == m_nVarStackRecursionLevel)
+ {
+ if (m_pcVarStackList[m_nOccupiedVariables].m_nVarType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ int32_t nSize = GetStructureSize(m_pcVarStackList[m_nOccupiedVariables].m_sVarStructureName) >> 2;
+ m_nStackCurrentDepth -= nSize;
+ }
+ else
+ {
+ --m_nStackCurrentDepth;
+ }
+ RemoveFromSymbolTableVarStack(m_nOccupiedVariables, m_nStackCurrentDepth, m_nGlobalVariableSize);
+ --m_nOccupiedVariables;
+ }
+
+ --m_nVarStackRecursionLevel;
+
+ // Code Generation
+
+ int32_t nStackModifier = (m_nStackCurrentDepth - nStackAtStart) * 4;
+
+ if (nStackModifier != 0)
+ {
+ EmitModifyStackPointer(nStackModifier);
+ }
+
+ // At this point we should have had the same state that we saved earlier. If we
+ // don't, there's a big problem, and we should be alerted to it. This is really
+ // a compiler error, rather than something the user has done.
+
+ if (pNode->m_nStackPointer != m_nStackCurrentDepth)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INCORRECT_VARIABLE_STATE_LEFT_ON_STACK,pNode);
+ }
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_CONDITION ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COND_CONDITION ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_CONDITION ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_CONDITION ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_CONDITION)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ pNode->nType = pNode->pLeft->nType;
+ // I *HOPE* this is not a structure, but just in case.
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ (pNode->m_psTypeName) = new CExoString(pNode->pLeft->m_psTypeName->CStr());
+ }
+ }
+
+ // If we're a switch condition, confirm that we're an integer at this stage!
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_CONDITION)
+ {
+ if (m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_SWITCH_MUST_EVALUATE_TO_AN_INTEGER,pNode);
+ }
+
+ // MGB - 12/06/2004 - START FIX
+ //
+ // Why didn't anyone tell me that the debugger was screwed when
+ // entering/leaving case statements. It's been broken for nearly 18 months!
+ //
+ // Okay, stop ranting ... we know it's a problem NOW. The fix is as follows:
+ //
+ // Here, we must add the code to hang a "#switcheval" parameter on to the
+ // variable stack. However, the integer is already on the stack (what do
+ // you think we're checking above?), so we simply have to delude the variable
+ // stack to add the variable at this point (and hand it to the Symbol Table).
+ // At the end of the SWITCH_BLOCK, we will remove the "#switcheval"
+ // variable from the Symbol Table.
+
+ ++m_nOccupiedVariables;
+
+ m_pcVarStackList[m_nOccupiedVariables].m_psVarName = "#switcheval";
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarLevel = m_nVarStackRecursionLevel;
+
+ // Note we must subtract four from the current top, since the variable is really at
+ // (m_nStackCurrentDepth - 1), instead of the top of the list.
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarRunTimeLocation = (m_nStackCurrentDepth - 1) * 4;
+
+ // Now it has been added to the list
+ AddToSymbolTableVarStack(m_nOccupiedVariables, m_nStackCurrentDepth - 1, m_nGlobalVariableSize);
+
+ // MGB - 12/06/2004 - END FIX
+ }
+
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_CONDITION)
+ {
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+ }
+
+ return 0;
+ }
+
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK)
+ {
+ // MGB - 12/06/2004 - START FIX
+ //
+ // If you look a few lines up, I rant about the need to put in this
+ // "#switcheval" variable for a switch statement, since the game
+ // will proceed to emit fiery chunks by running a case through the
+ // debugger when there is a string (or other deferencable object)
+ // as the top thing on the stack. It basically screws the stack
+ // by one. This is our attempt to undo the hack at this point!
+ //
+ // At the end of the SWITCH_BLOCK, we will remove the "#switcheval"
+ // variable from the Symbol Table.
+
+ RemoveFromSymbolTableVarStack(m_nOccupiedVariables, m_nStackCurrentDepth - 1, m_nGlobalVariableSize);
+ --m_nOccupiedVariables;
+
+ // MGB - 12/06/2004 - END FIX
+
+ // Generate a label for the end of the function (used by the break keyword)
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_BR_%08x",m_nSwitchIdentifier); */
+ AddSymbolToLabelList(m_nOutputCodeLength,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_BREAK,
+ m_nSwitchIdentifier);
+
+ // Restore the old values of switch level and the switch identifier.
+ --m_nSwitchLevel;
+ m_nSwitchIdentifier = pNode->nIntegerData2;
+ m_nSwitchStackDepth = pNode->nIntegerData3;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK)
+ {
+
+ // Here, we implement the loop back to location _W1_ and insert
+ // the information on jumping to _W2_ at this point.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ int32_t nJmpLength = pNode->nIntegerData - m_nOutputCodeLength;
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nJmpLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nJmpLength)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JZ command we gave earlier during
+ // the InVisit() [code located at pNode->nIntegerdata2].
+ // This is an awfully good thing to do.
+
+ nJmpLength = m_nOutputCodeLength - pNode->nIntegerData2;
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ // Generate a label for the end of the function (used by the break keyword)
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_BR_%08x",m_nLoopIdentifier); */
+ AddSymbolToLabelList(m_nOutputCodeLength, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_BREAK,m_nLoopIdentifier,0);
+
+
+ pNode->nType = pNode->pLeft->nType;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ pNode->m_psTypeName = new CExoString(pNode->pLeft->m_psTypeName->CStr());
+ }
+
+ // Reset the loop identifier.
+ m_nLoopIdentifier = pNode->nIntegerData3;
+ m_nLoopStackDepth = pNode->nIntegerData4;
+
+ return 0;
+
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_CHOICE)
+ {
+ // FOR TESTING PURPOSES
+ // We do nothing. Why? It's all done by WHILE_BLOCK
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK)
+ {
+ // CODE GENERATION
+ // Here, we implement a JZ to _DW2_, which clears the JMP back to _DW1_.
+
+ //
+ // First, let's deal with the JZ instruction.
+ //
+
+ if (m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INTEGER_NOT_AT_TOP_OF_STACK,pNode);
+ }
+ --m_nStackCurrentDepth;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JZ;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // The jump length is over this instruction and the jmp instruction, both of
+ // which are OPERATION_BASE_SIZE + 4 (for the address).
+
+ int32_t nJmpLength = (CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4) << 1;
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nJmpLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nJmpLength)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ //
+ // And now, the JMP instruction.
+ //
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // The jmp length is back to the beginning of the do/while loop,
+ // which is stored in pNode->nIntegerData;
+ // which are OPERATION_BASE_SIZE + 4 (for the address).
+
+ nJmpLength = pNode->nIntegerData - m_nOutputCodeLength;
+ m_pchOutputCode[m_nOutputCodeLength+ CVIRTUALMACHINE_EXTRA_DATA_LOCATION ] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nJmpLength) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nJmpLength)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Generate a label for the end of the function (used by the break keyword)
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_BR_%08x",m_nLoopIdentifier); */
+ AddSymbolToLabelList(m_nOutputCodeLength, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_BREAK,m_nLoopIdentifier);
+
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,pNode->nLine,m_nOutputCodeLength);
+ }
+
+ pNode->nType = pNode->pRight->nType;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ pNode->m_psTypeName = new CExoString(pNode->pRight->m_psTypeName->CStr());
+ }
+
+ // Reset the loop identifier.
+ m_nLoopIdentifier = pNode->nIntegerData3;
+ m_nLoopStackDepth = pNode->nIntegerData4;
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_CHOICE)
+ {
+ // Here, we implement the loop back to location _W1_ and insert
+ // the information on jumping to _W2_ at this point.
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JMP command we gave earlier during
+ // the InVisit() [code located at pNode->nIntegerdata2].
+ // This is an awfully good thing to do.
+
+ int32_t nJmpLength = m_nOutputCodeLength - pNode->nIntegerData2;
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ // FOR TESTING PURPOSES
+ // We do nothing. Why? It's been done in pregenerate code
+ // (to reflect where the variable will be removed from the
+ // stack during the run-time execution!)
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK)
+ {
+ pNode->nType = pNode->pLeft->nType;
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COND_CHOICE)
+ {
+ // Here, we implement the loop back to location _CH1_ and insert
+ // the information on jumping to _CH2_ at this point.
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JMP command we gave earlier during
+ // the InVisit() [code located at pNode->nIntegerdata2].
+ // This is an awfully good thing to do.
+
+ int32_t nJmpLength = m_nOutputCodeLength - pNode->nIntegerData2;
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ // FOR TESTING PURPOSES
+ // Check to see if the types are the same.
+
+ if (pNode->pLeft->nType != pNode->pRight->nType ||
+ (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT &&
+ *(pNode->pLeft->m_psTypeName) != *(pNode->pRight->m_psTypeName)))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_CONDITIONAL_MUST_HAVE_MATCHING_RETURN_TYPES,pNode);
+ }
+
+ pNode->nType = pNode->pLeft->nType;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ pNode->m_psTypeName = new CExoString(pNode->pLeft->m_psTypeName->CStr());
+ }
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COND_BLOCK)
+ {
+ // Type of the conditional block is the same as the type of the conditional choice
+ // underneath it (pRight).
+ pNode->nType = pNode->pRight->nType;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ pNode->m_psTypeName = new CExoString(pNode->pRight->m_psTypeName->CStr());
+ }
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_NON_VOID_EXPRESSION ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_INTEGER_EXPRESSION)
+ {
+
+ // MGB - October 29, 2002 - START CHANGE
+ // Code changed to properly account for "action" variables (which aren't
+ // actually stored on the stack) as non-void expressions.
+
+ int32_t nTargetRemovedTokens = 1;
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION)
+ {
+ nTargetRemovedTokens = 0;
+ }
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nTargetRemovedTokens = (GetStructureSize(*(pNode->pLeft->m_psTypeName)) >> 2);
+ }
+
+ int nActualRemovedTokens = m_nStackCurrentDepth - pNode->m_nStackPointer;
+
+ if (nActualRemovedTokens == 0 && nTargetRemovedTokens != 0)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_VOID_EXPRESSION_WHERE_NON_VOID_REQUIRED,pNode);
+ }
+
+ if (nActualRemovedTokens != nTargetRemovedTokens)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_INCORRECT_VARIABLE_STATE_LEFT_ON_STACK,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_INTEGER_EXPRESSION &&
+ m_pchStackTypes[m_nStackCurrentDepth-1] != CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_NON_INTEGER_EXPRESSION_WHERE_INTEGER_REQUIRED,pNode);
+ }
+
+ // Now, that we've "verified" the type, we should be able to set the value
+ // of the type of the expression underneath it.
+ pNode->nType = pNode->pLeft->nType;
+
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+
+ pNode->m_psTypeName = new CExoString(pNode->pLeft->m_psTypeName->CStr());
+ }
+
+ // MGB - October 29, 2002 - END CHANGE
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_LOGICAL_AND)
+ {
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write a "logical AND of two ints" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_LOGICAL_AND;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+
+ // Now, we insert the label _ILA_ to indicate this is where we jump
+ // to on a "short cut".
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JZ command we gave earlier during
+ // the InVisit() [code located at pNode->nIntegerData].
+ // This is an awfully good thing to do.
+
+ int32_t nJmpLength = m_nOutputCodeLength - pNode->nIntegerData;
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_LOGICAL_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_LOGICAL_OR)
+ {
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // First, we insert the label _ILO_ to indicate this is where we jump
+ // to on a "short cut".
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+
+ // Here, we go back and add the relative offset to get beyond this return
+ // statement to the JMP command we gave earlier during
+ // the InVisit() [code located at pNode->nIntegerData].
+ // This is an awfully good thing to do.
+
+ int32_t nJmpLength = m_nOutputCodeLength - pNode->nIntegerData;
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nJmpLength) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nJmpLength) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nJmpLength) >> 8 ) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nJmpLength) ) & 0x0ff);
+
+ // CODE GENERATION
+ // Write a "logical OR of two ints" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_LOGICAL_OR;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_LOGICAL_OPERATION_HAS_INVALID_OPERANDS,pNode);
+
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_INCLUSIVE_OR)
+ {
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write an "inclusive OR of two ints" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_INCLUSIVE_OR;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_LOGICAL_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_EXCLUSIVE_OR)
+ {
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write an "exclusive OR of two ints" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EXCLUSIVE_OR;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_LOGICAL_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_BOOLEAN_AND)
+ {
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write an "boolean AND of two ints" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_BOOLEAN_AND;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_LOGICAL_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_NOT_EQUAL)
+ {
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write an "condition EQUAL/NOT EQUAL of two ints" operation.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EQUAL;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NOT_EQUAL;
+ }
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ // CODE GENERATION
+ // Write an "condition EQUAL/NOT EQUAL of two floats" operation.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EQUAL;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NOT_EQUAL;
+ }
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_FLOAT;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove two floats, add an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT)
+ {
+ // CODE GENERATION
+ // Write an "condition EQUAL/NOT EQUAL of two objects" operation.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EQUAL;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NOT_EQUAL;
+ }
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_OBJECT_OBJECT;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove two objects, add an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ // CODE GENERATION
+ // Write an "condition EQUAL/NOT EQUAL of two strings" operation.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EQUAL;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NOT_EQUAL;
+ }
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_STRING_STRING;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ pNode->pLeft->nType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9 &&
+ pNode->pRight->nType == pNode->pLeft->nType)
+ {
+
+ uint8_t nEngineStructureNumber = (uint8_t) (pNode->pLeft->nType - CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0);
+
+ // CODE GENERATION
+ // Write an "condition EQUAL/NOT EQUAL of two strings" operation.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EQUAL;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NOT_EQUAL;
+ }
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = (char) (CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST0_ENGST0 + nEngineStructureNumber);
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (*(pNode->pLeft->m_psTypeName) == *(pNode->pRight->m_psTypeName))
+ {
+ int32_t nSize = GetStructureSize(*(pNode->pLeft->m_psTypeName));
+
+ // CODE GENERATION
+ // Write an "condition EQUAL/NOT EQUAL of two strings" operation.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_EQUAL;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NOT_EQUAL;
+ }
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_STRUCT_STRUCT;
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+0] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 2;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+
+ // FOR TESTING PURPOSES
+ // Remove the two structures, and add an INT.
+
+ // Why remove half of the size? We're actually removing two structures, but
+ // the size reported is actually in bytes, not in the number of entries the
+ // stack is measured in. Thus, nSize * 2 / 4 = nSize >> 1.
+
+ m_nStackCurrentDepth -= (nSize >> 1);
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_EQUALITY_TEST_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_GEQ ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_GT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_LT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_LEQ)
+ {
+
+ // CODE GENERATION
+ // Write the base of the arithmetic operation.
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_GEQ)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_GEQ;
+ }
+ else if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_GT)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_GT;
+ }
+ else if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONDITION_LT)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_LT;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_LEQ;
+ }
+
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write an "condition GEQ/GT/LT/LEQ of two ints" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ // CODE GENERATION
+ // Write an "condition GEQ/GT/LT/LEQ of two floats" operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_FLOAT;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_COMPARISON_TEST_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SHIFT_LEFT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SHIFT_RIGHT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_UNSIGNED_SHIFT_RIGHT)
+ {
+
+
+
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write an "<>>/>>> of two ints" operation.
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SHIFT_LEFT)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_SHIFT_LEFT;
+ }
+ else if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SHIFT_RIGHT)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_SHIFT_RIGHT;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_USHIFT_RIGHT;
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // FOR TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_SHIFT_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ADD ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SUBTRACT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_MULTIPLY ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DIVIDE)
+ {
+
+ // CODE GENERATION
+ // Write the base of the arithmetic operation.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ADD)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_ADD;
+ }
+ else if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SUBTRACT)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_SUB;
+ }
+ else if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_MULTIPLY)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_MUL;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_DIV;
+ }
+
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write a +-*/ operation on two ints.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write a +-*/ operation on a float and a PROMOTED int.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ // CODE GENERATION
+ // Write a +-*/ operation on a PROMOTED int and a float.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_FLOAT;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ // CODE GENERATION
+ // Write a +-*/ operation on a PROMOTED int and a float.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_FLOAT;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove a float.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ if (pNode->nOperation != CSCRIPTCOMPILER_OPERATION_ADD)
+ { {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ }
+ // CODE GENERATION
+ // Write a s+s operation on two strings.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_STRING_STRING;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove both vectors, and add one back.
+ m_nStackCurrentDepth -= 2;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING,NULL,FALSE);
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (*(pNode->pLeft->m_psTypeName) == "vector" && *(pNode->pRight->m_psTypeName) == *(pNode->pLeft->m_psTypeName))
+ {
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_MULTIPLY ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DIVIDE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ // CODE GENERATION
+ // Write a v+-v operation on two vectors.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_VECTOR_VECTOR;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove both vectors, and add one back.
+ m_nStackCurrentDepth -= 6;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT,pNode->pLeft->m_psTypeName,FALSE);
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+ pNode->m_psTypeName = new CExoString(pNode->pLeft->m_psTypeName->CStr());
+ return 0;
+
+ }
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ if (*(pNode->pLeft->m_psTypeName) == "vector")
+ {
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ADD ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SUBTRACT)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ // CODE GENERATION
+ // Write a v*/f operation on two vectors.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_VECTOR_FLOAT;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove the vector and scalar, and add the back back.
+ m_nStackCurrentDepth -= 4;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT,pNode->pLeft->m_psTypeName,FALSE);
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+ pNode->m_psTypeName = new CExoString(pNode->pLeft->m_psTypeName->CStr());
+ return 0;
+ }
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ if (*(pNode->pRight->m_psTypeName) == "vector")
+ {
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ADD ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_SUBTRACT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DIVIDE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+
+ // CODE GENERATION
+ // Write a f*v operation.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_VECTOR;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove the vector and scalar, and add the vector back.
+ m_nStackCurrentDepth -= 4;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT,pNode->pRight->m_psTypeName,FALSE);
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ if (pNode->m_psTypeName != NULL)
+ {
+ delete pNode->m_psTypeName;
+ }
+ pNode->m_psTypeName = new CExoString(pNode->pRight->m_psTypeName->CStr());
+ return 0;
+ }
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_MODULUS)
+ {
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write a % operation on two ints.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_MODULUS;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Remove an integer.
+ --m_nStackCurrentDepth;
+ --m_nStackCurrentDepth;
+ AddVariableToStack(CSCRIPTCOMPILER_TOKEN_KEYWORD_INT,NULL,FALSE);
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_NEGATION)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write a negation operation on an int.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NEGATION;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Do nothing.
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ // CODE GENERATION
+ // Write a negation operation on a float.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_NEGATION;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ // For TESTING PURPOSES
+ // Do nothing.
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ return 0;
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_ONES_COMPLEMENT)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write a negation operation on an int.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_ONES_COMPLEMENT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Do nothing.
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_BOOLEAN_NOT)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ if (pNode->pLeft->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ // CODE GENERATION
+ // Write a negation operation on an int.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_BOOLEAN_NOT;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // For TESTING PURPOSES
+ // Do nothing.
+
+ pNode->nType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ return 0;
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS,pNode);
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STRUCTURE_DEFINITION)
+ {
+ // We should be in the variable-processing stage of the strucutre
+ // definition at this point.
+
+ if (m_nStructureDefinition != 2)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ // Set where the last field for this structure is located.
+
+ m_pcStructList[m_nMaxStructures].m_nFieldEnd = m_nMaxStructureFields - 1;
+
+ // Count the size of all the components in this structure.
+
+ int32_t nTotalSize = 0;
+
+ int32_t count;
+ for (count = m_pcStructList[m_nMaxStructures].m_nFieldStart;
+ count <= m_pcStructList[m_nMaxStructures].m_nFieldEnd;
+ ++count)
+ {
+ // Since we haven't set the location of the variables within this
+ // structure, we might as well do it here.
+ m_pcStructFieldList[count].m_nLocation = nTotalSize;
+
+ // All variables are of size "4" (i.e. 4 bytes), unless you've got
+ // a structure, which could take a lot more than 4 bytes on the
+ // stack. Thus, one would like to make these into 4 byte values.
+ if (m_pcStructFieldList[count].m_pchType != CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nTotalSize += 4;
+ }
+ else
+ {
+ int32_t count2;
+ for (count2 = 0; count2 < m_nMaxStructures; count2++)
+ {
+ if (m_pcStructFieldList[count].m_psStructureName == m_pcStructList[count2].m_psName)
+ {
+ nTotalSize += m_pcStructList[count2].m_nByteSize;
+ }
+ }
+ }
+ }
+
+ m_pcStructList[m_nMaxStructures].m_nByteSize = nTotalSize;
+
+ if (nTotalSize == 0)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ // Clear out the fact that we're in a structure definition ... since
+ // we're done this definition.
+ m_nStructureDefinition = 0;
+
+ // Finally, add the structure definition to the ones that we can look at.
+ ++m_nMaxStructures;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART)
+ {
+ m_bInStructurePart = FALSE;
+
+ if (pNode->pLeft != NULL && pNode->pRight != NULL)
+ {
+ if (pNode->pLeft->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_LEFT_OF_STRUCTURE_PART_NOT_STRUCTURE,pNode);
+ }
+ /*
+ if (pNode->pRight->nOperation != CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_RIGHT_OF_STRUCTURE_PART_NOT_FIELD_IN_STRUCTURE,pNode);
+ }
+ */
+
+ // Now that we have verified we have a structure on the left,
+ // and a variable on the right ... we can determine if we've
+ // got a field within the specified structure.
+ int32_t nValue = GetStructureField(*(pNode->pLeft->m_psTypeName), *(pNode->pRight->m_psStringData));
+ if (nValue < 0)
+ {
+ return OutputWalkTreeError(nValue,pNode);
+ }
+
+ // Yes, we have a valid structure field. Fetch the type,
+ // and structure name (if necessary) out of the structure field.
+ pNode->nType = m_pcStructFieldList[nValue].m_pchType;
+ if (pNode->nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ pNode->m_psTypeName = new CExoString(m_pcStructFieldList[nValue].m_psStructureName.CStr());
+ }
+
+ // Now, we update the pointer to the location of the variable. In
+ // all cases, we should still have a pointer into the stack that will
+ // help us determine the location of the structure part.
+ pNode->nIntegerData = pNode->pLeft->nIntegerData + m_pcStructFieldList[nValue].m_nLocation;
+
+ if (m_bAssignmentToVariable == FALSE)
+ {
+ // Let's do some code down here! We want to be able to remove
+ // the structure at the top of the stack and bust it down to
+ // the current thing on the stack. Thus, we create a new
+ // opcode for handling the division of a structure. It will
+ // have three parameters. (1) Size Of Original Structure
+ // (2) Start Location of New Component (3) Size of New
+ // Component. All of these will be with respect to the run-time
+ // stack.
+
+ int32_t nSizeOriginal = GetStructureSize(*(pNode->pLeft->m_psTypeName));
+
+ int32_t nSize = 4;
+ if (m_pcStructFieldList[nValue].m_pchType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nSize = GetStructureSize(*(pNode->m_psTypeName));
+ }
+
+ int32_t nStartComponent = m_pcStructFieldList[nValue].m_nLocation;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_DE_STRUCT;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nSizeOriginal) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nSizeOriginal)) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStartComponent) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStartComponent)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Okay, now we have to actually apply the de-struct information.
+ int32_t nCutSizeOriginal = (nSizeOriginal >> 2);
+ int32_t nCutSize = (nSize >> 2);
+ int32_t nCutStartComponent = (nStartComponent >> 2);
+
+ // Let's see what we want ...
+ //
+ //
+ // C C C C C C C
+ //
+ // B
+ // A A A
+ //
+ // nCutSize = A;
+ // nCutStartComponent = B;
+ // nCutSizeOriginal = C;
+ //
+ // StackPointer = Base + C;
+ // if (A+B < C)
+ // {
+ // StackPointer = Base + A + B; (Thus, subtract
+ // }
+ //
+ // Copy To Base ... Base+A-1 from Base+B to Base+A+B-1
+ //
+ // StackPointer = Base + A; // Remove B
+
+ if (nCutSize + nCutStartComponent < nCutSizeOriginal)
+ {
+ m_nStackCurrentDepth -= nCutSizeOriginal;
+ m_nStackCurrentDepth += nCutSize + nCutStartComponent;
+ }
+
+ for (int32_t count = m_nStackCurrentDepth - nCutSize - nCutStartComponent; count < m_nStackCurrentDepth - nCutStartComponent; ++count)
+ {
+ m_pchStackTypes[count] = m_pchStackTypes[count + nCutStartComponent];
+ }
+
+ m_nStackCurrentDepth -= nCutStartComponent;
+ }
+
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FUNCTIONAL_UNIT)
+ {
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FUNCTION )
+ {
+ // If there's no function implementation, we do not need to do anything.
+ if (m_bFunctionImp == FALSE)
+ {
+ return 0;
+ }
+
+ // Remove all variables, aside from #retval (only save #retval if the
+ // function is non-void).
+
+ int32_t nReturnValueLevel = m_nGlobalVariables;
+
+ if (m_nFunctionImpReturnType != CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ ++nReturnValueLevel;
+ }
+
+ while (m_nOccupiedVariables >= nReturnValueLevel)
+ {
+
+ if (m_pcVarStackList[m_nOccupiedVariables].m_nVarType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ int32_t nSize = GetStructureSize(m_pcVarStackList[m_nOccupiedVariables].m_sVarStructureName) >> 2;
+ m_nStackCurrentDepth -= nSize;
+ }
+ else
+ {
+ --m_nStackCurrentDepth;
+ }
+ RemoveFromSymbolTableVarStack(m_nOccupiedVariables, m_nStackCurrentDepth, m_nGlobalVariableSize);
+ --m_nOccupiedVariables;
+ }
+
+ // MGB - August 14, 2002 - For Scripting Debugger
+ // The COMPOUND_STATEMENT on the inside of the function declaration contains
+ // the placement of the final bracket and, hence, where the final line of
+ // code in the function belongs.
+ int32_t nLineEndOfFunction = pNode->nLine;
+ if (pNode->pRight != NULL)
+ {
+ nLineEndOfFunction = pNode->pRight->nLine;
+ }
+
+
+ // MGB - August 9, 2002 - Final Bracket Debugging
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ StartLineNumberAtBinaryInstruction(pNode->m_nFileReference,nLineEndOfFunction,m_nOutputCodeLength);
+ }
+
+ // At this point we should have the state with just the return value
+ // on the stack. We should use this opportunity to generate the shift
+ // in the run-time stack.
+
+ // Generate a label for the end of the function (used by the RETURN keyword)
+ /* CExoString sSymbolName;
+ sSymbolName.Format("FX_%s",m_sFunctionImpName.CStr()); */
+ int32_t nIdentifier = GetIdentifierByName(m_sFunctionImpName);
+ if (nIdentifier == STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ AddSymbolToLabelList(m_nOutputCodeLength, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_EXIT, nIdentifier, 0);
+
+ // Move the stack to update the current location of the code.
+
+ int32_t nStackModifier = (m_nStackCurrentDepth - pNode->m_nStackPointer) * 4;
+
+ if (nStackModifier != 0)
+ {
+ EmitModifyStackPointer(nStackModifier);
+ }
+
+ // MGB - August 22, 2002 - For Scripting Debugger
+ if (nReturnValueLevel != m_nGlobalVariables)
+ {
+ // Remove the variable from the StackCurrentDepth before
+ // handing it off to the code to get rid of!
+ int32_t nStackCurrentDepth = m_nStackCurrentDepth;
+
+ if (m_pcVarStackList[m_nOccupiedVariables].m_nVarType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ int32_t nSize = GetStructureSize(m_pcVarStackList[m_nOccupiedVariables].m_sVarStructureName) >> 2;
+ nStackCurrentDepth -= nSize;
+ }
+ else
+ {
+ --nStackCurrentDepth;
+ }
+
+ RemoveFromSymbolTableVarStack(m_nOccupiedVariables, nStackCurrentDepth, m_nGlobalVariableSize);
+ }
+
+ // Add the RET statement
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RET;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE ;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Remove the last variable (#retval), and reset the state of the
+ // variable stack.
+
+ if (m_nFunctionImpReturnType != CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ // Check the function using our custom function to handle this.
+ if (FoundReturnStatementOnAllBranches(pNode->pRight) == FALSE)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_NOT_ALL_CONTROL_PATHS_RETURN_A_VALUE,pNode);
+ }
+ }
+
+ // If the function is non-void, remove #retval from the stack.
+ // The way we know the function is non-void can be found above.
+
+
+ if (nReturnValueLevel != m_nGlobalVariables)
+ {
+ if (m_pcVarStackList[m_nOccupiedVariables].m_nVarType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ int32_t nSize = GetStructureSize(m_pcVarStackList[m_nOccupiedVariables].m_sVarStructureName) >> 2;
+ m_nStackCurrentDepth -= nSize;
+ }
+ else
+ {
+ --m_nStackCurrentDepth;
+ }
+ --m_nOccupiedVariables;
+ }
+
+ --m_nVarStackRecursionLevel;
+
+ nIdentifier = GetIdentifierByName(m_sFunctionImpName);
+
+ if (nIdentifier < 0)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ m_pcIdentifierList[nIdentifier].m_nBinarySourceFinish = m_nOutputCodeLength;
+
+ m_bFunctionImp = FALSE;
+
+ // MGB - August 9, 2002 - Final Bracket Debugging
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ EndLineNumberAtBinaryInstruction(pNode->m_nFileReference,nLineEndOfFunction,m_nOutputCodeLength);
+ }
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_GLOBAL_VARIABLES)
+ {
+ m_bGlobalVariableDefinition = FALSE;
+
+ // Add the SAVE_BASE_POINTER statement so that these globals can be used.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_SAVE_BASE_POINTER;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ ////////////////////////////////////////////////////
+ // MGB - September 13, 2001 - Start of added chunk.
+ ////////////////////////////////////////////////////
+
+ if (m_bCompileConditionalFile == TRUE)
+ {
+ // Write the integer that we're going to store the return value into!
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_ADD;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+
+ //////////////////////////////////////////////////
+ // MGB - September 13, 2001 - End of added chunk.
+ //////////////////////////////////////////////////
+
+ // Write the JSR FE_main instruction that is guaranteed to be successful
+ // because of the checks in InstallLoader().
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JSR;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // There is no point in expressing this yet, because we haven't decided on the
+ // locations of any of the final functions in the executable. So, write
+ // the symbol into the table.
+
+ /*
+ CExoString sSymbolName;
+ if (m_bCompileConditionalFile == FALSE)
+ {
+ sSymbolName.Format("FE_main");
+ }
+ else
+ {
+ sSymbolName.Format("FE_StartingConditional");
+ }
+ */
+
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION,
+ CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY,0,2);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+
+ ////////////////////////////////////////////////////
+ // MGB - September 13, 2001 - Start of added chunk.
+ ////////////////////////////////////////////////////
+
+ if (m_bCompileConditionalFile == TRUE)
+ {
+ // We need to assign the return value to the first value on the stack (which is the return value
+ // of the full function).
+
+ // Set up a "write to #retval" instruction.
+
+ // Must move beyond Global Variables + [#retval + basepointer (on stack) + RSADDI = 12]
+ int32_t nStackElementsDown = -(m_nGlobalVariableSize + 12);
+ int32_t nSize = 4;
+ if (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nSize = GetStructureSize(m_sFunctionImpReturnStructureName);
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_ASSIGNMENT;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+
+ // Add the "modify stack pointer" statement so that the return value is never used again.
+ EmitModifyStackPointer(-4);
+ }
+
+ //////////////////////////////////////////////////
+ // MGB - September 13, 2001 - End of added chunk.
+ //////////////////////////////////////////////////
+
+ // Add the RESTORE_BASE_POINTER statement so that these globals can be popped off.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RESTORE_BASE_POINTER;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ ////////////////////////////////////////////////////
+ // MGB - September 13, 2001 - Start of added chunk.
+ ////////////////////////////////////////////////////
+
+ // Add the "modify stack pointer" statement so that these globals are never used again
+
+ int32_t nStackPointer = -m_nGlobalVariableSize;
+
+ // MGB - April 12, 2002 - Removing a bug where this instruction is added needlessly
+ // (causing great grief to the virtual machine) when the stack pointer doesn't need
+ // to be moved at all!
+ if (nStackPointer != 0)
+ {
+ EmitModifyStackPointer(nStackPointer);
+ }
+
+ //////////////////////////////////////////////////
+ // MGB - September 13, 2001 - End of added chunk.
+ //////////////////////////////////////////////////
+
+
+
+ // Finally, add the RET statement so that we can bail out of this routine.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RET;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ // Last, but not least, add a function to the user-defined identifier list
+ // that specifies where this code is located.
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceFinish = m_nOutputCodeLength;
+
+ ++m_nOccupiedIdentifiers;
+ if (m_nOccupiedIdentifiers >= CSCRIPTCOMPILER_MAX_IDENTIFIERS)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_IDENTIFIER_LIST_FULL,pNode);
+ }
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FUNCTION_IDENTIFIER)
+ {
+ // We've just read a "type", but we really don't need to propogate this type to
+ // anyone ... we'll simply feed it
+ m_nVarStackVariableType = CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION;
+
+ if (m_bFunctionImp == FALSE)
+ {
+ return 0;
+ }
+
+ if (pNode->pLeft == NULL)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ //
+ // We want to add #retval to the run-time stack, and record the
+ // return type.
+ //
+
+ // We know the "operation" of the type via the left branch, but
+ // we don't actually know the "token" type.
+ int32_t nTokenType;
+ CExoString sTokenStructureName = "";
+
+ if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ sTokenStructureName = *(pNode->pLeft->m_psStringData);
+ }
+ else if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ }
+ else if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ }
+ else if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ }
+ else if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT;
+ }
+ else if (pNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID;
+ }
+ else if (pNode->pLeft->nOperation >= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0 &&
+ pNode->pLeft->nOperation <= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 +
+ (pNode->pLeft->nOperation - CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0);
+ }
+ else
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ // Add the variable "#retval" to the occupied variables list.
+
+ if (nTokenType != CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ ++m_nOccupiedVariables;
+ if (m_bGlobalVariableDefinition)
+ {
+ ++m_nGlobalVariables;
+ if (nTokenType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_nGlobalVariableSize += GetStructureSize(sTokenStructureName);
+ }
+ else
+ {
+ m_nGlobalVariableSize += 4;
+ }
+ }
+
+ m_pcVarStackList[m_nOccupiedVariables].m_psVarName = "#retval";
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarType = nTokenType;
+ if (nTokenType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_pcVarStackList[m_nOccupiedVariables].m_sVarStructureName = sTokenStructureName;
+ }
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarLevel = m_nVarStackRecursionLevel;
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarRunTimeLocation = m_nStackCurrentDepth * 4;
+
+ // Now, we can add the variable to the run time stack!
+
+ int32_t nOccupiedVariables = m_nOccupiedVariables;
+ int32_t nStackCurrentDepth = m_nStackCurrentDepth;
+ int32_t nGlobalVariableSize = m_nGlobalVariableSize;
+ AddVariableToStack(nTokenType, &sTokenStructureName, FALSE);
+ AddToSymbolTableVarStack(nOccupiedVariables,nStackCurrentDepth,nGlobalVariableSize);
+ }
+
+ m_nFunctionImpReturnType = nTokenType;
+ m_sFunctionImpReturnStructureName = sTokenStructureName;
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FUNCTION_PARAM_NAME)
+ {
+
+ m_nVarStackVariableType = CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION;
+
+ if (m_bFunctionImp == FALSE)
+ {
+ // This is required here, since we've just discovered that we're
+ // actually parsing a function and not a series of declarations.
+ return 0;
+ }
+
+ if (pNode->pRight == NULL)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ for (nCount = m_nOccupiedVariables; nCount >= 0; --nCount)
+ {
+ if (m_pcVarStackList[nCount].m_psVarName == *(pNode->m_psStringData) &&
+ m_pcVarStackList[nCount].m_nVarLevel == m_nVarStackRecursionLevel)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_VARIABLE_ALREADY_USED_WITHIN_SCOPE,pNode);
+ }
+ }
+
+ // We know the "operation" of the type via the left branch, but
+ // we don't actually know the "token" type.
+ int32_t nTokenType;
+ CExoString sTokenStructureName = "";
+
+ if (pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ sTokenStructureName = *(pNode->pRight->m_psStringData);
+ }
+ else if (pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ }
+ else if (pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ }
+ else if (pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ }
+ else if (pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT;
+ }
+ else if (pNode->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID;
+ }
+ else if (pNode->pRight->nOperation >= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0 &&
+ pNode->pRight->nOperation <= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ nTokenType = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 +
+ (pNode->pRight->nOperation - CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0);
+ }
+
+ else
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ // Add the variable named at this node to the occupied variables list.
+
+ if (nTokenType != CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ ++m_nOccupiedVariables;
+ if (m_bGlobalVariableDefinition)
+ {
+ ++m_nGlobalVariables;
+ if (nTokenType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_nGlobalVariableSize += GetStructureSize(sTokenStructureName);
+ }
+ else
+ {
+ m_nGlobalVariableSize += 4;
+ }
+
+ }
+
+ m_pcVarStackList[m_nOccupiedVariables].m_psVarName = *(pNode->m_psStringData);
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarType = nTokenType;
+ if (nTokenType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_pcVarStackList[m_nOccupiedVariables].m_sVarStructureName = sTokenStructureName;
+ }
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarLevel = m_nVarStackRecursionLevel;
+ m_pcVarStackList[m_nOccupiedVariables].m_nVarRunTimeLocation = m_nStackCurrentDepth * 4;
+
+ // Now, we can add the variable to the run time stack!
+ int32_t nOccupiedVariables = m_nOccupiedVariables;
+ int32_t nStackCurrentDepth = m_nStackCurrentDepth;
+ int32_t nGlobalVariableSize = m_nGlobalVariableSize;
+ AddVariableToStack(nTokenType, &sTokenStructureName, FALSE);
+ AddToSymbolTableVarStack(nOccupiedVariables,nStackCurrentDepth,nGlobalVariableSize);
+ }
+
+ // This is required here, since we've just discovered that we're
+ // actually parsing a function and not a series of declarations.
+
+
+
+ return 0;
+
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_FUNCTION_DECLARATION)
+ {
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_RETURN)
+ {
+
+ if (m_bFunctionImp == FALSE)
+ {
+ return 0;
+ }
+
+ if ((m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID && pNode->pRight != NULL) ||
+ (m_nFunctionImpReturnType != CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID && pNode->pRight == NULL))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_RETURN_TYPE_AND_FUNCTION_TYPE_MISMATCHED,pNode);
+ }
+
+ if ((m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_INT) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE1 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE1) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE3 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE3) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE4 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE4) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE5 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE5) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE6 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE6) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE8 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE8) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9 && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_RETURN_TYPE_AND_FUNCTION_TYPE_MISMATCHED,pNode);
+ }
+
+ if ((m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT && pNode->pRight->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT) ||
+ (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT && m_sFunctionImpReturnStructureName != *(pNode->pRight->m_psTypeName)))
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_RETURN_TYPE_AND_FUNCTION_TYPE_MISMATCHED,pNode);
+ }
+
+ // Okay, now we've got fun!
+
+ if (m_nFunctionImpReturnType != CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ // Set up a "write to #retval" instruction.
+
+ int32_t nStackElementsDown = m_nGlobalVariableSize - m_nStackCurrentDepth * 4;
+ int32_t nSize = 4;
+ if (m_nFunctionImpReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ nSize = GetStructureSize(m_sFunctionImpReturnStructureName);
+ }
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_ASSIGNMENT;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_VOID;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+4] = (char) (((nSize) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+5] = (char) (((nSize)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 6;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+
+ // Write the MODIFY_STACK_POINTER instruction to modify the stack.
+
+ pNode->nIntegerData = (m_nFunctionImpAbortStackPointer - m_nStackCurrentDepth) * 4;
+ //m_nStackCurrentDepth = m_nFunctionImpAbortStackPointer;
+
+ if (pNode->nIntegerData != 0)
+ {
+ EmitModifyStackPointer(pNode->nIntegerData);
+ }
+
+ // And, finally, write the JMP statement.
+
+ // Here, we will need to write a symbol into the code and
+ // mark the location for updating during the label generation pass.
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ // There is no point in expressing this yet, because we haven't decided on the
+ // locations of any of the final functions in the executable. So, write
+ // the symbol into the table.
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("FX_%s",m_sFunctionImpName.CStr()); */
+ int32_t nIdentifier = GetIdentifierByName(m_sFunctionImpName);
+ if (nIdentifier == STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_EXIT, nIdentifier, 0);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ return 0;
+
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_PRE_INCREMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_PRE_DECREMENT)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ if (pNode->pLeft->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_OPERAND_MUST_BE_AN_INTEGER_LVALUE,pNode);
+ }
+
+ // Is pNode->pLeft actually a valid LValue?
+ if (pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_VARIABLE &&
+ pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_OPERAND_MUST_BE_AN_INTEGER_LVALUE,pNode->pLeft);
+ }
+
+ pNode->nType = pNode->pLeft->nType;
+
+ // Current location of the variable is stored in pNode->pLeft->nIntegerData because
+ // it is a valid LValue.
+
+ int32_t nStackElementsDown = pNode->pLeft->nIntegerData - m_nStackCurrentDepth * 4;
+
+ // MGB - August 10, 2001 - Determine whether we should be operating on the base
+ // pointer or the stack pointer.
+
+ int32_t bOperateOnStackPointer;
+ if (pNode->pLeft->nIntegerData < m_nGlobalVariableSize && m_bGlobalVariableDefinition == FALSE)
+ {
+ bOperateOnStackPointer = FALSE;
+ nStackElementsDown = pNode->pLeft->nIntegerData - (m_nGlobalVariableSize);
+ }
+ else
+ {
+ bOperateOnStackPointer = TRUE;
+ // And don't forget to add the ADDITIONAL integer that is now sitting on top of the stack!
+ nStackElementsDown += 4;
+ }
+
+ // And now, fill in the appropriate code (pNode->nIntegerData2 points to the location
+ // of the EXTRA_DATA that we reserved for the data pointer!)
+
+ // MGB - August 10, 2001
+ // NOTE that we only write data into the opcode if we are not using the stack pointer,
+ // since the code has already been written for using the stack pointer in the PreIncrement
+ // call.
+ if (bOperateOnStackPointer == FALSE)
+ {
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_PRE_INCREMENT)
+ {
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_INCREMENT_BASE;
+ }
+ else
+ {
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_DECREMENT_BASE;
+ }
+ }
+
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[pNode->nIntegerData2 + CVIRTUALMACHINE_EXTRA_DATA_LOCATION + 3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ return 0;
+ }
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_POST_INCREMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_POST_DECREMENT)
+ {
+ if (pNode->pLeft != NULL)
+ {
+ if (pNode->pLeft->nType != CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_OPERAND_MUST_BE_AN_INTEGER_LVALUE,pNode);
+ }
+
+ // Is pNode->pLeft actually a valid LValue?
+ if (pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_VARIABLE &&
+ pNode->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_OPERAND_MUST_BE_AN_INTEGER_LVALUE,pNode->pLeft);
+ }
+
+ pNode->nType = pNode->pLeft->nType;
+
+ // Current location of the variable is stored in pNode->pLeft->nIntegerData because
+ // it is a valid LValue.
+
+ int32_t nStackElementsDown = pNode->pLeft->nIntegerData - m_nStackCurrentDepth * 4;
+
+ int32_t bOperateOnStackPointer = TRUE;
+ if (pNode->pLeft->nIntegerData < m_nGlobalVariableSize && m_bGlobalVariableDefinition == FALSE)
+ {
+ bOperateOnStackPointer = FALSE;
+ nStackElementsDown = pNode->pLeft->nIntegerData - (m_nGlobalVariableSize);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_POST_INCREMENT)
+ {
+ if (bOperateOnStackPointer == TRUE)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_INCREMENT;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_INCREMENT_BASE;
+ }
+ }
+ else
+ {
+ if (bOperateOnStackPointer == TRUE)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_DECREMENT;
+ }
+ else
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_DECREMENT_BASE;
+ }
+ }
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION] = (char) (((nStackElementsDown) >> 24) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+1] = (char) (((nStackElementsDown) >> 16) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+2] = (char) (((nStackElementsDown) >> 8) & 0x0ff);
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_EXTRA_DATA_LOCATION+3] = (char) (((nStackElementsDown)) & 0x0ff);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ return 0;
+ }
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER,pNode);
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CASE)
+ {
+
+ return 0;
+ }
+
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_DEFAULT)
+ {
+ // Generate a label for the jump caused by the switch
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_SC_DEFAULT_%08x",m_nSwitchIdentifier); */
+ AddSymbolToLabelList(m_nOutputCodeLength, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_SWITCH_DEFAULT,m_nSwitchIdentifier,0);
+
+ if (m_nSwitchStackDepth + 1 != m_nStackCurrentDepth)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_JUMPING_OVER_DECLARATION_STATEMENTS_DEFAULT_DISALLOWED,pNode);
+ }
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_BREAK)
+ {
+ // CODE GENERATION
+ // Add the "JMP _BR_nIdentifierBreak" operation, where nIdentifierBreak
+ // represents the innermost for/while/dowhile/case statement!
+
+ // Compute the location of the innermost loop that we are allowed
+ // to break out of.
+
+ int32_t nIdentifierBreak;
+
+ // MGB - December 6, 2004 - START FIX
+ // The line below fixes a bug where a
+ // do/while loop is immediately followed by a switch statement;
+ // both the loop and the switch will be equal, causing the break
+ // in the switch to jump out of the do loop. This is a bad thing.
+ // The if used to simply be greater than (>). Note that this fix
+ // is safe because only do/while loops emit no code before they
+ // execute interior code. switch statements always emit code if they
+ // are the "outer" function, so it is safe to assign equality always
+ // to the switch statement.
+
+ if (m_nSwitchIdentifier >= m_nLoopIdentifier)
+ {
+ nIdentifierBreak = m_nSwitchIdentifier;
+ }
+ else
+ {
+ nIdentifierBreak = m_nLoopIdentifier;
+ }
+
+ // MGB - December 6, 2004 - END FIX
+
+ if (nIdentifierBreak == 0)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_BREAK_OUTSIDE_OF_LOOP_OR_CASE_STATEMENT,pNode);
+ }
+
+ // MGB - October 15, 2002 - Start Change
+ // End-User reported bug: break/continue do not modify stack properly.
+ // We must ditch any/all stack values that weren't there at the start of the loop ...
+ // MGB - December 8, 2004 - FIX Attempt 2.
+ if (nIdentifierBreak != m_nSwitchIdentifier)
+ {
+ if (m_nLoopStackDepth != m_nStackCurrentDepth)
+ {
+ int32_t nStackChange = (m_nLoopStackDepth - m_nStackCurrentDepth) * 4;
+ EmitModifyStackPointer(nStackChange);
+ }
+ }
+ // MGB - November 8, 2002 - Start Change
+ // Apparently, we forgot to deal with break statements in case statements as well!
+ // MGB - December 8, 2004 - FIX Attempt 2.
+ else
+ {
+ if ((m_nSwitchStackDepth + 1) != m_nStackCurrentDepth)
+ {
+ int32_t nStackChange = ((m_nSwitchStackDepth + 1) - m_nStackCurrentDepth) * 4;
+ EmitModifyStackPointer(nStackChange);
+ }
+ }
+ // MGB - November 8, 2002 - End Change
+ // MGB - October 15, 2002 - End Change
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_BR_%08x",nIdentifierBreak); */
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_BREAK,nIdentifierBreak,0);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONTINUE)
+ {
+ // MGB - October 15, 2002 - Start Change
+ // End-User reported bug: break/continue do not modify stack properly.
+ // We must ditch any/all stack values that weren't there at the start of the loop ...
+ if (m_nLoopStackDepth != m_nStackCurrentDepth)
+ {
+ int32_t nStackChange = (m_nLoopStackDepth - m_nStackCurrentDepth) * 4;
+ EmitModifyStackPointer(nStackChange);
+ }
+ // MGB - October 15, 2002 - End Change
+
+ // CODE GENERATION
+ // Add the "JMP _CN_nLoopIdentifier" operation.
+
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_JMP;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = 0;
+
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_CN_%08x",m_nLoopIdentifier); */
+ AddSymbolToQueryList(m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_CONTINUE,m_nLoopIdentifier,0);
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + 4;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_CONTINUE)
+ {
+ // Generate a label for the continue keyword.for a while loop.
+ /* CExoString sSymbolName;
+ sSymbolName.Format("_CN_%08x",m_nLoopIdentifier); */
+ AddSymbolToLabelList(m_nOutputCodeLength, CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_CONTINUE, m_nLoopIdentifier, 0);
+ return 0;
+ }
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_CONST_DECLARATION)
+ {
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_CONST_KEYWORD_CANNOT_BE_USED_ON_NON_GLOBAL_VARIABLES,pNode);
+ }
+
+ // Finally, if we've gone through *all* of these checks, we should abort immediately, because
+ // it's not in the list of operations that I understand.
+
+ return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_OPERATION_IN_SEMANTIC_CHECK,pNode);
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::FoundReturnStatementOnAllBranches()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/24/2000
+//
+// This routine attempts to determine whether there is a RETURN statement on
+// all control paths. Note that it will only follow if/else choices.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::FoundReturnStatementOnAllBranches(CScriptParseTreeNode *pNode)
+{
+
+ // Clearly, if the NODE is NULL, then we don't need to
+ if (pNode == NULL)
+ {
+ return FALSE;
+ }
+
+ // Here, we want to verify that BOTH paths have a RETURN statement
+ // before letting people know that both sides of it are protected.
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_RETURN)
+ {
+ return TRUE;
+ }
+
+ // Here, we want to verify that BOTH paths have a RETURN statement
+ // before letting people know that both sides of it are protected.
+
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_CHOICE)
+ {
+ if (FoundReturnStatementOnAllBranches(pNode->pLeft) == TRUE)
+ {
+ if (FoundReturnStatementOnAllBranches(pNode->pRight) == TRUE)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ // We want to pass through these functions, and if either side reports that
+ // they have a RETURN statement in them, that's good enough for me.
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST ||
+ pNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK)
+ {
+ if (FoundReturnStatementOnAllBranches(pNode->pLeft) == TRUE)
+ {
+ return TRUE;
+ }
+
+ if (FoundReturnStatementOnAllBranches(pNode->pRight) == TRUE)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ // We don't want to scan through any other part of the tree, so we
+ // should return FALSE here.
+
+ return FALSE;
+
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GetStructureSize()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/21/2000
+// Description: This routine will get a field from a strucutre, based on the
+// name of the structure and the field.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::GetStructureSize(const CExoString &sStructureName)
+{
+
+ int32_t count;
+
+ for (count = 0; count < m_nMaxStructures; count++)
+ {
+ if (sStructureName == m_pcStructList[count].m_psName)
+ {
+ return m_pcStructList[count].m_nByteSize;
+ }
+ }
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GetIdentifierByName()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/25/2000
+// Description: This routine will get the information on an identifier, based
+// on the name of the identifier.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::GetIdentifierByName(const CExoString &sIdentifierName)
+{
+ BOOL bInfiniteLoop = TRUE;
+ uint32_t nOriginalHash = HashString(sIdentifierName);
+
+ // Search for the exact entry.
+ uint32_t nHash = nOriginalHash % CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE;
+ uint32_t nEndHash = nHash + (CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE - 1) & CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+
+ while (bInfiniteLoop)
+ {
+ // If we're at the correct entry, confirm that the strings are identical and then
+ // return to the main routine.
+ if (m_pIdentifierHashTable[nHash].m_nHashValue == nOriginalHash &&
+ m_pIdentifierHashTable[nHash].m_nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER)
+ {
+ int32_t count = m_pIdentifierHashTable[nHash].m_nIdentifierIndex;
+ if (m_pcIdentifierList[count].m_psIdentifier == sIdentifierName)
+ {
+ return count;
+ }
+ }
+
+ // Have we hit a blank entry? Then it's not in the list.
+ if (m_pIdentifierHashTable[nHash].m_nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_UNKNOWN)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ }
+
+ // Have we searched the entire list?
+ if (nEndHash == nHash)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ }
+
+ // Move to the next entry in the list.
+ ++nHash;
+ nHash &= CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE;
+
+ }
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GetStructureField()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/20/2000
+// Description: This routine will get a field from a strucutre, based on the
+// name of the structure and the field.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::GetStructureField(const CExoString &sStructureName, const CExoString &sFieldName)
+{
+
+ int32_t count, count2;
+
+ for (count = 0; count < m_nMaxStructures; count++)
+ {
+ if (sStructureName == m_pcStructList[count].m_psName)
+ {
+ for (count2 = m_pcStructList[count].m_nFieldStart; count2 <= m_pcStructList[count].m_nFieldEnd; count2++)
+ {
+ if (sFieldName == m_pcStructFieldList[count2].m_psVarName)
+ {
+ return count2;
+ }
+ }
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_FIELD_IN_STRUCTURE;
+ }
+ }
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_STRUCTURE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::AddVariableToStack()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/22/2000
+// Description: This routine will add a variable to the run-time stack
+// based on the type (handing off to AddStructureToStack if
+// it is too complicated for me to handle).
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::AddVariableToStack(int32_t nVariableType, CExoString *psVariableTypeName, BOOL bGenerateCode)
+{
+ if (nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ (nVariableType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ nVariableType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9))
+ {
+
+ int32_t nAuxCodeType = 0;
+
+ if (nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ }
+ else if (nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+ }
+ else if (nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_STRING;
+ }
+ else if (nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_OBJECT;
+ }
+ else if (nVariableType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ nVariableType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST0 + (nVariableType - CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0);
+ }
+
+ m_pchStackTypes[m_nStackCurrentDepth] = (char) nAuxCodeType;
+ ++m_nStackCurrentDepth;
+
+ if (bGenerateCode == TRUE)
+ {
+ // CODE GENERATION
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_ADD;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = (char) nAuxCodeType;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+ }
+ else if (nVariableType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ // Function to recursively do all structures within the structure on the stack.
+ AddStructureToStack(*psVariableTypeName, bGenerateCode);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::AddStructureToStack()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/22/2000
+// Description: This routine will add the strucutre to the run-time stack,
+// based on the name of the structure.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::AddStructureToStack(const CExoString &sStructureName, BOOL bGenerateCode)
+{
+ int32_t count, count2;
+
+ for (count = 0; count < m_nMaxStructures; count++)
+ {
+ if (sStructureName == m_pcStructList[count].m_psName)
+ {
+ for (count2 = m_pcStructList[count].m_nFieldStart; count2 <= m_pcStructList[count].m_nFieldEnd; count2++)
+ {
+ int32_t nFieldType = m_pcStructFieldList[count2].m_pchType;
+
+ if (nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ (nFieldType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ nFieldType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9))
+ {
+
+ int32_t nAuxCodeType = 0;
+
+ if (nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER;
+ }
+ else if (nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT;
+ }
+ else if (nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_STRING;
+ }
+ else if (nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_OBJECT;
+ }
+ else if (nFieldType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ nFieldType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ nAuxCodeType = CVIRTUALMACHINE_AUXCODE_TYPE_ENGST0 + (nFieldType - CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0);
+ }
+
+ m_pchStackTypes[m_nStackCurrentDepth] = (char) nAuxCodeType;
+ ++m_nStackCurrentDepth;
+
+ // CODE GENERATION
+ if (bGenerateCode == TRUE)
+ {
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = CVIRTUALMACHINE_OPCODE_RUNSTACK_ADD;
+ m_pchOutputCode[m_nOutputCodeLength+CVIRTUALMACHINE_AUXCODE_LOCATION] = (char) nAuxCodeType;
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ }
+ }
+ else if (nFieldType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ // Function to recursively do all structures within the structure on the stack.
+ AddStructureToStack(m_pcStructFieldList[count2].m_psStructureName, bGenerateCode);
+ }
+
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GetFunctionNameFromSymbolSubTypes()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Nov. 21, 2002
+// Description: A utility function to return a function name from the symbol
+// subtypes you've passed in.
+///////////////////////////////////////////////////////////////////////////////
+CExoString CScriptCompiler::GetFunctionNameFromSymbolSubTypes(int32_t nSubType1,int32_t nSubType2)
+{
+ CExoString sNewFunctionName;
+
+ if (nSubType1 == 0 &&
+ nSubType2 != 0)
+ {
+ // Starting functions, need to be handled with kid gloves.
+ if (nSubType2 == 2)
+ {
+ if (m_bCompileConditionalFile == 0)
+ {
+ sNewFunctionName = "main";
+ }
+ else
+ {
+ sNewFunctionName = "StartingConditional";
+ }
+ }
+ else
+ {
+ sNewFunctionName = "#globals";
+ }
+
+ }
+ else if (nSubType1 != 0 &&
+ nSubType2 == 0)
+ {
+ // These can be looked up on the Occupied Identifiers list.
+ uint32_t nNewFunctionIdentifier = nSubType1;
+ sNewFunctionName = m_pcIdentifierList[nNewFunctionIdentifier].m_psIdentifier;
+ }
+ else
+ {
+ // Sorry, dude ... this shouldn't have happened under any circumstance.
+ sNewFunctionName = "";
+ }
+
+ return sNewFunctionName;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::AddSymbolToLabelList()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/22/2000
+// Description: Adds information to the symbol label list for examination at
+// a later date.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::AddSymbolToLabelList(int32_t nLocationPointer, int32_t nSymbolType, int32_t nSymbolSubType1, int32_t nSymbolSubType2)
+{
+ if (m_nSymbolLabelListSize == m_nSymbolLabelList)
+ {
+ CScriptCompilerSymbolTableEntry *m_pNewLabelList;
+
+ // Create a new list.
+
+ m_nSymbolLabelListSize += 8192;
+ m_pNewLabelList = new CScriptCompilerSymbolTableEntry[m_nSymbolLabelListSize];
+
+ if (m_pSymbolLabelList != NULL)
+ {
+ for (int32_t count = 0; count < m_nSymbolLabelList; ++count)
+ {
+ m_pNewLabelList[count].m_nSymbolType = m_pSymbolLabelList[count].m_nSymbolType;
+ m_pNewLabelList[count].m_nSymbolSubType1 = m_pSymbolLabelList[count].m_nSymbolSubType1;
+ m_pNewLabelList[count].m_nSymbolSubType2 = m_pSymbolLabelList[count].m_nSymbolSubType2;
+ m_pNewLabelList[count].m_nLocationPointer = m_pSymbolLabelList[count].m_nLocationPointer;
+ m_pNewLabelList[count].m_nNextEntryPointer = m_pSymbolLabelList[count].m_nNextEntryPointer;
+ }
+ delete[] m_pSymbolLabelList;
+ }
+ m_pSymbolLabelList = m_pNewLabelList;
+ }
+
+ m_pSymbolLabelList[m_nSymbolLabelList].m_nSymbolType = nSymbolType;
+ m_pSymbolLabelList[m_nSymbolLabelList].m_nSymbolSubType1 = nSymbolSubType1;
+ m_pSymbolLabelList[m_nSymbolLabelList].m_nSymbolSubType2 = nSymbolSubType2;
+ m_pSymbolLabelList[m_nSymbolLabelList].m_nLocationPointer = nLocationPointer;
+ m_pSymbolLabelList[m_nSymbolLabelList].m_nNextEntryPointer = -1;
+
+ uint32_t nLabelHash = (nSymbolSubType1 & 0x01ff);
+ if (m_pSymbolLabelStartEntry[nLabelHash] == -1)
+ {
+ // First entry in list.
+ m_pSymbolLabelStartEntry[nLabelHash] = m_nSymbolLabelList;
+ }
+ else
+ {
+ // Chain the new entry to the tail of the list ...
+ int32_t nCurrentPtr = m_pSymbolLabelStartEntry[nLabelHash];
+ while (m_pSymbolLabelList[nCurrentPtr].m_nNextEntryPointer != -1)
+ {
+ nCurrentPtr = m_pSymbolLabelList[nCurrentPtr].m_nNextEntryPointer;
+ }
+ m_pSymbolLabelList[nCurrentPtr].m_nNextEntryPointer = m_nSymbolLabelList;
+ }
+
+ // Advance the symbol label list pointer.
+ ++m_nSymbolLabelList;
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::AddSymbolToQueryList()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/22/2000
+// Description: Adds information to the symbol query list for examination at
+// a later date.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::AddSymbolToQueryList(int32_t nLocationPointer, int32_t nSymbolType, int32_t nSymbolSubType1, int32_t nSymbolSubType2)
+{
+ if (m_nSymbolQueryListSize == m_nSymbolQueryList)
+ {
+ CScriptCompilerSymbolTableEntry *m_pNewQueryList;
+
+ // Create a new list.
+
+ m_nSymbolQueryListSize += 8192;
+ m_pNewQueryList = new CScriptCompilerSymbolTableEntry[m_nSymbolQueryListSize];
+
+ if (m_pSymbolQueryList != NULL)
+ {
+ for (int32_t count = 0; count < m_nSymbolQueryList; ++count)
+ {
+ m_pNewQueryList[count].m_nSymbolType = m_pSymbolQueryList[count].m_nSymbolType;
+ m_pNewQueryList[count].m_nSymbolSubType1 = m_pSymbolQueryList[count].m_nSymbolSubType1;
+ m_pNewQueryList[count].m_nSymbolSubType2 = m_pSymbolQueryList[count].m_nSymbolSubType2;
+ m_pNewQueryList[count].m_nLocationPointer = m_pSymbolQueryList[count].m_nLocationPointer;
+ m_pNewQueryList[count].m_nNextEntryPointer = m_pSymbolQueryList[count].m_nNextEntryPointer;
+ }
+ delete[] m_pSymbolQueryList;
+ }
+ m_pSymbolQueryList = m_pNewQueryList;
+ }
+
+ m_pSymbolQueryList[m_nSymbolQueryList].m_nSymbolType = nSymbolType;
+ m_pSymbolQueryList[m_nSymbolQueryList].m_nSymbolSubType1 = nSymbolSubType1;
+ m_pSymbolQueryList[m_nSymbolQueryList].m_nSymbolSubType2 = nSymbolSubType2;
+ m_pSymbolQueryList[m_nSymbolQueryList].m_nLocationPointer = nLocationPointer;
+ // m_nNextEntryPointer is not valid for query list.
+ ++m_nSymbolQueryList;
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::WalkParseTree()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: This routine will walk the compile tree, generating a postfix
+// listing of the nodes (if necessary).
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::WalkParseTree(CScriptParseTreeNode *pNode)
+{
+ if (pNode != NULL)
+ {
+ //INT bPrinted = 0;
+
+
+ int nReturnCode;
+
+ ConstantFoldNode(pNode);
+ nReturnCode = PreVisitGenerateCode(pNode);
+
+ if (nReturnCode == 0)
+ {
+ nReturnCode = WalkParseTree(pNode->pLeft);
+ }
+
+ if (nReturnCode == 0)
+ {
+ ConstantFoldNode(pNode);
+ nReturnCode = InVisitGenerateCode(pNode);
+ }
+
+ if (nReturnCode == 0)
+ {
+ nReturnCode = WalkParseTree(pNode->pRight);
+ }
+
+ if (nReturnCode == 0)
+ {
+ ConstantFoldNode(pNode);
+ nReturnCode = PostVisitGenerateCode(pNode);
+ }
+
+ if (nReturnCode > 0)
+ {
+ nReturnCode = 0;
+ }
+
+ // Oh, dear. If there is not enough room, we should probably grow the
+ // output buffer by a bit!
+ // [36628] We make this check AFTER the data has been written without
+ // boundary checks. 200 bytes was not enough to protect from buffer
+ // overflows, raising to 16K. -virusman 2018/04/13
+ if (nReturnCode == 0 && m_nOutputCodeLength >= m_nOutputCodeSize - 16384)
+ {
+ m_nOutputCodeSize += CSCRIPTCOMPILER_MAX_CODE_SIZE;
+ char *pNewArray = new char[m_nOutputCodeSize];
+ memcpy(pNewArray,m_pchOutputCode,m_nOutputCodeLength);
+ delete[] m_pchOutputCode;
+ m_pchOutputCode = pNewArray;
+ // return OutputWalkTreeError(STRREF_CSCRIPTCOMPILER_ERROR_SCRIPT_TOO_LARGE,pNode);
+ }
+
+ return nReturnCode;
+ }
+
+ // A Null pointer is not an error.
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::StartLineNumberAtBinaryInstruction()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: August 29, 2002
+// Description: This routine will attempt to deal with line number
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::StartLineNumberAtBinaryInstruction(int32_t nFileReference, int32_t nLineNumber, int32_t nBinaryInstruction)
+{
+ if (m_nCurrentLineNumber != nLineNumber ||
+ m_nCurrentLineNumberFileReference != nFileReference)
+ {
+ m_nCurrentLineNumber = nLineNumber;
+ m_nCurrentLineNumberFileReference = nFileReference;
+ m_nCurrentLineNumberReferences = 1;
+ m_nCurrentLineNumberBinaryStartInstruction = nBinaryInstruction;
+ }
+ else
+ {
+ m_nCurrentLineNumberReferences += 1;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::EndLineNumberAtBinaryInstruction()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: August 29, 2002
+// Description: This routine will attempt to deal with line number
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::EndLineNumberAtBinaryInstruction(int32_t nFileReference, int32_t nLineNumber, int32_t nBinaryInstruction)
+{
+ // If we've received an end of line for something that we haven't started,
+ // this is a bug, so let's not write anything into the table.
+ if (m_nCurrentLineNumber != nLineNumber ||
+ m_nCurrentLineNumberFileReference != nFileReference)
+ {
+ m_nCurrentLineNumber = -1;
+ m_nCurrentLineNumberFileReference = -1;
+ m_nCurrentLineNumberReferences = 0;
+ return;
+ }
+
+ // If you have had multiple references for the same line, just subtract
+ // one of them away.
+ if (m_nCurrentLineNumberReferences > 1)
+ {
+ m_nCurrentLineNumberReferences -= 1;
+ return;
+ }
+
+ // We're at the last reference for a line, so we can write the information
+ // into the table.
+
+ // Fetch the file name reference.
+ CExoString *psCurrentLineNumberFileName = m_ppsParseTreeFileNames[m_nCurrentLineNumberFileReference];
+
+ int32_t nFileNameReference = -1;
+ for (int32_t nCount=0; nFileNameReference == -1 && nCount < m_nTableFileNames; ++nCount)
+ {
+ if (strcmp(m_psTableFileNames[nCount].CStr(),psCurrentLineNumberFileName->CStr()) == 0)
+ {
+ nFileNameReference = nCount;
+ }
+ }
+
+ if (nFileNameReference == -1)
+ {
+ if (m_nTableFileNames >= CSCRIPTCOMPILER_MAX_TABLE_FILENAMES)
+ {
+ return;
+ }
+ m_psTableFileNames[m_nTableFileNames] = *psCurrentLineNumberFileName;
+ nFileNameReference = m_nTableFileNames;
+ ++m_nTableFileNames;
+ }
+
+ if (m_pnTableInstructionFileReference.size() == m_nLineNumberEntries)
+ {
+ int32_t nSize = m_pnTableInstructionFileReference.size() * 2;
+ if (nSize <= 16)
+ {
+ nSize = 16;
+ }
+
+ m_pnTableInstructionFileReference.resize(nSize);
+ m_pnTableInstructionLineNumber.resize(nSize);
+ m_pnTableInstructionBinaryStart.resize(nSize);
+ m_pnTableInstructionBinaryEnd.resize(nSize);
+ m_pnTableInstructionBinaryFinal.resize(nSize);
+ m_pnTableInstructionBinarySortedOrder.resize(nSize);
+
+ }
+
+ // Write all of the information for this line into the table.
+ m_pnTableInstructionFileReference[m_nLineNumberEntries] = nFileNameReference;
+ m_pnTableInstructionLineNumber[m_nLineNumberEntries] = nLineNumber;
+ m_pnTableInstructionBinaryStart[m_nLineNumberEntries] = m_nCurrentLineNumberBinaryStartInstruction;
+ m_pnTableInstructionBinaryEnd[m_nLineNumberEntries] = nBinaryInstruction;
+ m_pnTableInstructionBinaryFinal[m_nLineNumberEntries] = FALSE;
+ m_pnTableInstructionBinarySortedOrder[m_nLineNumberEntries] = -1;
+
+ m_nLineNumberEntries++;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::AddToSymbolTableVarStack()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: August 21, 2002
+// Description: This routine will add an occupied variable to the symbol
+// table.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::AddToSymbolTableVarStack(int32_t nOccupiedVariables, int32_t nStackCurrentDepth, int32_t nGlobalVariableSize)
+{
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ if (m_pnSymbolTableVarType.size() == m_nSymbolTableVariables)
+ {
+ int32_t nSize = m_pnSymbolTableVarType.size() * 2;
+ if (nSize <= 16)
+ {
+ nSize = 16;
+ }
+
+ m_pnSymbolTableVarType.resize(nSize);
+ m_psSymbolTableVarName.resize(nSize);
+ m_psSymbolTableVarStructureName.resize(nSize);
+ m_pnSymbolTableVarStackLoc.resize(nSize);
+ m_pnSymbolTableVarBegin.resize(nSize);
+ m_pnSymbolTableVarEnd.resize(nSize);
+ m_pnSymbolTableBinaryFinal.resize(nSize);
+ m_pnSymbolTableBinarySortedOrder.resize(nSize);
+ }
+
+ m_pnSymbolTableVarType[m_nSymbolTableVariables] = m_pcVarStackList[nOccupiedVariables].m_nVarType;
+ m_psSymbolTableVarName[m_nSymbolTableVariables] = m_pcVarStackList[nOccupiedVariables].m_psVarName;
+ if (m_pcVarStackList[nOccupiedVariables].m_nVarType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_psSymbolTableVarStructureName[m_nSymbolTableVariables] = (m_pcVarStackList[nOccupiedVariables].m_sVarStructureName);
+ }
+ m_pnSymbolTableVarStackLoc[m_nSymbolTableVariables] = nStackCurrentDepth * 4 - nGlobalVariableSize;
+ m_pnSymbolTableVarBegin[m_nSymbolTableVariables] = m_nOutputCodeLength;
+ m_pnSymbolTableVarEnd[m_nSymbolTableVariables] = -1;
+ m_pnSymbolTableBinaryFinal[m_nSymbolTableVariables] = FALSE;
+ m_pnSymbolTableBinarySortedOrder[m_nSymbolTableVariables] = -1;
+ m_nSymbolTableVariables += 1;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::RemoveFromSymbolTableVarStack()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: August 21, 2002
+// Description: This routine will add an occupied variable to the symbol
+// table.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::RemoveFromSymbolTableVarStack(int32_t nOccupiedVariables, int32_t nStackCurrentDepth, int32_t nGlobalVariableSize)
+{
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+
+ int32_t nVarCount = m_nSymbolTableVariables - 1;
+ while (nVarCount >= 0)
+ {
+ BOOL bMatch = TRUE;
+ if (m_pnSymbolTableVarType[nVarCount] != m_pcVarStackList[nOccupiedVariables].m_nVarType)
+ {
+ bMatch = FALSE;
+ }
+ if (bMatch == TRUE &&
+ m_psSymbolTableVarName[nVarCount] != m_pcVarStackList[nOccupiedVariables].m_psVarName)
+ {
+ bMatch = FALSE;
+ }
+ if (bMatch == TRUE &&
+ m_pnSymbolTableVarStackLoc[nVarCount] != nStackCurrentDepth * 4 - nGlobalVariableSize)
+ {
+ bMatch = FALSE;
+ }
+
+ if (bMatch == TRUE &&
+ m_pcVarStackList[nOccupiedVariables].m_nVarType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT &&
+ m_psSymbolTableVarStructureName[nVarCount] != (m_pcVarStackList[nOccupiedVariables].m_sVarStructureName))
+ {
+ bMatch = FALSE;
+ }
+
+ if (bMatch == TRUE && m_pnSymbolTableVarEnd[nVarCount] == -1)
+ {
+ m_pnSymbolTableVarEnd[nVarCount] = m_nOutputCodeLength;
+ return;
+ }
+
+ --nVarCount;
+ }
+
+ /////////////////////////////////////////////////////////////////
+ //
+ // Once we get past this point, we are actually deleting an entry
+ // that we haven't found in the list ... this is usually a bad
+ // thing. However, to cover over the problem, we're just going
+ // to add an additional entry.
+ //
+ /////////////////////////////////////////////////////////////////
+
+ if (m_pnSymbolTableVarType.size() == m_nSymbolTableVariables)
+ {
+ int32_t nSize = m_pnSymbolTableVarType.size() * 2;
+ if (nSize <= 16)
+ {
+ nSize = 16;
+ }
+
+ m_pnSymbolTableVarType.resize(nSize);
+ m_psSymbolTableVarName.resize(nSize);
+ m_psSymbolTableVarStructureName.resize(nSize);
+ m_pnSymbolTableVarStackLoc.resize(nSize);
+ m_pnSymbolTableVarBegin.resize(nSize);
+ m_pnSymbolTableVarEnd.resize(nSize);
+ m_pnSymbolTableBinaryFinal.resize(nSize);
+ m_pnSymbolTableBinarySortedOrder.resize(nSize);
+ }
+
+ m_pnSymbolTableVarType[m_nSymbolTableVariables] = m_pcVarStackList[nOccupiedVariables].m_nVarType;
+ m_psSymbolTableVarName[m_nSymbolTableVariables] = m_pcVarStackList[nOccupiedVariables].m_psVarName;
+ if (m_pcVarStackList[nOccupiedVariables].m_nVarType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_psSymbolTableVarStructureName[m_nSymbolTableVariables] = (m_pcVarStackList[nOccupiedVariables].m_sVarStructureName);
+ }
+ m_pnSymbolTableVarStackLoc[m_nSymbolTableVariables] = nStackCurrentDepth * 4 - nGlobalVariableSize;
+ m_pnSymbolTableVarBegin[m_nSymbolTableVariables] = -1;
+ m_pnSymbolTableVarEnd[m_nSymbolTableVariables] = m_nOutputCodeLength;
+ m_pnSymbolTableBinaryFinal[m_nSymbolTableVariables] = FALSE;
+ m_pnSymbolTableBinarySortedOrder[m_nSymbolTableVariables] = -1;
+ m_nSymbolTableVariables += 1;
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ResolveDebuggingInformation()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: August 29, 2002
+// Description: This routine will take the binary source locations for
+// line numbers and variables stored in the .ndb and moves
+// them to their correct final location.
+///////////////////////////////////////////////////////////////////////////////
+void CScriptCompiler::ResolveDebuggingInformation()
+{
+ // m_nFinalLineNumberEntries contains the number of entries that
+ // will eventually be written into the file. Only those entries
+ // where m_pnTableInstructionBinaryFinal[] == TRUE will be included
+ // in this total.
+ m_nFinalLineNumberEntries = 0;
+
+ {
+ int32_t nCurrentBinarySize = CVIRTUALMACHINE_BINARY_SCRIPT_HEADER;
+ while (nCurrentBinarySize < m_nFinalBinarySize)
+ {
+ BOOL bFoundIdentifier = FALSE;
+ int32_t nCount2 = m_nMaxPredefinedIdentifierId;
+ while (bFoundIdentifier == FALSE && nCount2 <= m_nOccupiedIdentifiers)
+ {
+ if (nCurrentBinarySize == m_pcIdentifierList[nCount2].m_nBinaryDestinationStart)
+ {
+ ResolveDebuggingInformationForIdentifier(nCount2);
+ nCurrentBinarySize = m_pcIdentifierList[nCount2].m_nBinaryDestinationFinish;
+ bFoundIdentifier = TRUE;
+ }
+ nCount2++;
+ }
+
+ if (bFoundIdentifier == FALSE)
+ {
+ // This is bad, since we have a discontinuity
+ // in the binary functions.
+ nCurrentBinarySize = m_nFinalBinarySize;
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ResolveDebuggingInformationForIdentifier()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: August 29, 2002
+// Description: The routine that actually resolves line numbers and
+// variables on a per-identifier (function) basis.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::ResolveDebuggingInformationForIdentifier(int32_t nIdentifier)
+{
+ int32_t nCount;
+
+ // Loop through all of the line number pairs that we have accumulated.
+ for (nCount = 0; nCount < m_nLineNumberEntries; nCount++)
+ {
+
+ // Has the entry been resolved?
+ if (m_pnTableInstructionBinaryFinal[nCount] == FALSE)
+ {
+ // Resolve the location of where we will be writing the address
+ // for the start of the line number we're lookin' for.
+ int32_t nLineBinaryInstructionStart = m_pnTableInstructionBinaryStart[nCount];
+
+ if (nLineBinaryInstructionStart >= m_pcIdentifierList[nIdentifier].m_nBinarySourceStart &&
+ nLineBinaryInstructionStart < m_pcIdentifierList[nIdentifier].m_nBinarySourceFinish)
+ {
+ // Now, check to see if the query even BELONGS in the final file.
+ // (The function may not be reachable through a call to main(),
+ // so we don't need to store information about it!)
+ //
+ // If it does belong in the final file, generate its change in
+ // location and let it be "printed" to the file.
+ if (m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart != -1)
+ {
+ int32_t nBinaryLocationChange = (m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart -
+ m_pcIdentifierList[nIdentifier].m_nBinarySourceStart);
+
+ m_pnTableInstructionBinaryStart[nCount] += nBinaryLocationChange;
+ m_pnTableInstructionBinaryEnd[nCount] += nBinaryLocationChange;
+ m_pnTableInstructionBinaryFinal[nCount] = TRUE;
+ m_pnTableInstructionBinarySortedOrder[m_nFinalLineNumberEntries] = nCount;
+ m_nFinalLineNumberEntries += 1;
+ }
+ }
+ }
+ }
+
+ // Loop through all of the symbol table entries we have accumulated.
+ for (nCount = 0; nCount < m_nSymbolTableVariables; nCount++)
+ {
+ // Has the entry been resolved?
+ if (m_pnSymbolTableBinaryFinal[nCount] == FALSE)
+ {
+ int32_t nInstruction = m_pnSymbolTableVarBegin[nCount];
+ if (nInstruction == -1)
+ {
+ nInstruction = m_pnSymbolTableVarEnd[nCount];
+ }
+
+ if (nInstruction >= m_pcIdentifierList[nIdentifier].m_nBinarySourceStart &&
+ nInstruction < m_pcIdentifierList[nIdentifier].m_nBinarySourceFinish)
+ {
+ if (m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart != -1)
+ {
+ int32_t nBinaryLocationChange = (m_pcIdentifierList[nIdentifier].m_nBinaryDestinationStart -
+ m_pcIdentifierList[nIdentifier].m_nBinarySourceStart);
+
+ if (m_pnSymbolTableVarBegin[nCount] != -1)
+ {
+ m_pnSymbolTableVarBegin[nCount] += nBinaryLocationChange;
+ }
+
+ if (m_pnSymbolTableVarEnd[nCount] != -1)
+ {
+ m_pnSymbolTableVarEnd[nCount] += nBinaryLocationChange;
+ }
+
+ m_pnSymbolTableBinaryFinal[nCount] = TRUE;
+ m_pnSymbolTableBinarySortedOrder[m_nFinalSymbolTableVariables] = nCount;
+ m_nFinalSymbolTableVariables += 1;
+ }
+ }
+ }
+ }
+}
+
+CExoString CScriptCompiler::GenerateDebuggerTypeAbbreviation(int32_t nType, CExoString sStructureName)
+{
+ CExoString sReturnValue = "?";
+
+ if (nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID ||
+ nType == CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER)
+ {
+ sReturnValue = "v";
+ }
+ else if (nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ nType == CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER)
+ {
+ sReturnValue = "f";
+ }
+ else if (nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ nType == CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER)
+ {
+ sReturnValue = "i";
+ }
+ else if (nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ nType == CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER)
+ {
+ sReturnValue = "o";
+ }
+ else if (nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ nType == CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER)
+ {
+ sReturnValue = "s";
+ }
+ else if ((nType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ nType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9) ||
+ (nType >= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER &&
+ nType <= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER))
+ {
+ if (nType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ nType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ sReturnValue.Format("e%01d",nType - CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0);
+ }
+ else
+ {
+ sReturnValue.Format("e%01d",nType - CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER);
+ }
+ }
+ else if (nType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT ||
+ nType == CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER)
+ {
+ for (int32_t count = 0; count < m_nMaxStructures; count++)
+ {
+ if (m_pcStructList[count].m_psName == sStructureName)
+ {
+ sReturnValue.Format("t%04d",count);
+ }
+ }
+ }
+
+ return sReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::WriteOutDebuggerOutput()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: September 3, 2002
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::WriteDebuggerOutputToFile(CExoString sFileName)
+{
+ if (m_nGenerateDebuggerOutput != 0)
+ {
+ if (m_pchDebuggerCode == NULL)
+ {
+ m_nDebuggerCodeSize = CSCRIPTCOMPILER_MAX_DEBUG_OUTPUT_SIZE;
+ m_pchDebuggerCode = new char[m_nDebuggerCodeSize];
+ }
+
+ if (m_pchDebuggerCode == NULL)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNABLE_TO_OPEN_FILE_FOR_WRITING;
+ }
+
+ // MGB - February 14, 2003
+ // Evaluate the size of the debugger output. If the debugger output is larger
+ // than the buffer, we should increase the size of the buffer by a bit (double it!)
+
+ {
+ int32_t nMaxSize = 9 + 40; // NDB Header + Section sizes.
+ int32_t nMaxTypeNameSize = 5;
+ int32_t count;
+ for (count = 0; count < m_nTableFileNames; count++)
+ {
+ nMaxSize += m_psTableFileNames[count].GetLength() + 5;
+ }
+ for (count = 0; count < m_nMaxStructures; count++)
+ {
+ nMaxSize += m_pcStructList[count].m_psName.GetLength() + 6;
+ int32_t countField;
+ for (countField = m_pcStructList[count].m_nFieldStart; countField <= m_pcStructList[count].m_nFieldEnd; countField++)
+ {
+ // sTypeName can be at most size 5.
+ nMaxSize += nMaxTypeNameSize + m_pcStructFieldList[countField].m_psVarName.GetLength() + 5;
+ }
+ }
+ for (count = m_nMaxPredefinedIdentifierId; count < m_nOccupiedIdentifiers; count++)
+ {
+ nMaxSize += nMaxTypeNameSize + m_pcIdentifierList[count].m_psIdentifier.GetLength() + 26;
+ int32_t countParams;
+ for (countParams = 0; countParams < m_pcIdentifierList[count].m_nParameters; countParams++)
+ {
+ nMaxSize += nMaxTypeNameSize + 4;
+ }
+ }
+ for (count = 0; count < m_nFinalSymbolTableVariables; count++)
+ {
+ int32_t nSTEntry = m_pnSymbolTableBinarySortedOrder[count];
+ if (m_pnSymbolTableBinaryFinal[nSTEntry] == TRUE)
+ {
+ nMaxSize += nMaxTypeNameSize + m_psSymbolTableVarName[nSTEntry].GetLength() + 31;
+ }
+ }
+ for (count = 0; count < m_nFinalLineNumberEntries; count++)
+ {
+ int32_t nLNEntry = m_pnTableInstructionBinarySortedOrder[count];
+ if (m_pnTableInstructionBinaryFinal[nLNEntry] == TRUE)
+ {
+ nMaxSize += 30;
+ }
+ }
+
+ if (nMaxSize >= m_nDebuggerCodeSize)
+ {
+ if (nMaxSize < m_nDebuggerCodeSize * 2)
+ {
+ m_nDebuggerCodeSize *= 2;
+ }
+ else
+ {
+ m_nDebuggerCodeSize = nMaxSize * 2;
+ }
+
+ delete[] m_pchDebuggerCode;
+ m_pchDebuggerCode = new char[m_nDebuggerCodeSize];
+
+ if (m_pchDebuggerCode == NULL)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNABLE_TO_OPEN_FILE_FOR_WRITING;
+ }
+ }
+ }
+
+
+ sprintf(m_pchDebuggerCode,"NDB V1.0\n");
+ m_nDebuggerCodeLength = 9;
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"%07d %07d %07d %07d %07d\n",
+ m_nTableFileNames, m_nMaxStructures,
+ m_nOccupiedIdentifiers - m_nMaxPredefinedIdentifierId,
+ m_nFinalSymbolTableVariables,m_nFinalLineNumberEntries);
+ m_nDebuggerCodeLength += 40;
+
+ int32_t count;
+
+ for (count = 0; count < m_nTableFileNames; count++)
+ {
+ if (m_psTableFileNames[count] == sFileName)
+ {
+ // Capital F indicates the base file.
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"N%02d %s\n",count,m_psTableFileNames[count].CStr());
+ }
+ else
+ {
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"n%02d %s\n",count,m_psTableFileNames[count].CStr());
+ }
+ m_nDebuggerCodeLength += m_psTableFileNames[count].GetLength() + 5;
+ }
+
+ for (count = 0; count < m_nMaxStructures; count++)
+ {
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"s %02d %s\n",
+ (m_pcStructList[count].m_nFieldEnd - m_pcStructList[count].m_nFieldStart + 1),
+ m_pcStructList[count].m_psName.CStr());
+ m_nDebuggerCodeLength += m_pcStructList[count].m_psName.GetLength() + 6;
+
+ int32_t countField;
+ for (countField = m_pcStructList[count].m_nFieldStart; countField <= m_pcStructList[count].m_nFieldEnd; countField++)
+ {
+ CExoString sTypeName = GenerateDebuggerTypeAbbreviation(m_pcStructFieldList[countField].m_pchType,m_pcStructFieldList[countField].m_psStructureName);
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"sf %s %s\n",
+ sTypeName.CStr(), m_pcStructFieldList[countField].m_psVarName.CStr());
+ m_nDebuggerCodeLength += sTypeName.GetLength() + m_pcStructFieldList[countField].m_psVarName.GetLength() + 5;
+ }
+ }
+
+ for (count = m_nMaxPredefinedIdentifierId; count < m_nOccupiedIdentifiers; count++)
+ {
+ CExoString sTypeName = GenerateDebuggerTypeAbbreviation(m_pcIdentifierList[count].m_nReturnType,m_pcIdentifierList[count].m_psStructureReturnName);
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"f %08x %08x %03d %s %s\n",
+ m_pcIdentifierList[count].m_nBinaryDestinationStart,
+ m_pcIdentifierList[count].m_nBinaryDestinationFinish,
+ m_pcIdentifierList[count].m_nParameters,
+ sTypeName.CStr(), m_pcIdentifierList[count].m_psIdentifier.CStr());
+ m_nDebuggerCodeLength += sTypeName.GetLength() + m_pcIdentifierList[count].m_psIdentifier.GetLength() + 26;
+
+ int32_t countParams;
+ for (countParams = 0; countParams < m_pcIdentifierList[count].m_nParameters; countParams++)
+ {
+ CExoString sTypeName = (GenerateDebuggerTypeAbbreviation(m_pcIdentifierList[count].m_pchParameters[countParams],
+ m_pcIdentifierList[count].m_psStructureParameterNames[countParams]));
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"fp %s\n",sTypeName.CStr());
+ m_nDebuggerCodeLength += sTypeName.GetLength() + 4;
+ }
+ }
+
+ for (count = 0; count < m_nFinalSymbolTableVariables; count++)
+ {
+ int32_t nSTEntry = m_pnSymbolTableBinarySortedOrder[count];
+ if (m_pnSymbolTableBinaryFinal[nSTEntry] == TRUE)
+ {
+ CExoString sTypeName = GenerateDebuggerTypeAbbreviation(m_pnSymbolTableVarType[nSTEntry],
+ m_psSymbolTableVarStructureName[nSTEntry]);
+
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"v %08x %08x %08x %s %s\n",
+ m_pnSymbolTableVarBegin[nSTEntry],
+ m_pnSymbolTableVarEnd[nSTEntry],
+ m_pnSymbolTableVarStackLoc[nSTEntry],
+ sTypeName.CStr(), m_psSymbolTableVarName[nSTEntry].CStr());
+ m_nDebuggerCodeLength += sTypeName.GetLength() + m_psSymbolTableVarName[nSTEntry].GetLength() + 31;
+ }
+ }
+
+ for (count = 0; count < m_nFinalLineNumberEntries; count++)
+ {
+ int32_t nLNEntry = m_pnTableInstructionBinarySortedOrder[count];
+ if (m_pnTableInstructionBinaryFinal[nLNEntry] == TRUE)
+ {
+ sprintf(m_pchDebuggerCode + m_nDebuggerCodeLength,"l%02d %07d %08x %08x\n",
+ m_pnTableInstructionFileReference[nLNEntry],m_pnTableInstructionLineNumber[nLNEntry],
+ m_pnTableInstructionBinaryStart[nLNEntry],m_pnTableInstructionBinaryEnd[nLNEntry]);
+ m_nDebuggerCodeLength += 30;
+ }
+ }
+
+ // Now that the debugger information has been written into a buffer,
+ // we can write it out in one operation to disk!
+ CExoString sModifiedFileName;
+ sModifiedFileName.Format("%s:%s",m_sOutputAlias.CStr(),sFileName.CStr());
+
+ const int32_t ret = m_cAPI.ResManWriteToFile(
+ sModifiedFileName.CStr(), m_nResTypeDebug,
+ (const uint8_t*) m_pchDebuggerCode, m_nDebuggerCodeLength, false);
+
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ if (m_bAutomaticCleanUpAfterCompiles == TRUE)
+ {
+ CExoString sDirectoryFileName;
+
+ sDirectoryFileName.Format("%s:",m_sOutputAlias.CStr());
+ m_cAPI.ResManUpdateResourceDirectory(sDirectoryFileName.CStr());
+
+ // Delete the Debugger code buffer
+ delete[] m_pchDebuggerCode;
+ m_pchDebuggerCode = NULL;
+ m_nDebuggerCodeSize = 0;
+ }
+
+ // This must always happen.
+ m_nDebuggerCodeLength = 0;
+ }
+ return 0;
+}
+
+char *CScriptCompiler::InstructionLookback(uint32_t last)
+{
+ if (last == 0 || last > m_aOutputCodeInstructionBoundaries.size())
+ return NULL;
+
+ return &m_pchOutputCode[m_aOutputCodeInstructionBoundaries[m_aOutputCodeInstructionBoundaries.size() - 1 - last]];
+}
+
+void CScriptCompiler::WriteByteSwap32(char *buffer, int32_t value)
+{
+ buffer[0] = (char)((value >> 24) & 0xff);
+ buffer[1] = (char)((value >> 16) & 0xff);
+ buffer[2] = (char)((value >> 8) & 0xff);
+ buffer[3] = (char)((value) & 0xff);
+}
+int32_t CScriptCompiler::ReadByteSwap32(char *buffer)
+{
+ return ((int32_t)buffer[0] << 24) | ((int32_t)buffer[1] << 16) | ((int32_t)buffer[2] << 8) | (int32_t)buffer[3];
+}
+
+char *CScriptCompiler::EmitInstruction(uint8_t nOpCode, uint8_t nAuxCode, int32_t nDataSize)
+{
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_OPCODE_LOCATION] = nOpCode;
+ m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_AUXCODE_LOCATION] = nAuxCode;
+
+ char *ret = &m_pchOutputCode[m_nOutputCodeLength + CVIRTUALMACHINE_EXTRA_DATA_LOCATION];
+
+ m_nOutputCodeLength += CVIRTUALMACHINE_OPERATION_BASE_SIZE + nDataSize;
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+
+ return ret;
+}
+
+void CScriptCompiler::EmitModifyStackPointer(int32_t nModifyBy)
+{
+ if (m_nOptimizationFlags & CSCRIPTCOMPILER_OPTIMIZE_MELD_INSTRUCTIONS)
+ {
+ char *last = InstructionLookback(1);
+
+ // Temporarily disabled. Compiler is generating dead MOVSP instructions
+ // in some cases when returning from a function, and merging a live one
+ // with a dead one causes issues, unsurprisingly.
+#if 0
+ // Multiple MODIFY_STACK_POINTER instructions can always be merged into a single one
+ if (last[CVIRTUALMACHINE_OPCODE_LOCATION] == CVIRTUALMACHINE_OPCODE_MODIFY_STACK_POINTER)
+ {
+ int32_t mod = ReadByteSwap32(&last[CVIRTUALMACHINE_EXTRA_DATA_LOCATION]);
+ mod += nModifyBy;
+ WriteByteSwap32(&last[CVIRTUALMACHINE_EXTRA_DATA_LOCATION], mod);
+ return;
+ }
+#endif
+ // The nwscript construct `int n = 3;` gets compiled into the following:
+ // RUNSTACK_ADD, TYPE_INTEGER
+ // CONSTANT, TYPE_INTEGER, 3
+ // ASSIGNMENT, TYPE_VOID, -8, 4
+ // MODIFY_STACK_POINTER, -4
+ // This ends up with just the CONSTI 3 on the top of stack, but the
+ // dance is necessary as `n = 3` is also an expression which returns 3.
+ // Then, the last MODSP discards the result of the expression.
+ // Here, we detect the pattern when it is discarded, and replace the
+ // whole set of instructions with just CONSTI 3
+ if (last[CVIRTUALMACHINE_OPCODE_LOCATION] == CVIRTUALMACHINE_OPCODE_ASSIGNMENT)
+ {
+ char *instConstant = InstructionLookback(2);
+ char *instRunstackAdd = InstructionLookback(3);
+
+ if (instConstant && instConstant[CVIRTUALMACHINE_OPCODE_LOCATION] == CVIRTUALMACHINE_OPCODE_CONSTANT &&
+ instRunstackAdd && instRunstackAdd[CVIRTUALMACHINE_OPCODE_LOCATION] == CVIRTUALMACHINE_OPCODE_RUNSTACK_ADD &&
+ instConstant[CVIRTUALMACHINE_AUXCODE_LOCATION] == instRunstackAdd[CVIRTUALMACHINE_AUXCODE_LOCATION] &&
+ ReadByteSwap32(&last[CVIRTUALMACHINE_EXTRA_DATA_LOCATION]) == -8
+ )
+ {
+ // Move the CONST instruction up to where runstack add is..
+ const int32_t instConstantSize = (last - instConstant);
+ memmove(instRunstackAdd, instConstant, instConstantSize);
+ // Roll back output code length to where the old instConstant started..
+ m_nOutputCodeLength = (instRunstackAdd - m_pchOutputCode) + instConstantSize;
+ // Pop the last two instruction boundaries (CONSTANT, ASSIGNMENT) since those don't exist anymore
+ m_aOutputCodeInstructionBoundaries.pop_back();
+ m_aOutputCodeInstructionBoundaries.pop_back();
+ m_aOutputCodeInstructionBoundaries.pop_back();
+ m_aOutputCodeInstructionBoundaries.push_back(m_nOutputCodeLength);
+ return;
+ }
+ }
+ }
+
+ char *buf = EmitInstruction(CVIRTUALMACHINE_OPCODE_MODIFY_STACK_POINTER, 0, 4);
+ WriteByteSwap32(buf, nModifyBy);
+}
diff --git a/src/Native Compiler/scriptcompidentspec.cpp b/src/Native Compiler/scriptcompidentspec.cpp
new file mode 100644
index 0000000..e1e9d95
--- /dev/null
+++ b/src/Native Compiler/scriptcompidentspec.cpp
@@ -0,0 +1,907 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Script Project
+//::
+//:: Copyright (c) 2002, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ScriptCompIdentSpec.cpp
+//::
+//:: Implementation of parsing the identifier specification file.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: October 8, 2002
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: This file contains "ported" code (used when writing out floating point
+//:: numbers on the MacIntosh platforms).
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+// external header files
+#include "exobase.h"
+#include "scriptcomp.h"
+
+// internal header files
+#include "scriptinternal.h"
+
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Class CScriptCompiler
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GenerateIdentifierList()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/24/99
+// Description: Takes the output from the lexical analysis to generate a
+// list of indentifiers.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::GenerateIdentifierList()
+{
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE1 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE3 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE4 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE5 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE6 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE8 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9 ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_START_OF_LINE)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_AFTER_TYPE_DECLARATION;
+ m_nIdentifierListReturnType = m_nTokenStatus;
+ return 0;
+ }
+ else if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST)
+ {
+ // Use the keywords to add the parameter into the list.
+
+ int32_t nValue = m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_nParameters;
+
+ if (nValue == m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_nParameterSpace)
+ {
+ int nReturnValue = m_pcIdentifierList[m_nOccupiedIdentifiers-1].ExpandParameterSpace();
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ }
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_pchParameters[nValue] = (char) m_nTokenStatus;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_pchParameters[nValue] = (char) CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_psStructureParameterNames[nValue] = "vector";
+ }
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_pbOptionalParameters[nValue] = FALSE;
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_nParameters = nValue+1;
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFINE)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_START_OF_LINE)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_DEFINE_STATEMENT;
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_NUM_STRUCTURES_DEFINITION)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_DEFINE_STATEMENT)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_DEFINE_NUM_ENGINE_STRUCTURE;
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_DEFINE_STATEMENT)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_DEFINE_SINGLE_ENGINE_STRUCTURE;
+ m_nIdentifierListEngineStructure = (int32_t) (m_pchToken[17] - '0');
+
+ if (m_nIdentifierListEngineStructure < 0 || m_nIdentifierListEngineStructure >= 10)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_AFTER_FUNCTION_IDENTIFIER)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER;
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_nIdentifierType = 0;
+ return 0;
+ }
+ else if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT;
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VARIABLE)
+ {
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_DEFINE_SINGLE_ENGINE_STRUCTURE)
+ {
+ m_pbEngineDefinedStructureValid[m_nIdentifierListEngineStructure] = TRUE;
+ m_pchToken[m_nTokenCharacters] = 0;
+ (m_psEngineDefinedStructureName[m_nIdentifierListEngineStructure]).Format("%s",(char *) m_pchToken);
+
+ HashManagerAdd(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_ENGINE_STRUCTURE, m_nIdentifierListEngineStructure);
+
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_START_OF_LINE;
+ return 0;
+ }
+
+ // There are many identifiers in the list, the only one we
+ // want to deal with is the name of the function. The names
+ // of the parameters are irrelevant (hence, the transfer from
+ // state 1 to state 2.
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_AFTER_TYPE_DECLARATION)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_AFTER_FUNCTION_IDENTIFIER;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierType = 1;
+
+ if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE1)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE1_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE2_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE3)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE3_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE4)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE4_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE5)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE5_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE6)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE6_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE7_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE8)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE8_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER;
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStructureReturnName = "vector";
+ }
+ else if (m_nIdentifierListReturnType == CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ // Copy the token name, MINUS the return type, into the code.
+ m_pchToken[m_nTokenCharacters] = 0;
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psIdentifier).Format("%s",(char *) m_pchToken);
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierHash) = HashString(m_pcIdentifierList[m_nOccupiedIdentifiers].m_psIdentifier);
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierLength = m_nTokenCharacters;
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceStart = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceFinish = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationStart = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationFinish = -1;
+ HashManagerAdd(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER, m_nOccupiedIdentifiers);
+
+ m_nOccupiedIdentifiers++;
+ if (m_nOccupiedIdentifiers >= CSCRIPTCOMPILER_MAX_IDENTIFIERS)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_IDENTIFIER_LIST_FULL;
+ return nError;
+ }
+
+ return 0;
+ }
+ else if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST)
+ {
+ return 0;
+ }
+
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ return nError;
+
+ }
+
+ // This one is tough. Bail at the end of the file.
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_EOF)
+ {
+ return 0;
+ }
+
+ // This one is *really* tough. We should signify that we should take
+ // the negative of the constant when we deal with the next token.
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_MINUS)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_nIntegerData = -1;
+ }
+ // We also store the data here if we are in a parameter list.
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers-1].m_nIntegerData = -1;
+ }
+ return 0;
+ }
+
+ int32_t nCount;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_DEFINE_NUM_ENGINE_STRUCTURE)
+ {
+ // Fetch the value.
+ int nValue = 0;
+ for (nCount = 0; nCount < m_nTokenCharacters; nCount++)
+ {
+ nValue = nValue * 10 + (m_pchToken[nCount] - '0');
+ }
+
+ if (nValue >= 10)
+ {
+ nValue = 10;
+ }
+
+ if (nValue < 0)
+ {
+ nValue = 1;
+ }
+
+ m_nNumEngineDefinedStructures = nValue;
+
+ if (m_pbEngineDefinedStructureValid)
+ {
+ delete[] m_pbEngineDefinedStructureValid;
+ }
+
+ m_pbEngineDefinedStructureValid = new BOOL[nValue];
+ for (int32_t cnt = 0; cnt < nValue; cnt++)
+ {
+ m_pbEngineDefinedStructureValid[cnt] = FALSE;
+ }
+
+ if (m_psEngineDefinedStructureName)
+ {
+ delete[] m_psEngineDefinedStructureName;
+ }
+ m_psEngineDefinedStructureName = new CExoString[nValue];
+
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_START_OF_LINE;
+ return 0;
+
+ }
+
+ if (m_bCompileIdentifierConstants == FALSE &&
+ m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ return 0;
+ }
+
+ int nLoc = m_nOccupiedIdentifiers - 1;
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER;
+
+ if(m_pcIdentifierList[nLoc].m_nReturnType!=CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER ||
+ m_pcIdentifierList[nLoc].m_nIdentifierType != 0)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_INTEGER_ID_FOR_INTEGER_CONSTANT;
+ return nError;
+ }
+ }
+ else if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ int nSign = 1;
+ if (m_pcIdentifierList[nLoc].m_nIntegerData == -1)
+ {
+ m_pcIdentifierList[nLoc].m_nIntegerData = 0;
+ nSign = -1;
+ }
+
+ int nValue = 0;
+
+ // MGB - June 3, 2002
+ // Most of the time, the minus sign has already been removed
+ // from the integer constant. However, if we specify a negative
+ // constant and THEN use it as a default parameter, it can sneak
+ // into this function via the back door. This is the ultimate
+ // final trap for it.
+ nCount = 0;
+ if (m_pchToken[nCount] == '-')
+ {
+ nSign *= -1;
+ ++nCount;
+ }
+
+ for (; nCount < m_nTokenCharacters; nCount++)
+ {
+ nValue = nValue * 10 + (m_pchToken[nCount] - '0');
+ }
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER)
+ {
+ m_pcIdentifierList[nLoc].m_nIntegerData = nSign * nValue;
+ m_pchToken[m_nTokenCharacters] = 0;
+
+ // MGB - September 14, 2001 - Negative constants will have to be stored
+ // into the string.
+ if (nSign == -1)
+ {
+ (m_pcIdentifierList[nLoc].m_psStringData).Format("-%s",m_pchToken);
+ }
+ else
+ {
+ (m_pcIdentifierList[nLoc].m_psStringData).Format("%s",m_pchToken);
+ }
+ }
+ else if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ m_pcIdentifierList[nLoc].m_pnOptionalParameterIntegerData[nLoc2] = nSign * nValue;
+ }
+
+ return 0;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT)
+ {
+ if (m_bCompileIdentifierConstants == FALSE && m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ return 0;
+ }
+
+ int nLoc = m_nOccupiedIdentifiers - 1;
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER;
+ if(m_pcIdentifierList[nLoc].m_nReturnType != CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER ||
+ m_pcIdentifierList[nLoc].m_nIdentifierType != 0)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_FLOAT_ID_FOR_FLOAT_CONSTANT;
+ return nError;
+ }
+ }
+ else if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_PARAMETER &&
+ m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_CONSTANT &&
+ m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ float fSign = 1.0f;
+ if (m_pcIdentifierList[nLoc].m_nIntegerData == -1)
+ {
+ m_pcIdentifierList[nLoc].m_nIntegerData = 0;
+ fSign = -1.0f;
+ }
+
+ float fValue = ParseFloatFromTokenString();
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER)
+ {
+ m_pcIdentifierList[nLoc].m_fFloatData = fSign * fValue;
+ m_pchToken[m_nTokenCharacters] = 0;
+
+ // MGB - September 14, 2001 - Negative constants will have to be stored
+ // into the string.
+ if (fSign < 0.0f)
+ {
+ (m_pcIdentifierList[nLoc].m_psStringData).Format("-%s",m_pchToken);
+ }
+ else
+ {
+ (m_pcIdentifierList[nLoc].m_psStringData).Format("%s",m_pchToken);
+ }
+ }
+ else if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ m_pcIdentifierList[nLoc].m_pfOptionalParameterFloatData[nLoc2] = fSign * fValue;
+ }
+ else if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_CONSTANT)
+ {
+ m_pcIdentifierList[nLoc].m_fVectorData[m_nIdentifierListVector] = fSign * fValue;
+ }
+ else if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_PARAMETER)
+ {
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ m_pcIdentifierList[nLoc].m_pfOptionalParameterVectorData[nLoc2 * 3 + m_nIdentifierListVector] = fSign * fValue;
+ }
+
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING)
+ {
+ if (m_bCompileIdentifierConstants == FALSE && m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ return 0;
+ }
+
+ int nLoc = m_nOccupiedIdentifiers - 1;
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER;
+
+ if(m_pcIdentifierList[nLoc].m_nReturnType != CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER ||
+ m_pcIdentifierList[nLoc].m_nIdentifierType != 0)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_STRING_ID_FOR_STRING_CONSTANT;
+ return nError;
+ }
+ }
+ else if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER)
+ {
+ m_pchToken[m_nTokenCharacters] = 0;
+ (m_pcIdentifierList[nLoc].m_psStringData).Format("%s",m_pchToken);
+ }
+ else if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ m_pchToken[m_nTokenCharacters] = 0;
+ (m_pcIdentifierList[nLoc].m_psOptionalParameterStringData[nLoc2]).Format("%s",m_pchToken);
+ }
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_SELF)
+ {
+ if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ int32_t nLoc = m_nOccupiedIdentifiers - 1;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ m_pcIdentifierList[nLoc].m_poidOptionalParameterObjectData[nLoc2] = (OBJECT_ID) 0;
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_INVALID)
+ {
+ if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ int32_t nLoc = m_nOccupiedIdentifiers - 1;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ m_pcIdentifierList[nLoc].m_poidOptionalParameterObjectData[nLoc2] = (OBJECT_ID) 1;
+ return 0;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_LOCATION_INVALID)
+ {
+ if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ int32_t nLoc = m_nOccupiedIdentifiers - 1;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ // LOCATION_INVALID is reusing the integer data field
+ m_pcIdentifierList[nLoc].m_pnOptionalParameterIntegerData[nLoc2] = 0;
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING)
+ {
+ if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT)
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ int32_t nLoc = m_nOccupiedIdentifiers - 1;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL)
+ m_pcIdentifierList[nLoc].m_psOptionalParameterStringData[nLoc2] = "null";
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE)
+ m_pcIdentifierList[nLoc].m_psOptionalParameterStringData[nLoc2] = "false";
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE)
+ m_pcIdentifierList[nLoc].m_psOptionalParameterStringData[nLoc2] = "true";
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT)
+ m_pcIdentifierList[nLoc].m_psOptionalParameterStringData[nLoc2] = "{}";
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY)
+ m_pcIdentifierList[nLoc].m_psOptionalParameterStringData[nLoc2] = "[]";
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING)
+ m_pcIdentifierList[nLoc].m_psOptionalParameterStringData[nLoc2] = "\"\"";
+ else
+ EXOASSERTNCSTR("missing impl");
+
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_SQUARE_BRACKET)
+ {
+ if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT &&
+ m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+ m_nIdentifierListVector = 0;
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_CONSTANT;
+ }
+ else
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_PARAMETER;
+ }
+
+ int32_t nLoc = m_nOccupiedIdentifiers - 1;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+ m_pcIdentifierList[nLoc].m_pbOptionalParameters[nLoc2] = TRUE;
+ for (int32_t nLoc3 = 0; nLoc3 < 3; nLoc3++)
+ {
+ m_pcIdentifierList[nLoc].m_pfOptionalParameterVectorData[nLoc2 * 3 + nLoc3] = (float) 0.0f;
+ }
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET)
+ {
+ if (m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_PARAMETER &&
+ m_nIdentifierListState != CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_CONSTANT)
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+ return nError;
+ }
+
+ m_nIdentifierListVector = 0;
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_PARAMETER)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ }
+ else
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER;
+ }
+
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ // Semicolon resets the state of the identifier list parsing.
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST)
+ {
+ int32_t nLoc = m_nOccupiedIdentifiers - 1;
+ int32_t nLoc2 = m_pcIdentifierList[nLoc].m_nParameters - 1;
+
+ m_pcIdentifierList[nLoc].m_nIdIdentifier = m_nPredefinedIdentifierOrder;
+ ++m_nPredefinedIdentifierOrder;
+ m_pcIdentifierList[nLoc].m_bImplementationInPlace = TRUE;
+
+
+ // Find the last non-optional parameter so that we know the size of the list
+ // of non-optional parameters!
+ m_pcIdentifierList[nLoc].m_nNonOptionalParameters = 0;
+ for (int32_t cnt = nLoc2; cnt >= 0 && m_pcIdentifierList[nLoc].m_nNonOptionalParameters == 0; cnt--)
+ {
+ if (m_pcIdentifierList[nLoc].m_pbOptionalParameters[cnt] == FALSE)
+ {
+ m_pcIdentifierList[nLoc].m_nNonOptionalParameters = cnt+1;
+ }
+ }
+
+ }
+ ++m_nMaxPredefinedIdentifierId;
+
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_START_OF_LINE;
+ return 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ if (m_nIdentifierListState == CSCRIPTCOMPILER_IDENT_STATE_AFTER_FUNCTION_IDENTIFIER)
+ {
+ m_nIdentifierListState = CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST;
+ return 0;
+ }
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA)
+ {
+ return 0;
+ }
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::PrintParseIdentifierFileError()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/24/99
+// Description: This routine will parse the identifier file.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::PrintParseIdentifierFileError(int32_t nParsingError)
+{
+ CExoString strRes = m_cAPI.TlkResolve(-nParsingError);
+
+ CExoString *psFileName = &(m_pcIncludeFileStack[0].m_sCompiledScriptName);
+ OutputError(nParsingError,psFileName,m_nLines,strRes);
+ m_pcIncludeFileStack[0].m_sSourceScript = "";
+ return STRREF_CSCRIPTCOMPILER_ERROR_ALREADY_PRINTED;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseIdentifierFile()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/24/99
+// Description: This routine will parse the identifier file.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseIdentifierFile()
+{
+
+ char *pScript;
+ uint32_t nScriptLength;
+ uint32_t i;
+ int32_t ch;
+ int32_t chNext;
+
+ int32_t nParseCharacterReturn;
+
+ // Initialize();
+
+ m_nPredefinedIdentifierOrder = 0;
+
+ const char* sTest = m_cAPI.ResManLoadScriptSourceFile(m_sLanguageSource.CStr(), m_nResTypeSource);
+ if (!sTest)
+ {
+ return PrintParseIdentifierFileError(STRREF_CSCRIPTCOMPILER_ERROR_FILE_NOT_FOUND);
+ }
+
+ m_pcIncludeFileStack[0].m_sSourceScript = sTest;
+ pScript = m_pcIncludeFileStack[0].m_sSourceScript.CStr();
+ nScriptLength = m_pcIncludeFileStack[0].m_sSourceScript.GetLength();
+
+ if ( nScriptLength < 1 )
+ {
+ ch = -1;
+ }
+ else
+ {
+ ch = pScript[0];
+ }
+
+ if ( nScriptLength < 2 )
+ {
+ chNext = -1;
+ }
+ else
+ {
+ chNext = pScript[1];
+ }
+
+ i = 2;
+
+ while (ch != -1)
+ {
+ nParseCharacterReturn = ParseNextCharacter(ch,chNext, pScript + i, nScriptLength - i);
+ if (nParseCharacterReturn < 0)
+ {
+ m_pcIncludeFileStack[0].m_sSourceScript = "";
+ return PrintParseIdentifierFileError(nParseCharacterReturn);
+ }
+
+ while (nParseCharacterReturn >= 0)
+ {
+ // Process the location of the next character.
+ if (ch == '\n')
+ {
+ ++m_nLines;
+ m_nCharacterOnLine = 1;
+ }
+ else
+ {
+ ++m_nCharacterOnLine;
+ }
+
+ // Fetch the "next" character and update the status
+ // of the current character that we are looking at.
+ ch = chNext;
+
+ if ( i >= nScriptLength )
+ {
+ chNext = -1;
+ }
+ else
+ {
+ chNext = (unsigned char) pScript[i];
+ }
+
+ --nParseCharacterReturn;
+
+ ++i;
+ }
+ }
+
+ nParseCharacterReturn = ParseNextCharacter(-1,-1, nullptr, 0);
+
+ m_pcIncludeFileStack[0].m_sSourceScript = "";
+
+ if (nParseCharacterReturn < 0)
+ {
+ return PrintParseIdentifierFileError(nParseCharacterReturn);
+ }
+
+ return 0;
+
+}
diff --git a/src/Native Compiler/scriptcomplexical.cpp b/src/Native Compiler/scriptcomplexical.cpp
new file mode 100644
index 0000000..23482f3
--- /dev/null
+++ b/src/Native Compiler/scriptcomplexical.cpp
@@ -0,0 +1,1774 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+ ///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Script Project
+//::
+//:: Copyright (c) 2002, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ScriptCompLexical.cpp
+//::
+//:: Implementation of parsing a stream of characters into tokens that can
+//:: either be handed to GenerateIdentifierFile() or GenerateParseTree().
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: Oct. 8, 2002
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: This file contains "ported" code (used when writing out floating point
+//:: numbers on the MacIntosh platforms).
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+// external header files
+#include "exobase.h"
+#include "scriptcomp.h"
+
+// internal header files
+#include "scriptinternal.h"
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Class CScriptCompiler
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseFloatFromTokenString()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 10/17/2000
+// Description: Parses a floating point number from the m_pchToken that has
+// been read in (i.e. a TOKEN_FLOAT).
+///////////////////////////////////////////////////////////////////////////////
+
+float CScriptCompiler::ParseFloatFromTokenString()
+{
+ float fReturnValue = 0.0f;
+ int32_t nMode = 0;
+ float fDecimalConstant = 1.0f;
+ float fSign = 1.0f;
+
+ for (int32_t nCount = 0; nCount < m_nTokenCharacters; nCount++)
+ {
+ if (m_pchToken[nCount] == '-' && nCount == 0)
+ {
+ fSign = -1.0f;
+ }
+
+ if (m_pchToken[nCount] >= '0' &&
+ m_pchToken[nCount] <= '9')
+ {
+ if (nMode == 0)
+ {
+ fReturnValue *= 10.0f;
+ fReturnValue += (m_pchToken[nCount] - '0');
+ }
+ if (nMode == 1)
+ {
+ fDecimalConstant /= 10.0f;
+ fReturnValue += ((m_pchToken[nCount] - '0') * fDecimalConstant);
+ }
+
+ }
+ if (m_pchToken[nCount] == '.')
+ {
+ nMode = 1;
+ }
+ }
+
+ // If the constant is negative, apply the sign to it.
+ if (fSign < 0.0f)
+ {
+ fReturnValue = fSign * fReturnValue;
+ }
+
+ return fReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterNumeric()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a numeric character for use by tokens
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterNumeric(int32_t ch)
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_INTEGER;
+ m_nTokenCharacters = 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_HEX_INTEGER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_IDENTIFIER)
+ {
+ m_pchToken[m_nTokenCharacters] = (char) ch;
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters > CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ return nError;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterPeriod()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a period for use by tokens
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterPeriod(int32_t chNext)
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ return nError;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_FLOAT;
+ m_pchToken[m_nTokenCharacters] = '.';
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_IDENTIFIER)
+ {
+ // Cut off the current identifier, and then pass the
+ // period in as a token!
+ int nReturnValue = HandleIdentifierToken();
+ if (nReturnValue >= 0)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_STRUCTURE_PART_SPECIFY;
+ nReturnValue = HandleToken();
+ }
+ return nReturnValue;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ // If our token starts with a dot, and next one is a digit, it's a float
+ // in the form of ".42", meaning 0.42
+ if (chNext >= '0' && chNext <= '9')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_FLOAT;
+ m_pchToken[m_nTokenCharacters++] = '0';
+ m_pchToken[m_nTokenCharacters++] = '.';
+ }
+ else // Otherwise, assume struct field
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_STRUCTURE_PART_SPECIFY;
+ return HandleToken();
+ }
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ return nError;
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterAlphabet()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a alphabetic character for use by tokens
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterAlphabet(int32_t ch)
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_IDENTIFIER;
+ m_nTokenCharacters = 0;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER && (ch == 'x' || ch == 'X') &&
+ m_nTokenCharacters == 1 && m_pchToken[0] == '0')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_HEX_INTEGER;
+ m_pchToken[m_nTokenCharacters] = (char) ch;
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_HEX_INTEGER &&
+ ((ch >= 'a' && ch <='f') ||
+ (ch >= 'A' && ch <='F')))
+ {
+ if (ch <= 'F')
+ {
+ m_pchToken[m_nTokenCharacters] = (char) (ch + 32);
+ }
+ else
+ {
+ m_pchToken[m_nTokenCharacters] = (char) ch;
+ }
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_IDENTIFIER || m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING)
+ {
+ m_pchToken[m_nTokenCharacters] = (char) ch;
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ return nError;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterSlash()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a slash for use by tokens
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterSlash(int32_t chNext)
+{
+ int32_t nReturnValue = 1;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '*')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_CCOMMENT;
+ nReturnValue = 1;
+ }
+ else if (chNext == '/')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_CPLUSCOMMENT;
+ nReturnValue = 1;
+ }
+ else if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_DIVIDE;
+ int32_t nReturnHandle = HandleToken();
+ if (nReturnHandle < 0)
+ {
+ return nReturnHandle;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_DIVIDE;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterAmpersand()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles an ampersand for use by tokens
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterAmpersand(int32_t chNext)
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '&')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_LOGICAL_AND;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ return 1;
+ }
+ else if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_AND;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ return 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_BOOLEAN_AND;
+ return HandleToken();
+ }
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ return nError;
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterVerticalBar()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a vertical bar for use by tokens
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterVerticalBar(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '|')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_LOGICAL_OR;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_OR;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_INCLUSIVE_OR;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterAsterisk()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles an asterisk for use by tokens
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterAsterisk(int32_t chNext)
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MULTIPLY;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ return 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_MULTIPLY;
+ return HandleToken();
+ }
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ return nError;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCommentedOutCharacter()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Determies whether or not the COMMENT token ends.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCommentedOutCharacter(int32_t ch)
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_CPLUSCOMMENT)
+ {
+ if (ch == '\n')
+ {
+
+#ifndef NWN
+ // For other projects, this is useful for keeping the scripting
+ // commands straight.
+ if (m_bCompileIdentifierList == TRUE)
+ {
+ if (m_nTokenCharacters >= 2 &&
+ m_pchToken[0] == '!')
+ {
+ m_pchToken[m_nTokenCharacters] = 0;
+ int32_t nProperFunctionIdentifier = atoi(m_pchToken + 1);
+
+ if (nProperFunctionIdentifier != m_nPredefinedIdentifierOrder)
+ {
+ BOOL bAlwaysFalse = FALSE;
+ EXOASSERTSTR(bAlwaysFalse,"Language Definition File Is Misordered!");
+ }
+ }
+ }
+#endif // !NWN
+
+ TokenInitialize();
+ }
+ else if (m_bCompileIdentifierList == TRUE)
+ {
+
+#ifndef NWN
+ m_pchToken[m_nTokenCharacters] = (char) ch;
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+#endif // !NWN
+
+ }
+
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_CCOMMENT)
+ {
+ // If the last character we have seen is an asterisk, then
+ // m_nTokenCharacters == 1. Only when we see ch == '/' and
+ // we see m_nTokenCharacters == 1 should we bother to unset
+ // CCOMMENT mode.
+
+ if (ch == '*')
+ {
+ if (m_nTokenCharacters == 0)
+ {
+ m_nTokenCharacters = 1;
+ }
+ }
+ else if (ch == '/')
+ {
+ if (m_nTokenCharacters == 1)
+ {
+ TokenInitialize();
+ }
+ }
+ else
+ {
+ m_nTokenCharacters = 0;
+ }
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseStringCharacter()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a character for a TOKEN_STRING token. Need to compile
+// stuff like \n into a single character (\n). Wow.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseStringCharacter(int32_t ch, int32_t chNext, char *pScript, int32_t nScriptLength)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING)
+ {
+ if (ch == '\n')
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNTERMINATED_STRING_CONSTANT;
+ }
+ else if (ch == '"')
+ {
+ return ParseCharacterQuotationMark();
+ }
+ else if (ch == '\\')
+ {
+ BOOL escapedChar = true;
+ // Handle the "\n" type characters in a string constant.
+ if (chNext == 'n')
+ {
+ m_pchToken[m_nTokenCharacters] = '\n';
+ }
+ else if (chNext == '\\')
+ {
+ m_pchToken[m_nTokenCharacters] = '\\';
+ }
+ else if (chNext == '"')
+ {
+ m_pchToken[m_nTokenCharacters] = '"';
+ }
+ else if (chNext == 'x')
+ {
+ // This is bit of a hack; but we can just grab the next characters from
+ // the source data and return what we ate.
+ if (nScriptLength < 2)
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNTERMINATED_STRING_CONSTANT;
+ const char hex[3] = { pScript[0], pScript[1], '\0'};
+ char* ptr = nullptr;
+ // can never be >byte, we only parse two bytes
+ m_pchToken[m_nTokenCharacters++] = (char) strtol(hex, &ptr, 16);
+ return 3; // eat "xXX"
+ }
+ else
+ {
+ escapedChar = false;
+ }
+
+ if (escapedChar)
+ {
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+ return 1;
+ }
+ }
+ else
+ {
+ m_pchToken[m_nTokenCharacters] = (char) ch;
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+
+ return 0;
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+
+ return nReturnValue;
+}
+
+int32_t CScriptCompiler::ParseRawStringCharacter(int32_t ch, int32_t chNext)
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RAW_STRING)
+ {
+ if (ch == '"')
+ {
+ if (chNext == '"')
+ {
+ // "" in a raw string means single "
+ m_pchToken[m_nTokenCharacters++] = '"';
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+ return 1; // consume 1 more
+ }
+
+ // Otherwise, terminate string literal.
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_STRING;
+ return HandleToken();
+ }
+
+ m_pchToken[m_nTokenCharacters++] = (char) ch;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ return STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+
+ return 0;
+ }
+
+ return STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterQuotationMark()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a quotation mark for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterQuotationMark()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_STRING;
+ m_nTokenCharacters = 0;
+ nReturnValue = 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING)
+ {
+ // Quotation Mark terminates the string.
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterHyphen()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a hyphen for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterHyphen(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MINUS;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else if (chNext == '-')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_DECREMENT;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_MINUS;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterLeftBrace()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a left brace for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterLeftBrace()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_LEFT_BRACE;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterRightBrace()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a right brace for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterRightBrace()
+{
+ int32_t nReturnValue = 0;
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterLeftBracket()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a left bracket for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterLeftBracket()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterRightBracket()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a right bracket for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterRightBracket()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterLeftSquareBracket()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 10/16/2000
+// Description: Compiles a left bracket for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterLeftSquareBracket()
+{
+ int32_t nReturnValue = 0;
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_LEFT_SQUARE_BRACKET;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterRightSquareBracket()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 10/16/2000
+// Description: Compiles a left bracket for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterRightSquareBracket()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterRightAngle()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a right angle for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterRightAngle(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ // Token is >=
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COND_GREATER_EQUAL;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else if (chNext == '>')
+ {
+ // Token is at least >> ... so keep going.
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_SHIFT_RIGHT;
+ nReturnValue = 0;
+ }
+ else
+ {
+ // Token is >
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COND_GREATER_THAN;
+ nReturnValue = HandleToken();
+ }
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SHIFT_RIGHT)
+ {
+
+ if (chNext == '>')
+ {
+ // Token is at least >>> ... so keep going.
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_UNSIGNED_SHIFT_RIGHT;
+ nReturnValue = 0;
+ }
+ else if (chNext == '=')
+ {
+ // Token is >>=
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_RIGHT;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ // Token is >>
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_SHIFT_RIGHT;
+ nReturnValue = HandleToken();
+ }
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNSIGNED_SHIFT_RIGHT)
+ {
+ if (chNext == '=')
+ {
+ // Token is >>>=
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_USHIFT_RIGHT;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ // Token is >>>
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_UNSIGNED_SHIFT_RIGHT;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterLeftAngle()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a left angle for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterLeftAngle(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COND_LESS_EQUAL;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else if (chNext == '<')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_SHIFT_LEFT;
+ return 0; // DO NOT REMOVE THE NEXT CHARACTER OR CALL HANDLETOKEN().
+ // That guarantees we visit the code later on in this function!
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COND_LESS_THAN;
+ nReturnValue = HandleToken();
+ }
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SHIFT_LEFT)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_LEFT;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_SHIFT_LEFT;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterExclamationPoint()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles an exclamation point for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterExclamationPoint(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COND_NOT_EQUAL;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_BOOLEAN_NOT;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterEqualSign()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles an equal sign for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterEqualSign(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COND_EQUAL;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterPlusSign()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles an plus sign for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterPlusSign(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_PLUS;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else if (chNext == '+')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_INCREMENT;
+ int nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_PLUS;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterPercentSign()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a percent sign for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterPercentSign(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MODULUS;
+ int32_t nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ nReturnValue = 1;
+ }
+ else
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_MODULUS;
+ nReturnValue = HandleToken();
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterSemicolon()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a semicolon for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterSemicolon()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_SEMICOLON;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterCarat()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a carat for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterCarat(int32_t chNext)
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ if (chNext == '=')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_XOR;
+ int32_t nHandleReturn = HandleToken();
+ if (nHandleReturn < 0)
+ {
+ return nHandleReturn;
+ }
+ return 1;
+ }
+
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_EXCLUSIVE_OR;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterTilde()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 08/13/99
+// Description: Compiles a tilde for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterTilde()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_TILDE;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterComma()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Compiles a comma for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterComma()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COMMA;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterEllipsis()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/14/2000
+// Description: Compiles an ellipsis for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterEllipsis()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_IDENTIFIER;
+ m_nTokenCharacters = 0;
+ m_pchToken[m_nTokenCharacters] = '#';
+ ++m_nTokenCharacters;
+ if (m_nTokenCharacters >= CSCRIPTCOMPILER_MAX_TOKEN_LENGTH)
+ {
+ nReturnValue = STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG;
+ }
+ else
+ {
+ nReturnValue = 0;
+ }
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterQuestionMark()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/23/2001
+// Description: Compiles a question mark for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterQuestionMark()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_QUESTION_MARK;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseCharacterColon()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/23/2001
+// Description: Compiles a colon for use by tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseCharacterColon()
+{
+ int32_t nReturnValue = 0;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNKNOWN)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_COLON;
+ nReturnValue = HandleToken();
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER;
+ nReturnValue = nError;
+ }
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::HandleToken()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Determines what to do with a "complete" token.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::HandleToken()
+{
+ // Do something with the token.
+ int32_t nReturnValue;
+
+ if (m_bCompileIdentifierList == TRUE)
+ {
+ nReturnValue = GenerateIdentifierList();
+ }
+ else
+ {
+ nReturnValue = GenerateParseTree();
+ }
+
+ if (m_nNextParseTreeFileName >= CSCRIPTCOMPILER_MAX_TABLE_FILENAMES)
+ {
+ nReturnValue = STRREF_CSCRIPTCOMPILER_ERROR_INCLUDE_TOO_MANY_LEVELS;
+ }
+
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+ TokenInitialize();
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::TestIdentifierToken()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/09/2001
+// Description: Tests the token and determines what the correct state for
+// the node is. (This was removed from HandleIdentifierToken()
+// because we need to make use of this during the handling
+// of global variable declarations).
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::TestIdentifierToken()
+{
+
+ char cTemp = m_pchToken[m_nTokenCharacters];
+ m_pchToken[m_nTokenCharacters] = 0;
+ int32_t nHashLocation = GetHashEntryByName(m_pchToken);
+ m_pchToken[m_nTokenCharacters] = cTemp;
+
+ if (nHashLocation == STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER)
+ {
+ if (m_pchToken[0] == '#')
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_ELLIPSIS_IN_IDENTIFIER;
+ return nError;
+ }
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_VARIABLE;
+ return 0;
+ }
+
+ int32_t nIdentifierType = m_pIdentifierHashTable[nHashLocation].m_nIdentifierType;
+ int32_t nIdentifierIndex = m_pIdentifierHashTable[nHashLocation].m_nIdentifierIndex;
+
+ if (nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER)
+ {
+ if (m_pcIdentifierList[nIdentifierIndex].m_nIdentifierType == 1)
+ {
+ // We just need to set the right type, based on the "return type" of
+ // the identifier, to allow the code to compile this properly.
+ m_nTokenStatus = m_pcIdentifierList[nIdentifierIndex].m_nReturnType;
+ }
+ else
+ {
+ if (m_pcIdentifierList[nIdentifierIndex].m_nReturnType == CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_INTEGER;
+ }
+ else if (m_pcIdentifierList[nIdentifierIndex].m_nReturnType == CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_FLOAT;
+ }
+ else if (m_pcIdentifierList[nIdentifierIndex].m_nReturnType == CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_STRING;
+ }
+ // Copy from the "defined" constant to m_pcIdentifierList
+ int32_t nSize = m_pcIdentifierList[nIdentifierIndex].m_psStringData.GetLength();
+ int32_t nCount2;
+ for (nCount2 = 0; nCount2 < nSize; nCount2++)
+ {
+ m_pchToken[nCount2] = ((m_pcIdentifierList[nIdentifierIndex].m_psStringData).CStr())[nCount2];
+ }
+ m_nTokenCharacters = nSize;
+ }
+ }
+ else if (nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_KEYWORD)
+ {
+ m_nTokenStatus = m_pcKeyWords[nIdentifierIndex].GetTokenToTranslate();
+ }
+ else // if (nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_ENGINE_STRUCTURE)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 + nIdentifierIndex;
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::HandleIdentifierToken()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Deals with identifier tokens.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::HandleIdentifierToken()
+{
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_IDENTIFIER)
+ {
+ int32_t nReturnValue = TestIdentifierToken();
+ if (nReturnValue != 0)
+ {
+ return nReturnValue;
+ }
+ }
+
+ return HandleToken();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseNextCharacter()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: With a "one-character look ahead" (chNext), determine what
+// type of token is expressed by the character in ch and the
+// character in chNext.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseNextCharacter(int32_t ch, int32_t chNext, char *pScript, int32_t nScriptLength)
+{
+
+ if (ch == -1)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_EOF;
+ int nHandleTokenReturn = HandleToken();
+ if (nHandleTokenReturn < 0)
+ {
+ return nHandleTokenReturn;
+ }
+ return 0;
+ }
+
+
+ // Deal with commented out code.
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_CPLUSCOMMENT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_CCOMMENT)
+ {
+ // Deal with next character.
+ return ParseCommentedOutCharacter(ch);
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING)
+ {
+ return ParseStringCharacter(ch,chNext, pScript, nScriptLength);
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RAW_STRING)
+ {
+ return ParseRawStringCharacter(ch, chNext);
+ }
+
+ if ((ch == 'r' || ch == 'R') && chNext == '"')
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_RAW_STRING;
+ m_nTokenCharacters = 0;
+ return 1; // consume r"
+ }
+
+ // Handle the tokens associated with integer and real numbers.
+ // Note that we terminate the current token if we are currently
+ // building an integer or a real number, and we've received a non
+ // numeric token. This is VERY important.
+
+ if (ch >= '0' && ch <= '9')
+ {
+ return ParseCharacterNumeric(ch);
+ }
+ else if (ch == '.')
+ {
+ return ParseCharacterPeriod(chNext);
+ }
+ else if ((ch == 'x' || ch == 'X') &&
+ m_nTokenCharacters == 1 &&
+ m_pchToken[0] == '0')
+ {
+ return ParseCharacterAlphabet(ch);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER || m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT)
+ {
+ int32_t nCompiledCharacters = 0;
+ // Compile all suffixes that make sense.
+ if (ch == 'f')
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER)
+ {
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_FLOAT;
+ }
+ nCompiledCharacters = 1;
+ }
+
+ int nReturnValue = HandleToken();
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ else if (nCompiledCharacters > 0)
+ {
+ return nCompiledCharacters - 1;
+ }
+ }
+
+ // For similar reasons, we deal with alphabetic characters and then
+ // we deal with the abrupt termination of a letter.
+
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')
+ {
+ return ParseCharacterAlphabet(ch);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_IDENTIFIER)
+ {
+ int nReturnValue = HandleIdentifierToken();
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_HEX_INTEGER)
+ {
+ int nReturnValue = HandleToken();
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ }
+
+ if (ch == '/')
+ {
+ return ParseCharacterSlash(chNext);
+ }
+ else if (ch == '*')
+ {
+ return ParseCharacterAsterisk(chNext);
+ }
+ else if (ch == '&')
+ {
+ return ParseCharacterAmpersand(chNext);
+ }
+ else if (ch == '|')
+ {
+ return ParseCharacterVerticalBar(chNext);
+ }
+
+ // Toss out blank space.
+ if (ch == ' ' || ch == '\n' || ch == '\t')
+ {
+ return 0;
+ }
+
+ if (ch == '"')
+ {
+ return ParseCharacterQuotationMark();
+ }
+ if (ch == '-')
+ {
+ return ParseCharacterHyphen(chNext);
+ }
+ if (ch == '{')
+ {
+ return ParseCharacterLeftBrace();
+ }
+ if (ch == '}')
+ {
+ return ParseCharacterRightBrace();
+ }
+ if (ch == '(')
+ {
+ return ParseCharacterLeftBracket();
+ }
+ if (ch == ')')
+ {
+ return ParseCharacterRightBracket();
+ }
+
+ if (ch == '[')
+ {
+ return ParseCharacterLeftSquareBracket();
+ }
+ if (ch == ']')
+ {
+ return ParseCharacterRightSquareBracket();
+ }
+
+ if (ch == '<')
+ {
+ return ParseCharacterLeftAngle(chNext);
+ }
+ if (ch == '>')
+ {
+ return ParseCharacterRightAngle(chNext);
+ }
+ if (ch == '!')
+ {
+ return ParseCharacterExclamationPoint(chNext);
+ }
+ if (ch == '=')
+ {
+ return ParseCharacterEqualSign(chNext);
+ }
+ if (ch == '+')
+ {
+ return ParseCharacterPlusSign(chNext);
+ }
+ if (ch == '%')
+ {
+ return ParseCharacterPercentSign(chNext);
+ }
+ if (ch == ';')
+ {
+ return ParseCharacterSemicolon();
+ }
+ if (ch == ',')
+ {
+ return ParseCharacterComma();
+ }
+ if (ch == '^')
+ {
+ return ParseCharacterCarat(chNext);
+ }
+ if (ch == '~')
+ {
+ return ParseCharacterTilde();
+ }
+ if (ch == '#')
+ {
+ return ParseCharacterEllipsis();
+ }
+ if (ch == '?')
+ {
+ return ParseCharacterQuestionMark();
+ }
+ if (ch == ':')
+ {
+ return ParseCharacterColon();
+ }
+
+ return 0;
+}
diff --git a/src/Native Compiler/scriptcompparsetree.cpp b/src/Native Compiler/scriptcompparsetree.cpp
new file mode 100644
index 0000000..3000e70
--- /dev/null
+++ b/src/Native Compiler/scriptcompparsetree.cpp
@@ -0,0 +1,4609 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Script Project
+//::
+//:: Copyright (c) 2002, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ScriptCompParseTree.cpp
+//::
+//:: Implementation of conversion from scripting language source to a parse
+//:: tree that we can use to generate final code. Because this includes the
+//:: lexical analysis of tokens, the code to parse the identifier file is
+//:: also included within this file.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: Oct. 8, 2002
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: This file contains "ported" code (used when writing out floating point
+//:: numbers on the MacIntosh platforms).
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+
+// external header files
+#include "exobase.h"
+#include "scriptcomp.h"
+
+// internal header files
+#include "scriptinternal.h"
+
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Class CScriptCompiler
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::TokenInitialize()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Sets up parsing routine to be ready to accept a new token.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::TokenInitialize()
+{
+ m_nTokenStatus = 0; // TOKEN_UNKNOWN;
+ m_nTokenCharacters = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::PushSRStack()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Code to place another context on to the Shift-Reduce stack.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::PushSRStack(int32_t nState, int32_t nRule, int32_t nTerm,
+ CScriptParseTreeNode *pCurrentTree)
+{
+ if (m_nSRStackStates+1 >= m_nSRStackEntries)
+ {
+ CScriptCompilerStackEntry *pNewSRStack = new CScriptCompilerStackEntry[m_nSRStackEntries * 2];
+ for (int nCount = 0; nCount < m_nSRStackEntries; nCount++)
+ {
+ pNewSRStack[nCount].nState = m_pSRStack[nCount].nState;
+ pNewSRStack[nCount].nRule = m_pSRStack[nCount].nRule;
+ pNewSRStack[nCount].nTerm = m_pSRStack[nCount].nTerm;
+ pNewSRStack[nCount].pCurrentTree = m_pSRStack[nCount].pCurrentTree;
+ pNewSRStack[nCount].pReturnTree = m_pSRStack[nCount].pReturnTree;
+ }
+ m_nSRStackEntries *= 2;
+ delete[] m_pSRStack;
+ m_pSRStack = pNewSRStack;
+ }
+
+ ++m_nSRStackStates;
+ m_pSRStack[m_nSRStackStates].nState = nState;
+ m_pSRStack[m_nSRStackStates].nRule = nRule;
+ m_pSRStack[m_nSRStackStates].nTerm = nTerm;
+ m_pSRStack[m_nSRStackStates].pCurrentTree = pCurrentTree;
+ m_pSRStack[m_nSRStackStates].pReturnTree = NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::PopSRStack()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Code to remove a context from the Shift-Reduce stack.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::PopSRStack(int32_t *nState, int32_t *nRule, int32_t *nTerm,
+ CScriptParseTreeNode **pCurrentTree,
+ CScriptParseTreeNode **pReturnTree )
+{
+
+ if (m_nSRStackStates < 0)
+ {
+ return FALSE;
+ }
+
+ *nState = m_pSRStack[m_nSRStackStates].nState;
+ *nRule = m_pSRStack[m_nSRStackStates].nRule;
+ *nTerm = m_pSRStack[m_nSRStackStates].nTerm;
+ *pCurrentTree = m_pSRStack[m_nSRStackStates].pCurrentTree;
+ *pReturnTree = m_pSRStack[m_nSRStackStates].pReturnTree;
+ --m_nSRStackStates;
+
+ return TRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ModifySRStackReturnTree()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: Code to hand a compile tree pointer to the next stack pointer
+// level.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::ModifySRStackReturnTree(
+ CScriptParseTreeNode *pReturnTree )
+{
+ if (m_nSRStackStates >= 0)
+ {
+ m_pSRStack[m_nSRStackStates].pReturnTree = pReturnTree;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GetNewScriptParseTreeNode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Nov. 22, 2002
+// Description: Wrapper to create a ScriptParseTreeNode from the blocks that
+// we have potentially already created
+///////////////////////////////////////////////////////////////////////////////
+CScriptParseTreeNode *CScriptCompiler::GetNewScriptParseTreeNode()
+{
+ CScriptParseTreeNode *pParseTreeNode;
+ // New Version
+
+ // If we are at the end of the linked list of node blocks, and we don't
+ // have any room left in this block (or the block doesn't exist!),
+ // we should create a new block to use.
+ if (m_nParseTreeNodeBlockEmptyNodes == -1 &&
+ (m_pCurrentParseTreeNodeBlock == NULL || m_pCurrentParseTreeNodeBlock->m_pNextBlock == NULL))
+ {
+ m_pCurrentParseTreeNodeBlock = new CScriptParseTreeNodeBlock;
+ m_nParseTreeNodeBlockEmptyNodes = CSCRIPTCOMPILER_PARSETREENODEBLOCK_SIZE - 1;
+
+ // Chain it on to the list of currently allocated blocks.
+ if (m_pParseTreeNodeBlockTail == NULL)
+ {
+ m_pParseTreeNodeBlockHead = m_pCurrentParseTreeNodeBlock;
+ m_pParseTreeNodeBlockTail = m_pCurrentParseTreeNodeBlock;
+ }
+ else
+ {
+ m_pParseTreeNodeBlockTail->m_pNextBlock = m_pCurrentParseTreeNodeBlock;
+ m_pParseTreeNodeBlockTail = m_pCurrentParseTreeNodeBlock;
+ }
+ }
+
+ // We are guaranteed that we have a block that exists with nodes in it
+ // or we have a block that is full that has a connected block that has
+ // nodes in it!
+
+ if (m_nParseTreeNodeBlockEmptyNodes >= 0)
+ {
+ // This block has spots in it ... so we do nothing but let it
+ // fall through and use the blank spot!
+ }
+ else
+ {
+ // So our current block doesn't have spots; that's fine ... the next
+ // one is guaranteed to have spots in it!
+ m_pCurrentParseTreeNodeBlock = m_pCurrentParseTreeNodeBlock->m_pNextBlock;
+ m_pCurrentParseTreeNodeBlock->CleanBlockEntries();
+ m_nParseTreeNodeBlockEmptyNodes = CSCRIPTCOMPILER_PARSETREENODEBLOCK_SIZE - 1;
+ }
+
+ // ... and finally, return the connected node!
+ pParseTreeNode = &(m_pCurrentParseTreeNodeBlock->m_pNodes[m_nParseTreeNodeBlockEmptyNodes]);
+ --m_nParseTreeNodeBlockEmptyNodes;
+
+ return pParseTreeNode;
+
+ // Old Version
+ //return new CScriptParseTreeNode();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::DeleteScriptParseTreeNode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: Nov. 22, 2002
+// Description: Wrapper to "deallocate" a CScriptParseTreeNode.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::DeleteScriptParseTreeNode(CScriptParseTreeNode *pParseTreeNode)
+{
+ // MGB - March 21, 2003 - Big bug in the handling of compiled scripts.
+ pParseTreeNode->Clean();
+ // MGB - March 21, 2003 - End Change.
+
+ // DO NOT DEALLOCATE MEMORY, FOR THE LOVE OF PETE. Let the blocks
+ // delete themselves.
+ pParseTreeNode = NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CreateScriptParseTreeNode()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/18/2001
+// Description: Wrapper to create a ScriptParseTreeNode quickly without
+// having to change the code in a hundred places.
+///////////////////////////////////////////////////////////////////////////////
+
+CScriptParseTreeNode *CScriptCompiler::CreateScriptParseTreeNode(
+ int32_t nNodeOperation,
+ CScriptParseTreeNode *pNodeLeft,
+ CScriptParseTreeNode *pNodeRight)
+{
+ CScriptParseTreeNode *pNewNode = GetNewScriptParseTreeNode();
+ pNewNode->nOperation = nNodeOperation;
+ pNewNode->pLeft = pNodeLeft;
+ pNewNode->pRight = pNodeRight;
+ pNewNode->nLine = m_nLines;
+ pNewNode->nChar = m_nCharacterOnLine;
+
+ if (m_nCompileFileLevel >= 1)
+ {
+ if (m_nNextParseTreeFileName != 0)
+ {
+ // Check the current entry.
+ if (m_nCurrentParseTreeFileName >= 0 &&
+ m_nCurrentParseTreeFileName < m_nNextParseTreeFileName)
+ {
+ if (*(m_ppsParseTreeFileNames[m_nCurrentParseTreeFileName]) == m_pcIncludeFileStack[m_nCompileFileLevel-1].m_sCompiledScriptName)
+ {
+ pNewNode->m_nFileReference = m_nCurrentParseTreeFileName;
+ return pNewNode;
+ }
+ }
+
+ // It's not the current entry, search through all defined values.
+ int32_t nCount;
+ for (nCount = 0; nCount < m_nNextParseTreeFileName; nCount++)
+ {
+ if (m_ppsParseTreeFileNames[nCount]->CompareNoCase(m_pcIncludeFileStack[m_nCompileFileLevel-1].m_sCompiledScriptName) == TRUE)
+ {
+ m_nCurrentParseTreeFileName = nCount;
+ pNewNode->m_nFileReference = nCount;
+ return pNewNode;
+ }
+ }
+ }
+
+ // Can't find it in the currently defined values ... make a new one.
+ int32_t nNewEntry = m_nNextParseTreeFileName;
+ //(m_nNextParseTreeFileName is 0 ... add the first entry.
+ pNewNode->m_nFileReference = nNewEntry;
+ m_ppsParseTreeFileNames[nNewEntry] = new CExoString(m_pcIncludeFileStack[m_nCompileFileLevel-1].m_sCompiledScriptName.CStr());
+ ++m_nNextParseTreeFileName;
+ m_nCurrentParseTreeFileName = nNewEntry;
+ }
+
+ return pNewNode;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::DuplicateScriptParseTree()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/20/2001
+// Description: Duplicates a parse tree.for use in an assignment.
+///////////////////////////////////////////////////////////////////////////////
+
+CScriptParseTreeNode *CScriptCompiler::DuplicateScriptParseTree(CScriptParseTreeNode *pNode)
+{
+ if (pNode == NULL)
+ {
+ return NULL;
+ }
+
+ CScriptParseTreeNode *pNewNode = GetNewScriptParseTreeNode();
+
+ pNewNode->nOperation = pNode->nOperation;
+ pNewNode->nIntegerData = pNode->nIntegerData;
+ pNewNode->nIntegerData2 = pNode->nIntegerData2;
+ pNewNode->fFloatData = pNode->fFloatData;
+ pNewNode->fVectorData[0] = pNode->fVectorData[0];
+ pNewNode->fVectorData[1] = pNode->fVectorData[1];
+ pNewNode->fVectorData[2] = pNode->fVectorData[2];
+ pNewNode->nLine = pNode->nLine;
+ pNewNode->nChar = pNode->nChar;
+ pNewNode->nType = pNode->nType;
+ pNewNode->m_nStackPointer= pNode->m_nStackPointer;
+ pNewNode->m_nFileReference = pNode->m_nFileReference;
+
+ if (pNode->m_psStringData != NULL)
+ {
+ pNewNode->m_psStringData = new CExoString(pNode->m_psStringData->CStr());
+ }
+
+
+ if (pNode->m_psTypeName != NULL)
+ {
+ pNewNode->m_psTypeName = new CExoString(pNode->m_psTypeName->CStr());
+ }
+
+ pNewNode->pLeft = DuplicateScriptParseTree(pNode->pLeft);
+ pNewNode->pRight = DuplicateScriptParseTree(pNode->pRight);
+
+ return pNewNode;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CheckForBadLValue()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 02/20/2001
+// Description: Checks a branch of a tree to determine if this is a
+// suitable LValue for an assignment statement.
+///////////////////////////////////////////////////////////////////////////////
+
+BOOL CScriptCompiler::CheckForBadLValue(CScriptParseTreeNode *pNode)
+{
+ BOOL bBadLValue = TRUE;
+ if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ bBadLValue = FALSE;
+ }
+ else if (pNode->nOperation == CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART)
+ {
+ CScriptParseTreeNode *pTraceBranch = pNode->pLeft;
+ while (pTraceBranch != NULL && bBadLValue == TRUE)
+ {
+ if (pTraceBranch->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ bBadLValue = FALSE;
+ }
+ pTraceBranch = pTraceBranch->pLeft;
+ }
+ }
+
+ return bBadLValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::GenerateParseTree()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 07/22/99
+// Description: The main guts of the first pass of the parsing routine.
+// This routine takes a token and determines how it should be
+// connected to the rest of the tree. This is all done based
+// on the 32 case grammar that was determined earlier. Each
+// part of the 32-case grammar is listed beside the case
+// statement, and this will hopefully make the system as clear
+// as mud.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::GenerateParseTree()
+{
+ int32_t nTopStackState;
+ int32_t nTopStackRule;
+ int32_t nTopStackTerm;
+ CScriptParseTreeNode *pTopStackCurrentNode;
+ CScriptParseTreeNode *pTopStackReturnNode;
+
+ BOOL bAlwaysTrue = TRUE;
+
+ while (bAlwaysTrue)
+ {
+ // Remove the topmost state from the stack.
+ if (PopSRStack(&nTopStackState, &nTopStackRule,
+ &nTopStackTerm, &pTopStackCurrentNode,
+ &pTopStackReturnNode) == FALSE)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_FATAL_COMPILER_ERROR;
+ return nError;
+ }
+
+
+ // Now, the giant case statement. Based on the State, Rule, Term and Token,
+ // we either create some new nodes, link the existing nodes to the new nodes,
+ // push some states on to the stack, install a "return" tree on to the stack
+ // et cetera.
+
+ switch (nTopStackState)
+ {
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // case 35:
+ // constant:
+ // (1) integer-constant
+ // (2) string-constant
+ // (3) floating-point-constant
+ // (4) OBJECT_SELF
+ // (5) OBJECT_INVALID
+ // (6) [ {{{float_opt} , float_opt} , float_opt} ] (for declaring a vector).
+ // (7) JSON_* for declaring json default ctor constants.
+ ///////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_CONSTANT:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ int32_t nCount;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_SQUARE_BRACKET)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_VECTOR,NULL,NULL);
+ pNewNode->fVectorData[0] = 0.0f;
+ pNewNode->fVectorData[1] = 0.0f;
+ pNewNode->fVectorData[2] = 0.0f;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONSTANT,6,2,pNewNode);
+ return 0;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER,NULL,NULL);
+ pNewNode->nIntegerData = 0;
+ int32_t nSign = 1;
+ for (nCount = 0; nCount < m_nTokenCharacters; nCount++)
+ {
+ // Account for a negative constant from the language definition file.
+ if (m_pchToken[nCount] == '-' && nCount == 0)
+ {
+ nSign = -1;
+ }
+ else
+ {
+ pNewNode->nIntegerData *= 10;
+ pNewNode->nIntegerData += (m_pchToken[nCount] - '0');
+ }
+ }
+ // Apply the negative of the integer, if required.
+ if (nSign == -1)
+ {
+ pNewNode->nIntegerData *= nSign;
+ }
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_HEX_INTEGER)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->nIntegerData = 0;
+ for (nCount = 2; nCount < m_nTokenCharacters; nCount++)
+ {
+ if (m_pchToken[nCount] >= '0' &&
+ m_pchToken[nCount] <= '9')
+ {
+ pNewNode->nIntegerData *= 16;
+ pNewNode->nIntegerData += (m_pchToken[nCount] - '0');
+ }
+ else
+ {
+ pNewNode->nIntegerData *= 16;
+ pNewNode->nIntegerData += 10 + (m_pchToken[nCount] - 'a');
+ }
+ }
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT,NULL,NULL);
+ pNewNode->fFloatData = ParseFloatFromTokenString();
+
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->m_psStringData = new CExoString(m_pchToken);
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_SELF)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_OBJECT,NULL,NULL);
+ // ??? m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->nIntegerData = 0;
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_INVALID)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_OBJECT,NULL,NULL);
+ // ??? m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->nIntegerData = 1;
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_LOCATION_INVALID)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_LOCATION,NULL,NULL);
+ // ??? m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->nIntegerData = 0;
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_JSON,NULL,NULL);
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL)
+ pNewNode->m_psStringData = new CExoString("null");
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE)
+ pNewNode->m_psStringData = new CExoString("false");
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE)
+ pNewNode->m_psStringData = new CExoString("true");
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT)
+ pNewNode->m_psStringData = new CExoString("{}");
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY)
+ pNewNode->m_psStringData = new CExoString("[]");
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING)
+ pNewNode->m_psStringData = new CExoString("\"\"");
+ else
+ EXOASSERTNCSTR("missing impl");
+
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT)
+ {
+ pTopStackCurrentNode->fVectorData[0] = ParseFloatFromTokenString();
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONSTANT,6,3,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_CONSTANT_VECTOR;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONSTANT,6,4,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_CONSTANT_VECTOR;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 4)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT)
+ {
+ pTopStackCurrentNode->fVectorData[1] = ParseFloatFromTokenString();
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONSTANT,6,5,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_CONSTANT_VECTOR;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 5)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONSTANT,6,6,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_CONSTANT_VECTOR;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 6)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT)
+ {
+ pTopStackCurrentNode->fVectorData[2] = ParseFloatFromTokenString();
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONSTANT,6,7,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_CONSTANT_VECTOR;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 7)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_CONSTANT_VECTOR;
+ return nError;
+ }
+ }
+
+ break;
+
+ //////////////////////////////////////////////////////////
+ // case 34:
+ // primary-expression:
+ // (1) non-void-identifier ( argument-expression-list )
+ // (2) constant
+ // (3) ( expression )
+ // (4) variable
+ // (5) void-identifier ( argument-expression-list )
+ // treated as an action argument ONLY!
+ /////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_HEX_INTEGER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_SELF ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_INVALID ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_LOCATION_INVALID ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_SQUARE_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,2,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONSTANT,0,0,NULL);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VARIABLE)
+ {
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode2->m_psStringData = new CExoString(m_pchToken);
+ ModifySRStackReturnTree(pNewNode2);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,3,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER ||
+ (m_nTokenStatus >= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER &&
+ m_nTokenStatus <= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER))
+ {
+ // Do somethin' with the identifier.
+
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ACTION_ID,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode2->m_psStringData = new CExoString(m_pchToken);
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ACTION,NULL,pNewNode2);
+
+ if ( m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER )
+ {
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ACTION_PARAMETER,pNewNode,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,5,2,pNewNode3);
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,1,2,pNewNode);
+ }
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,1,3,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_ARG_LIST;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_ARG_LIST;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 5 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,5,3,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_ARG_LIST;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 5 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ pTopStackCurrentNode->pLeft->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_ARG_LIST;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 1)
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ if (nTopStackRule == 3 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ }
+ }
+ break;
+
+ ///////////////////////////////////////////
+ // case 33:
+ // post-expression:
+ // (1) primary-expression
+ // (2) primary-expression . variable
+ // (3) primary_expression ++
+ // (4) primary_expression --
+ //////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,1,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 2) ||
+ (nTopStackTerm == 4))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRUCTURE_PART_SPECIFY)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART,NULL,NULL);
+ if (nTopStackTerm == 4)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+ else if (pTopStackCurrentNode != NULL && pTopStackReturnNode == NULL)
+ {
+ // This came in when we realized there was a structure part in
+ // the variable specified in an assignment statement. For the
+ // love of god, this is getting complicated.
+ pNewNode->pLeft = pTopStackCurrentNode;
+ }
+ else
+ {
+ // The standard method of receiving a structure part ... from
+ // a FREAKIN' return node. (Is that *SO* wrong?)
+ pNewNode->pLeft = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,2,4,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,2,3,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INCREMENT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_POST_INCREMENT,NULL,NULL);
+ if (nTopStackTerm == 4)
+ {
+ // Adding a post increment to a structure part.
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+ else
+ {
+ // Adding a post increment to a standalone variable.
+ pNewNode->pLeft = pTopStackReturnNode;
+ }
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_DECREMENT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_POST_DECREMENT,NULL,NULL);
+ if (nTopStackTerm == 4)
+ {
+ // Adding a post increment to a structure part.
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+ else
+ {
+ // Adding a post increment to a standalone variable.
+ pNewNode->pLeft = pTopStackReturnNode;
+ }
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else
+ {
+ // It's not one of our magic three operators?
+ // Well, then! That doesn't bode well. We have
+ // to report what we've constructed up the stack.
+
+ if (nTopStackTerm == 4)
+ {
+ // We are processing a structure part.
+ // We have a variable hanging around in pTopStackReturnNode.
+ // This should be reattached.
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ // This is just a standard primary-expression, so
+ // let's just send it up the stack.
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 3)
+ {
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode2->m_psStringData = new CExoString(m_pchToken);
+ ModifySRStackReturnTree(pNewNode2);
+ return 0;
+ }
+
+ break;
+
+ ////////////////////////////////////
+ // case 32:
+ // unary-expression:
+ // (1) - post-expression
+ // (2) ~ post-expression
+ // (3) ! post-expression
+ // (4) ++ post-expression
+ // (5) -- post_expression
+ // (6) post-expression
+ ////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_MINUS)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_NEGATION,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,1,1,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_TILDE)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ONES_COMPLEMENT,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,2,1,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_BOOLEAN_NOT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_BOOLEAN_NOT,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,3,1,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INCREMENT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_PRE_INCREMENT,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,4,1,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_DECREMENT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_PRE_DECREMENT,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,5,1,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,6,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION,0,0,NULL);
+ }
+ }
+ if ((nTopStackRule >= 1 && nTopStackRule <= 5) && nTopStackTerm == 1)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 1)
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ break;
+
+ //////////////////////////////////////////////////////
+ // case 31:
+ // multiplicative-expression
+ // (1) unary-expression
+ // (2) multiplicative-expression * unary-expression
+ // (3) multiplicative-expression / unary-expression
+ // (4) multiplicative-expression % unary-expression
+ //////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_MULTIPLY)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_MULTIPLY,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_DIVIDE)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_DIVIDE,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,3,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_MODULUS)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_MODULUS,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,4,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ //////////////////////////////////////////////////////////
+ // case 30:
+ // additive-expression
+ // (1) multiplicative-expression
+ // (2) additive-expression + multiplicative-expression
+ // (3) additive-expression - multiplicative-expression
+ //////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_PLUS)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ADD,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_MINUS)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SUBTRACT,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,3,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ ////////////////////////////////////////////////////
+ // case 29:
+ // shift-expression
+ // (1) additive-expression
+ // (2) shift-expression >> additive-expression
+ // (3) shift-expression << additive-expression
+ // (4) shift-expression >>> additive-expression
+ ////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SHIFT_LEFT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SHIFT_LEFT,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SHIFT_RIGHT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SHIFT_RIGHT,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,3,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_UNSIGNED_SHIFT_RIGHT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_UNSIGNED_SHIFT_RIGHT,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,4,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ ////////////////////////////////////////////////////
+ // case 28:
+ // relational-expression:
+ // (1) shift-expression
+ // (2) relational-expression >= shift-expression
+ // (3) relational-expression > shift-expression
+ // (4) relational-expression < shift-expression
+ // (5) relational-expression <= shift-expression
+ ////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COND_GREATER_EQUAL)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONDITION_GEQ,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COND_LESS_EQUAL)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONDITION_LEQ,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,3,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COND_LESS_THAN)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONDITION_LT,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,4,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COND_GREATER_THAN)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONDITION_GT,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,5,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ /////////////////////////////////////////////////////////
+ // case 27:
+ // equality-expression
+ // (1) relational-expression
+ // (2) equality-expression == relational-expression
+ // (3) equality-expression != relational-expression
+ /////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COND_NOT_EQUAL)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONDITION_NOT_EQUAL,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COND_EQUAL)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION,3,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ ////////////////////////////////////////////////////////
+ // case 26:
+ // boolean-AND-expression
+ // (1) equality-expression
+ // (2) boolean-AND-expression & equailty-expression
+ ////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_BOOLEAN_AND)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_BOOLEAN_AND,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ //////////////////////////////////////////////////////////
+ // case 25:
+ // exclusive-OR-expression
+ // (1) boolean-AND-expression
+ // (2) exclusive-OR-expression ^ boolean-AND-expression
+ //////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_EXCLUSIVE_OR)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_EXCLUSIVE_OR,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // case 24:
+ // inclusive-OR-expression:
+ // (1) exclusive-OR-expression
+ // (2) inclusive-OR-expression | exclusive-OR-expression
+ /////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INCLUSIVE_OR)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_INCLUSIVE_OR,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////
+ // case 23:
+ // logical-AND-expression:
+ // (1) inclusive-OR-expression
+ // (2) logical-AND-expression && inclusive-OR-expression
+ ///////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LOGICAL_AND)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_LOGICAL_AND,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // case 22:
+ // logical-OR-expression:
+ // (1) logical-AND-expression
+ // (2) logical-OR-expression || logical-AND-expression
+ //////////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_LOGICAL_OR_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_OR_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION,0,0,NULL);
+ }
+ if ((nTopStackRule == 1 && nTopStackTerm == 1) ||
+ (nTopStackTerm == 3))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LOGICAL_OR)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_LOGICAL_OR,pTopStackReturnNode,NULL);
+ if (nTopStackTerm == 3)
+ {
+ pNewNode->pLeft = pTopStackCurrentNode;
+ pNewNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_OR_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // case 21:
+ // conditional-expression:
+ // (1) logical-OR-expression
+ // (2) logical-OR-expression ? conditional_expression : conditional_expression
+ //////////////////////////////////////////////////////////////////////////////////
+ case CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION:
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_OR_EXPRESSION,0,0,NULL);
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 1)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_QUESTION_MARK)
+ {
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_COND_CONDITION,pTopStackReturnNode,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_COND_CHOICE,NULL,NULL);
+ CScriptParseTreeNode *pNewNode1 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_COND_BLOCK,pNewNode2,pNewNode3);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,2,3,pNewNode1);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_COLON)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_CONDITIONAL_REQUIRES_SECOND_EXPRESSION;
+ return nError;
+ }
+ pTopStackCurrentNode->pRight->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,2,5,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 5)
+ {
+ pTopStackCurrentNode->pRight->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ break;
+ /////////////////////////////////////////////////////////////////////
+ // case 20:
+ // assignment-expression:
+ // (1) conditional-expression
+ // (2) variable_lvalue = conditional_expression
+ // (3) variable_lvalue -= conditional_expression
+ // (4) variable_lvalue += conditional_expression
+ // (5) variable_lvalue *= conditional_expression
+ // (6) variable_lvalue /= conditional_expression
+ // (7) variable_lvalue %= conditional_expression
+ // (8) variable_lvalue &= conditional_expression
+ // (9) variable_lvalue ^= conditional_expression
+ // (10) variable_lvalue |= conditional_expression
+ // (11) variable_lvalue <<= conditional_expression
+ // (12) variable_lvalue >>= conditional_expression
+ // (13) variable_lvalue >>>= conditional_expression
+ // variable_lvalue is a variable or a structure part of a variable.
+ ////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_ASSIGNMENT_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ // MGB - Feb 11, 2003 - BEGIN CHANGE
+ // To speed up compiling, what's the point in pushing
+ // and popping all of this when we know we are on a
+ // greased pole directly to the unary expression?
+ // It saves about 2 seconds (in debug mode) by losing
+ // approximately 20% of all the Push and Pop operations.
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ASSIGNMENT_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_OR_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION,0,0,NULL);
+ // MGB - Feb 11, 2003 - END CHANGE
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 1)
+ {
+ if (m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MINUS &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_PLUS &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MULTIPLY &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_DIVIDE &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MODULUS &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_AND &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_XOR &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_OR &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_LEFT &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_RIGHT &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_USHIFT_RIGHT)
+
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ else
+ {
+ if (CheckForBadLValue(pTopStackReturnNode) == TRUE)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_BAD_LVALUE;
+ return nError;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ASSIGNMENT,NULL,pTopStackReturnNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ASSIGNMENT_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,0,0,NULL);
+ }
+ else
+ {
+ CScriptParseTreeNode *pDupTree = DuplicateScriptParseTree(pTopStackReturnNode);
+ int32_t nNewTerm = 0;
+ CScriptParseTreeNode *pNewNode2 = NULL;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MINUS)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SUBTRACT,pDupTree,NULL);
+ nNewTerm = 3;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_PLUS)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ADD,pDupTree,NULL);
+ nNewTerm = 4;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MULTIPLY)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_MULTIPLY,pDupTree,NULL);
+ nNewTerm = 5;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_DIVIDE)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_DIVIDE,pDupTree,NULL);
+ nNewTerm = 6;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MODULUS)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_MODULUS,pDupTree,NULL);
+ nNewTerm = 7;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_AND)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_BOOLEAN_AND,pDupTree,NULL);
+ nNewTerm = 8;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_XOR)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_EXCLUSIVE_OR,pDupTree,NULL);
+ nNewTerm = 9;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_OR)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_INCLUSIVE_OR,pDupTree,NULL);
+ nNewTerm = 10;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_LEFT)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SHIFT_LEFT,pDupTree,NULL);
+ nNewTerm = 11;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_RIGHT)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SHIFT_RIGHT,pDupTree,NULL);
+ nNewTerm = 12;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_USHIFT_RIGHT)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_UNSIGNED_SHIFT_RIGHT,pDupTree,NULL);
+ nNewTerm = 13;
+ }
+
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ASSIGNMENT,pNewNode2,pTopStackReturnNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ASSIGNMENT_EXPRESSION,nNewTerm,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,0,0,NULL);
+
+ }
+ return 0;
+ }
+ }
+ if (nTopStackTerm == 3)
+ {
+
+ // Mmmm ... creamy goodness. If we've managed to screw up the assignment because this
+ // is a variable, and there's a left bracket right after it ... then we've probably got
+ // an undefined identifier and we should do something about it.
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ if (pTopStackReturnNode != NULL)
+ {
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ m_sUndefinedIdentifier = *(pTopStackReturnNode->m_psStringData);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ return nError;
+ }
+ }
+ }
+
+ if (nTopStackRule == 2)
+ {
+ // For this rule (a plain assignment) attach the operand to the left of the assignment.
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ }
+ else
+ {
+ // For other rules, attach the second operand to the operation instead of the assignment.
+ pTopStackCurrentNode->pLeft->pRight = pTopStackReturnNode;
+ }
+
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+
+ break;
+
+ ////////////////////////////////
+ // case 19:
+ // expression:
+ // (1) assignment-expression
+ ////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ASSIGNMENT_EXPRESSION,0,0,NULL);
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 1)
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////
+ // case 18:
+ // non-void-expression:
+ // (1) expression, then ensure there is a single-return-value.
+ ////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXPRESSION,0,0,NULL);
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 1)
+ {
+ // MGB - October 29, 2002
+ // Here, we would check to see if there is a single-return-value
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_NON_VOID_EXPRESSION,pTopStackReturnNode,NULL);
+ ModifySRStackReturnTree(pNewNode);
+ }
+ break;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // case 17:
+ // boolean-expression:
+ // (1) non-void-expression, then Ensure there is a single integer returned.
+ /////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION,1,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION,0,0,NULL);
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 1)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_INTEGER_EXPRESSION,pTopStackReturnNode,NULL);
+ ModifySRStackReturnTree(pNewNode);
+ }
+ break;
+
+ /////////////////////////////////////////////////////////////////
+ // case 16:
+ // after-argument-expression:
+ // (1) ) // the end of the list ... hand it to previous level.
+ // (2) , non-void-expression after-argument-expression
+ /////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_AFTER_ARGUMENT_EXPRESSION:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ ModifySRStackReturnTree(NULL);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_ARGUMENT_EXPRESSION,2,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (m_pSRStack[m_nSRStackStates].pCurrentTree != NULL)
+ {
+ if (m_pSRStack[m_nSRStackStates].pCurrentTree->pRight != NULL)
+ {
+ if (m_pSRStack[m_nSRStackStates].pCurrentTree->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ m_sUndefinedIdentifier = *(m_pSRStack[m_nSRStackStates].pCurrentTree->pRight->m_psStringData);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ return nError;
+ }
+ if (m_pSRStack[m_nSRStackStates].pCurrentTree->pRight->pLeft != NULL)
+ {
+ if (m_pSRStack[m_nSRStackStates].pCurrentTree->pRight->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ m_sUndefinedIdentifier = *(m_pSRStack[m_nSRStackStates].pCurrentTree->pRight->pLeft->m_psStringData);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ return nError;
+ }
+
+ }
+ }
+ }
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 2)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ACTION_ARG_LIST,NULL,pTopStackReturnNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_ARGUMENT_EXPRESSION,2,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_ARGUMENT_EXPRESSION,0,0,NULL);
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // case 15:
+ // argument-expression-list:
+ // (1) ) // You see the end of the list ... can pop back to previous level if
+ // // when you've cross-checked the types of the return values, you see
+ // // that everything is kosher.
+ // (2) non-void-expression after-argument-expression
+ ///////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ }
+ else if (m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST,2,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION,0,0,NULL);
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 1)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ACTION_ARG_LIST,NULL,pTopStackReturnNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST,2,2,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_ARGUMENT_EXPRESSION,0,0,NULL);
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 2)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ break;
+
+ //////////////////////////////////////////
+ // case 14:
+ // declaration-variable-list-separator
+ // (1) ;
+ // (2) , declaration-variable-list
+ //////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST_SEPARATOR:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA)
+ {
+ // Create a new statement that we can link to.
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(0,NULL,NULL);
+ if (pTopStackCurrentNode != NULL &&
+ pTopStackCurrentNode->pLeft != NULL &&
+ pTopStackCurrentNode->pLeft->pLeft != NULL)
+ {
+ pNewNode3->nOperation = pTopStackCurrentNode->pLeft->pLeft->nOperation;
+ if (pNewNode3->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT)
+ {
+ pNewNode3->m_psStringData = new CExoString(pTopStackCurrentNode->pLeft->pLeft->m_psStringData->CStr());
+ }
+ }
+
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION,pNewNode3,NULL);
+ CScriptParseTreeNode *pNewNode1 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pNewNode2,NULL);
+
+ // Point back to the new statement ...
+ if (pTopStackCurrentNode->pRight == NULL)
+ {
+ // There is no assignment statement added to the list, so we
+ // can attach directly to pTopStackCurrentNode->pRight.
+ pTopStackCurrentNode->pRight = pNewNode1;
+ // Update the line number.
+ pTopStackCurrentNode->pRight->nLine = pTopStackCurrentNode->nLine;
+ }
+ else
+ {
+ // We've also added an assignment statement to the list, so we
+ // have to attach to pTopStackCurrentNode->pRight->pRight instead.
+ pTopStackCurrentNode->pRight->pRight = pNewNode1;
+ // Update the line number.
+ pTopStackCurrentNode->pRight->pRight->nLine = pTopStackCurrentNode->nLine;
+
+ }
+ // ... and feed it back to the main routine.
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST,0,0,pNewNode1);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////
+ // case 13:
+ // declaration-variable-list
+ // (1) variable declaration-variable-list-separator
+ // (2) variable = non-void-expression declaration-variable-list-separator
+ ////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VARIABLE)
+ {
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode2->m_psStringData = new CExoString(m_pchToken);
+
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE_LIST,pNewNode2,NULL);
+
+ if (pTopStackCurrentNode != NULL &&
+ pTopStackCurrentNode->pLeft != NULL)
+ {
+ pTopStackCurrentNode->pLeft->pRight = pNewNode;
+ }
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST,1,2,pTopStackCurrentNode);
+
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+ }
+ else if (nTopStackRule == 1 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL)
+ {
+ CScriptParseTreeNode *pNewNode0 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE,NULL,NULL);
+ if (pTopStackCurrentNode != NULL &&
+ pTopStackCurrentNode->pLeft != NULL &&
+ pTopStackCurrentNode->pLeft->pRight != NULL &&
+ pTopStackCurrentNode->pLeft->pRight->pLeft != NULL)
+ {
+ pNewNode0->m_psStringData = new CExoString(pTopStackCurrentNode->pLeft->pRight->pLeft->m_psStringData->CStr());
+ }
+
+ CScriptParseTreeNode *pNewNode1 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ASSIGNMENT,NULL,pNewNode0);
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pNewNode1,NULL);
+ pTopStackCurrentNode->pRight = pNewNode2;
+ pTopStackCurrentNode->pRight->nLine = pTopStackCurrentNode->nLine;
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST,2,2,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST_SEPARATOR,0,0,pTopStackCurrentNode);
+ }
+ }
+ else if (nTopStackRule == 2 && nTopStackTerm == 2)
+ {
+ pTopStackCurrentNode->pRight->pLeft->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST_SEPARATOR,0,0,pTopStackCurrentNode);
+ }
+
+ break;
+
+ ///////////////////////////////////////////////////////////////////////
+ // case 12:
+ // non-void-type-specifier:
+ // (1) [const] int
+ // (2) [const] float
+ // (3) [const] string
+ // (4) object
+ // (5) struct variable
+ // (6) one of the ENGINE_STRUCTURE defined variables passed in from
+ // the language definition!
+ // (7) vector -- treated as a structure.
+ ///////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_CONST)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONST_DECLARATION,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER,0,0,pNewNode);
+ return 0;
+ }
+
+ if (pTopStackCurrentNode != NULL &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_KEYWORD_INT &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT &&
+ m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_INVALID_TYPE_FOR_CONST_KEYWORD;
+ return nError;
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR)
+ {
+ // Treat "vector" as a "struct vector" token.
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->m_psStringData = new CExoString(m_pchToken);
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER,5,1,pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ (m_nTokenStatus >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ m_nTokenStatus <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9))
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(0,NULL,NULL);
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ pNewNode->nOperation = CSCRIPTCOMPILER_OPERATION_KEYWORD_INT;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ pNewNode->nOperation = CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ pNewNode->nOperation = CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT)
+ {
+ pNewNode->nOperation = CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT;
+ }
+ else if (m_nTokenStatus >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 && m_nTokenStatus <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ pNewNode->nOperation = CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0 + (m_nTokenStatus - CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0);
+ }
+
+ if (pTopStackCurrentNode != NULL)
+ {
+ // We've already checked to see if this is a valid type ... so we only need to
+ // put the const declaration operation above this type so that we can interpret
+ // it at the right time.
+ pTopStackCurrentNode->pLeft = pNewNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ ModifySRStackReturnTree(pNewNode);
+ }
+
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_INVALID_DECLARATION_TYPE;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 5 && nTopStackTerm == 1)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VARIABLE)
+ {
+ m_pchToken[m_nTokenCharacters] = 0;
+ pTopStackCurrentNode->m_psStringData = new CExoString(m_pchToken);
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_INVALID_DECLARATION_TYPE;
+ return nError;
+ }
+ }
+
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // case 11:
+ // any-type-specifier:
+ // (1) void
+ // (2) non-void-type-specifier
+ ////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_ANY_TYPE_SPECIFIER:
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID,NULL,NULL);
+ ModifySRStackReturnTree(pNewNode);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER,0,0,NULL);
+ }
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////
+ // case 10:
+ // Within-a-statement:
+ // (1) { within-a-compound-statement }
+ // (2) void-returning-identifier(argument-expression-list);
+ // (3) if (boolean-expression) statement
+ // (4) if (boolean-expression) statement else statement
+ // (5) switch ( boolean-expression ) statement
+ // (6) return non-void-expression(opt) ;
+ // (7) while (boolean-expression) statement
+ // (8) do statement while (boolean-expression);
+ // (9) for (expression_opt; expression_opt; expression_opt) statement
+ // (10) non-void-type-specifier declaration-list ;
+ // (11) expression(opt) ;
+ // (12) default :
+ // (13) case conditional_expression :
+ // (14) break ;
+ // (15) continue ;
+ /////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACE)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,1,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_COMPOUND_STATEMENT,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_RETURN)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_RETURN,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,6,2,pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_SWITCH)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,5,2,pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFAULT)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_DEFAULT,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,12,2,pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_CASE)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CASE,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,13,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_BREAK)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_BREAK,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,14,2,pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_CONTINUE)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONTINUE,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,15,2,pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER)
+ {
+ // Do somethin' with the identifier.
+
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ACTION_ID,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode2->m_psStringData = new CExoString(m_pchToken);
+
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_ACTION,NULL,pNewNode2);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,2,2,pNewNode);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_IF)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,3,2,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ELSE)
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_ELSE_WITHOUT_CORRESPONDING_IF;
+ return nError;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_WHILE)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,7,2,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_DO)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,8,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_FOR)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,2,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_CONST ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR ||
+ (m_nTokenStatus >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ m_nTokenStatus <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9))
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,10,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER,0,0,NULL);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,11,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXPRESSION,0,0,NULL);
+ }
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT,pTopStackReturnNode,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,1,3,pNewNode);
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_END_COMPOUND_STATEMENT;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int32_t nError = STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_END_COMPOUND_STATEMENT;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,2,3,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_ARG_LIST;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,2,4,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_ARG_LIST;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 4)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 3 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_IF_CHOICE,NULL,NULL);
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_IF_CONDITION,NULL,NULL);
+ CScriptParseTreeNode *pNewNode1 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_IF_BLOCK,pNewNode2,pNewNode3);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,3,3,pNewNode1);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 3 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ pTopStackCurrentNode->pLeft->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,3,5,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 3 && nTopStackTerm == 5)
+ {
+ // Link up the "if expression true" statement.
+ if (pTopStackReturnNode == NULL)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_IF_CONDITION_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT;
+ return nError;
+ }
+
+ // MGB - For Script Debugger.
+ CScriptParseTreeNode *pNewNode2;
+
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_FOR_BLOCK )
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,pTopStackReturnNode,NULL);
+ }
+ else
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pTopStackReturnNode,NULL);
+ pNewNode2->nLine = pTopStackReturnNode->nLine;
+ }
+ // MGB - !For Script Debugger
+
+ pTopStackCurrentNode->pRight->pLeft = pNewNode2;
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_ELSE)
+ {
+ // MGB - For Script Debugger.
+ // When we process an else branch, we need a line
+ // number for the code!
+ pTopStackCurrentNode->pRight->nLine = m_nLines;
+ // MGB - !For Script Debugger
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,3,7,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ }
+ if (nTopStackRule == 3 && nTopStackTerm == 7)
+ {
+ if (pTopStackReturnNode == NULL)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_ELSE_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT;
+ return nError;
+ }
+
+ // Link up the "if expression false" statement.
+ CScriptParseTreeNode *pNewNode2;
+
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_FOR_BLOCK)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,pTopStackReturnNode,NULL);
+ }
+ else
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pTopStackReturnNode,NULL);
+ pNewNode2->nLine = pTopStackReturnNode->nLine;
+ }
+
+ // MGB - August 10, 2001 - Fixed bug where else expression was actually linking
+ // directly to the returned parse tree without linking the operation_statement in place.
+ pTopStackCurrentNode->pRight->pRight = pNewNode2;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ if (nTopStackRule == 5 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,5,4,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 5 && nTopStackTerm == 4)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_SWITCH_CONDITION,pTopStackReturnNode,NULL);
+ pTopStackCurrentNode->pLeft = pNewNode;
+ // MGB - February 5, 2003 - Removed pTopStackReturnNode from left branch of this
+ // tree node, since it didn't really make a lot of sense.
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,NULL,NULL);
+ pTopStackCurrentNode->pRight = pNewNode2;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,5,5,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 5 && nTopStackTerm == 5)
+ {
+ if (pTopStackReturnNode == NULL)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_SWITCH_CONDITION_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT;
+ return nError;
+ }
+
+ pTopStackCurrentNode->pRight->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ if (nTopStackRule == 6 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,6,3,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION,0,0,NULL);
+ }
+ }
+
+ if (nTopStackRule == 6 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_RETURN_STATEMENT;
+ return nError;
+ }
+ }
+
+ if (nTopStackRule == 7 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ CScriptParseTreeNode *pNewNode1 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,7,3,pNewNode1);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 7 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_CONDITION,pTopStackReturnNode,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_CHOICE,NULL,NULL);
+ pTopStackCurrentNode->pLeft = pNewNode2;
+ pTopStackCurrentNode->pRight = pNewNode3;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,7,5,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ if (pTopStackReturnNode != NULL)
+ {
+ if (pTopStackReturnNode->pLeft != NULL)
+ {
+ if (pTopStackReturnNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ m_sUndefinedIdentifier = *(pTopStackReturnNode->pLeft->m_psStringData);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ return nError;
+ }
+ }
+ }
+ }
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 7 && nTopStackTerm == 5)
+ {
+ // Link up the "if expression true" statement.
+ CScriptParseTreeNode *pNewNode4 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_CONTINUE,NULL,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,pNewNode4,NULL);
+
+ if (pTopStackReturnNode == NULL)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_WHILE_CONDITION_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT;
+ return nError;
+ }
+
+ // MGB - For Script Debugger.
+ CScriptParseTreeNode *pNewNode2;
+
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_FOR_BLOCK)
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,pTopStackReturnNode,pNewNode3);
+ }
+ else
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pTopStackReturnNode,pNewNode3);
+ pNewNode2->nLine = pTopStackReturnNode->nLine;
+ }
+ // MGB - !For Script Debugger
+
+ pTopStackCurrentNode->pRight->pLeft = pNewNode2;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ if (nTopStackRule == 8 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_WHILE)
+ {
+ //CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pTopStackReturnNode,NULL);
+ CScriptParseTreeNode *pNewNode2;
+
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_FOR_BLOCK )
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,pTopStackReturnNode,NULL);
+ }
+ else
+ {
+ pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pTopStackReturnNode,NULL);
+ pNewNode2->nLine = pTopStackReturnNode->nLine;
+ }
+ CScriptParseTreeNode *pNewNode1 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_DOWHILE_CONDITION,NULL,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK,pNewNode2,pNewNode1);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,8,3,pNewNode3);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_WHILE_AFTER_DO_KEYWORD;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 8 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,8,5,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 8 && nTopStackTerm == 5)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ pTopStackCurrentNode->pRight->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,8,6,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 8 && nTopStackTerm == 6)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ CScriptParseTreeNode *pNewNode8 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_CONTINUE,NULL,NULL);
+ CScriptParseTreeNode *pNewNode9 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,NULL,NULL);
+ CScriptParseTreeNode *pNewNode1 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,NULL,NULL);
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,pNewNode8,pNewNode9);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_CHOICE,pNewNode1,pNewNode2);
+ CScriptParseTreeNode *pNewNode4 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_CONDITION,NULL,NULL);
+ CScriptParseTreeNode *pNewNode5 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK,pNewNode4,pNewNode3);
+ CScriptParseTreeNode *pNewNode6 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG,pNewNode5,NULL);
+ CScriptParseTreeNode *pNewNode7 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,NULL,pNewNode6);
+
+ CScriptParseTreeNode *pNewNode10 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_FOR_BLOCK,pNewNode7,NULL);
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,3,pNewNode10);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,5,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,4,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXPRESSION,0,0,NULL);
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 4)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ // Create a node and stick the expression on to it.
+ pTopStackCurrentNode->pLeft->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,5,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 5)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER,NULL,NULL);
+ pNewNode->nIntegerData = 1;
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_NON_VOID_EXPRESSION,pNewNode,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_INTEGER_EXPRESSION,pNewNode2,NULL);
+
+ pTopStackCurrentNode->pLeft->pRight->pLeft->pLeft->pLeft = pNewNode3;
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,7,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,6,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION,0,0,NULL);
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 6)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ // Create a node and stick the expression on to it.
+ pTopStackCurrentNode->pLeft->pRight->pLeft->pLeft->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,7,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 7)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,9,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,8,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_EXPRESSION,0,0,NULL);
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 8)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ pTopStackCurrentNode->pLeft->pRight->pLeft->pRight->pRight->pRight->pLeft = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,9,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 9)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,9,10,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,0,0,NULL);
+ }
+ if (nTopStackRule == 9 && nTopStackTerm == 10)
+ {
+ if (pTopStackReturnNode == NULL)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_FOR_STATEMENT_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT;
+ return nError;
+ }
+
+ pTopStackCurrentNode->pLeft->pRight->pLeft->pRight->pLeft->pLeft = pTopStackReturnNode;
+
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_FOR_BLOCK)
+ {
+ pTopStackCurrentNode->pLeft->pRight->pLeft->pRight->pLeft->nOperation = CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG;
+ }
+ else
+ {
+ // It's already a STATEMENT, so set the line correctly.
+ pTopStackCurrentNode->pLeft->pRight->pLeft->pRight->pLeft->nLine = pTopStackReturnNode->nLine;
+ }
+
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ if (nTopStackRule == 10 && nTopStackTerm == 2)
+ {
+ // Create a node.
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION,pTopStackReturnNode,NULL);
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pNewNode,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST,pNewNode2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,10,3,pNewNode3);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST,0,0,pNewNode2);
+ }
+ if (nTopStackRule == 10 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 11 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ return 0;
+ }
+ else
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ if (pTopStackReturnNode != NULL)
+ {
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_VARIABLE)
+ {
+ m_sUndefinedIdentifier = *(pTopStackReturnNode->m_psStringData);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER;
+ return nError;
+ }
+ }
+ }
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 12 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_COLON_AFTER_DEFAULT_LABEL;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 13 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COLON)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_COLON_AFTER_CASE_LABEL;
+ return nError;
+ }
+ }
+ if ((nTopStackRule == 14 && nTopStackTerm == 2) ||
+ (nTopStackRule == 15 && nTopStackTerm == 2))
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_STATEMENT;
+ return nError;
+ }
+ }
+
+ break;
+
+ /////////////////////////////////////////////////////////////
+ // case 9:
+ // Within-a-statement-list
+ // (1) within-a-statement within-a-statement-list
+ /////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_WITHIN_STATEMENT_LIST:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_EOF)
+ {
+ // Jump up to previous level.
+ ModifySRStackReturnTree(NULL);
+ }
+ else
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,NULL,NULL);
+ if (pTopStackCurrentNode != NULL)
+ {
+ pTopStackCurrentNode->pRight = pNewNode;
+ }
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_STATEMENT_LIST,1,1,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,0,0,NULL);
+ }
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 1)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+
+ // MGB - Stuff - For Debugging!
+ // IF_BLOCK will take care of its own addressing for conditionals.
+ if (pTopStackReturnNode != NULL)
+ {
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_IF_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK ||
+ pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_FOR_BLOCK)
+ {
+ pTopStackCurrentNode->nOperation = CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG;
+ }
+
+ }
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_STATEMENT_LIST,1,2,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_STATEMENT_LIST,0,0,pTopStackCurrentNode);
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 2)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ break;
+
+ /////////////////////////////////////////////////////////////
+ // case 8:
+ // within-a-compound-statement:
+ // (1) (right brace returns up higher in the tree)
+ // (2) Within-a-statement-list
+ /////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_WITHIN_COMPOUND_STATEMENT:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_COMPOUND_STATEMENT,2,1,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_STATEMENT_LIST,0,0,NULL);
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 1)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST,pTopStackReturnNode,NULL);
+ ModifySRStackReturnTree(pNewNode);
+ }
+ break;
+
+ /////////////////////////////////////////////////////////////
+ // case 7:
+ // non-initialized-decl-variable-list-separator
+ // (1) ;
+ // (2) , variable non-initialized-decl-variable-list
+ //
+ // A semi-colon should pass back up the stack so that the
+ // rule containing the right brace can compile it.
+ //////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST_SEPARATOR:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST,0,0,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////
+ // case 6:
+ // non-initialized-decl-variable-list
+ // (1) variable non-initialized-decl-variable-list-separator
+ //
+ // A semi-colon should pass back up the stack so that the
+ // rule containing the right brace can compile it.
+ //////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST:
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VARIABLE)
+ {
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE,NULL,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode2->m_psStringData = new CExoString(m_pchToken);
+
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE_LIST,pNewNode2,NULL);
+
+ if (pTopStackCurrentNode != NULL)
+ {
+ pTopStackCurrentNode->pRight = pNewNode;
+ }
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST,1,2,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST_SEPARATOR,0,0,pNewNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+ }
+ else if (nTopStackRule == 1 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // case 5:
+ // non-initialized-decl-list:
+ // (1)
+ // (2) non-void-type-specifier non-initialized-decl-variable-list ; non-initialized-decl-list
+ //
+ // A right brace should pass back up the stack so that the
+ // rule containing the right brace can compile it.
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR ||
+ (m_nTokenStatus >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ m_nTokenStatus <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9))
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,NULL,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST,2,2,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER,0,0,NULL);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE)
+ {
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ //return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_BAD_TYPE_SPECIFIER;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 2)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION,pTopStackReturnNode,NULL);
+ pTopStackCurrentNode->pLeft = pNewNode;
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST,2,3,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST,0,0,NULL);
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ // Attach variable list.
+ pTopStackCurrentNode->pLeft->pRight = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST,2,4,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 2 && nTopStackTerm == 4)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+
+ break;
+
+ //////////////////////////////////////////////////////////////////////
+ // case 4:
+ // after-function-parameter:
+ // (1)
+ // (2) , function-parameter-list
+ //
+ // A right bracket should pass back up the stack so that the
+ // rule containing the right bracket can compile it.
+ //////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_AFTER_FUNCTION_PARAM:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ ModifySRStackReturnTree(NULL);
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ }
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////
+ // case 3:
+ // function-parameter-list:
+ // (1) non-void-type-specifier variable after-function-parameter
+ // (2) non-void-type-specifier variable = constant after-function-parameter
+ // (3) non-void-type-specifier variable = - constant after-function-parameter
+ //
+ // Note: the right bracket should return to the previous rule.
+ //////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,1,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER,0,0,NULL);
+ //return 0;
+ }
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 2)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VARIABLE)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_FUNCTION_PARAM_NAME,NULL,pTopStackReturnNode);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->m_psStringData = new CExoString(m_pchToken);
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,1,3,pNewNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_BAD_VARIABLE_NAME;
+ return nError;
+ }
+ }
+ else if (nTopStackRule == 1 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,2,4,pTopStackCurrentNode);
+ //PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,0,1,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_FUNCTION_PARAM,0,0,NULL);
+ }
+ }
+ else if (nTopStackRule == 2 && nTopStackTerm == 4)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_MINUS)
+ {
+ // Constants can be negated in the function declaration, so allow them to be negated!
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_NEGATION,NULL,NULL);
+ pTopStackCurrentNode->pRight->pRight = pNewNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,3,6,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ // This should be a constant, hand it off to parsing by the primary expression rule.
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,2,5,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION,0,0,NULL);
+ }
+ }
+ else if (nTopStackRule == 2 && nTopStackTerm == 5)
+ {
+ // Add the constant on to the food chain.
+ pTopStackCurrentNode->pRight->pRight = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,0,1,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_FUNCTION_PARAM,0,0,NULL);
+ }
+ else if (nTopStackRule == 3 && nTopStackTerm == 6)
+ {
+ // Add the constant right after the potential negation.
+ pTopStackCurrentNode->pRight->pRight->pRight = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,0,1,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_FUNCTION_PARAM,0,0,NULL);
+ }
+
+ // 3,0,1 deals with after-function-parameter
+ if (nTopStackRule == 0 && nTopStackTerm == 1)
+ {
+ pTopStackCurrentNode->pLeft = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+ break;
+
+ //////////////////////////////////////////////////////////////////////
+ // case 2:
+ // after-program:
+ // (1)
+ //////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_AFTER_PROGRAM:
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_EOF)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_PROGRAM,1,1,pTopStackReturnNode);
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_AFTER_COMPOUND_STATEMENT_AT_END;
+ return nError;
+ }
+ }
+
+ // This passes the result of the include back to the
+ // previous thread of execution. All of the functional
+ // units are linked together.
+
+ if (nTopStackRule == 1 && nTopStackTerm == 1)
+ {
+ ModifySRStackReturnTree(pTopStackReturnNode);
+ }
+
+ break;
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ // case 1:
+ // functional-unit:
+ // (1) any-type-specifier variable ( parameter-list ) ;
+ // (2) any-type-specifier variable ( parameter-list ) { within-a-compound-statement }
+ // (3) struct-specifier { non-initialized-decl-list } ;
+ // (4) non-void-type-specifier declaration-list ;
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT:
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,0,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_ANY_TYPE_SPECIFIER,0,0,NULL);
+ }
+ if (nTopStackRule == 0 && nTopStackTerm == 2)
+ {
+ if (pTopStackReturnNode->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT &&
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACE)
+ {
+ // Transfer to rule 3.
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STRUCTURE_DEFINITION,pTopStackReturnNode,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,3,4,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VARIABLE ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER ||
+ (m_nTokenStatus >= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER &&
+ m_nTokenStatus <= CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER))
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_FUNCTION_IDENTIFIER,pTopStackReturnNode,NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode->m_psStringData = new CExoString(m_pchToken);
+
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_FUNCTION_DECLARATION,pNewNode,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_FUNCTION,pNewNode2,NULL);
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,0,3,pNewNode3);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_DEFINITION_MISSING_NAME;
+ return nError;
+ }
+ }
+ if (nTopStackRule == 0 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,0,5,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST,0,0,NULL);
+ return 0;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_COMMA ||
+ m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL)
+ {
+ // Move the code to the appropriate spot where we deal with
+ // global variables.
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,4,0,pTopStackCurrentNode);
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_DEFINITION_MISSING_PARAMETER_LIST;
+ return nError;
+ }
+
+ }
+
+ if (nTopStackRule == 0 && nTopStackTerm == 5)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET)
+ {
+ pTopStackCurrentNode->pLeft->pRight = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,0,6,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_MALFORMED_PARAMETER_LIST;
+ return nError;
+ }
+
+ }
+
+ // Here, we finally decide between a function declaration and
+ // a function implementation!
+
+ if (nTopStackRule == 0 && nTopStackTerm == 6)
+ {
+ // At this point we have access to a full declaration of a
+ // function. Thus, we should make use of this, and write
+ // the identifier on to the list.
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ int32_t nReturnValue = AddUserDefinedIdentifier(pTopStackCurrentNode, FALSE);
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ return nReturnValue;
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_LEFT_BRACE)
+ {
+ int32_t nReturnValue = AddUserDefinedIdentifier(pTopStackCurrentNode, TRUE);
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,2,8,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT,1,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_WITHIN_COMPOUND_STATEMENT,0,0,NULL);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ }
+ }
+
+ if (nTopStackRule == 2 && nTopStackTerm == 8)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+
+ if (nTopStackRule == 3 && nTopStackTerm == 4)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,3,5,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_BAD_TYPE_SPECIFIER;
+ return nError;
+ }
+
+ }
+
+ if (nTopStackRule == 3 && nTopStackTerm == 5)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ AddToGlobalVariableList(pTopStackCurrentNode);
+ //ModifySRStackReturnTree(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_STRUCTURE;
+ return nError;
+ }
+ }
+
+ if (nTopStackRule == 4 && nTopStackTerm == 0)
+ {
+ // Break the current tree, and build our own tree based on the fact
+ // that this is a declaration.
+
+ // Create the nodes for specifying a declaration.
+
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION,NULL,NULL);
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pNewNode,NULL);
+ CScriptParseTreeNode *pNewNode3 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST,pNewNode2,NULL);
+
+ if (pTopStackCurrentNode->pLeft->pLeft->pLeft->nOperation != CSCRIPTCOMPILER_OPERATION_CONST_DECLARATION)
+ {
+ // A variable type is at pTopStackCurrentNode->pLeft->pLeft->pLeft;
+ // Now, we attach the type declaration from the old branch.
+ pNewNode->pLeft = pTopStackCurrentNode->pLeft->pLeft->pLeft;
+ pTopStackCurrentNode->pLeft->pLeft->pLeft = NULL;
+
+ }
+ else
+ {
+ // The const_declaration is at pTopStackCurrentNode->pLeft->pLeft->pLeft;
+
+ // Remove the "const_declaration" operand from the type, and move it
+ // to the top of the statement list!
+
+ // First attach the "proper" type to the keyword declaration object.
+ pNewNode->pLeft = pTopStackCurrentNode->pLeft->pLeft->pLeft->pLeft;
+ // Detach the const_declaration operand from its type.
+ pTopStackCurrentNode->pLeft->pLeft->pLeft->pLeft = NULL;
+ // Attach the const_declaration operand between the statement list and
+ // the first statement node. (Following the left chains ...
+ // pNewNode3->const_declaration->pNewNode2)
+ pNewNode3->pLeft = pTopStackCurrentNode->pLeft->pLeft->pLeft;
+ pNewNode3->pLeft->pLeft = pNewNode2;
+ }
+
+ // Hand the statement list up the food chain.
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,4,3,pNewNode3);
+
+ // Do not allow a void parameter.
+ if (pNewNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_INVALID_DECLARATION_TYPE;
+ return nError;
+ }
+
+ int32_t nStartOfDeclarationLine = pNewNode->pLeft->nLine;
+ pNewNode3->nLine = nStartOfDeclarationLine;
+ pNewNode2->nLine = nStartOfDeclarationLine;
+
+ // If we have placed a const_declaration in place, give it the same
+ // line number, too!
+ if (pNewNode3->pLeft != pNewNode2)
+ {
+ pNewNode3->pLeft->nLine = nStartOfDeclarationLine;
+ }
+
+ // Now, let's get the variable name from the old tree.
+ pNewNode->m_psStringData = new CExoString(pTopStackCurrentNode->pLeft->pLeft->m_psStringData->CStr());
+
+ // Let's verify that this is, in fact, a variable (see rule 13).
+ int32_t m_nCurrentTokenStatus = m_nTokenStatus;
+
+ m_nTokenStatus = CSCRIPTCOMPILER_TOKEN_IDENTIFIER;
+ m_nTokenCharacters = pNewNode->m_psStringData->GetLength();
+ memcpy(m_pchToken, pNewNode->m_psStringData->CStr(), m_nTokenCharacters);
+ int32_t nReturnValue = TestIdentifierToken();
+ if (nReturnValue != 0)
+ {
+ return nReturnValue;
+ }
+
+ if (m_nTokenStatus != CSCRIPTCOMPILER_TOKEN_VARIABLE)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST;
+ return nError;
+ }
+
+ CScriptParseTreeNode *pNewNode5 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE, NULL, NULL);
+ m_pchToken[m_nTokenCharacters] = 0;
+ pNewNode5->m_psStringData = new CExoString(m_pchToken);
+
+ CScriptParseTreeNode *pNewNode6 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_VARIABLE_LIST, pNewNode5, NULL);
+
+ pNewNode->pRight = pNewNode6;
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST,1,2,pNewNode2);
+
+ // Restore the token, and delete the compile tree associated with
+ // the old branch.
+ m_nTokenStatus = m_nCurrentTokenStatus;
+
+ DeleteScriptParseTreeNode(pTopStackCurrentNode->pLeft->pLeft);
+ DeleteScriptParseTreeNode(pTopStackCurrentNode->pLeft);
+ DeleteScriptParseTreeNode(pTopStackCurrentNode);
+ }
+
+ if (nTopStackRule == 4 && nTopStackTerm == 3)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_SEMICOLON)
+ {
+ // Store the result into the global variable array.
+
+ // If we have global variables, we should be dealing with
+ // them immediately by adding them to the identifier list.
+ if (pTopStackCurrentNode->pLeft != NULL &&
+ pTopStackCurrentNode->pLeft->nOperation == CSCRIPTCOMPILER_OPERATION_CONST_DECLARATION)
+ {
+ int32_t nReturnValue = GenerateIdentifiersFromConstantVariables(pTopStackCurrentNode->pLeft->pLeft);
+ DeleteParseTree(FALSE, pTopStackCurrentNode);
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ return 0;
+ }
+
+ AddToGlobalVariableList(pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION;
+ return nError;
+ }
+ }
+
+ break;
+
+ /////////////////////////////////////////////////////////////////////////
+ // case 0:
+ // program:
+ // (1) after-program
+ // (2) functional-unit program
+ // (3) #include string program
+ //////////////////////////////////////////////////////////////////////////
+
+ case CSCRIPTCOMPILER_GRAMMAR_PROGRAM:
+
+ if (nTopStackRule == 0 && nTopStackTerm == 0)
+ {
+ if (pTopStackCurrentNode == NULL && m_nCompileFileLevel <= 1)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_AFTER_PROGRAM,0,0,NULL);
+ }
+
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_EOF)
+ {
+ ModifySRStackReturnTree(NULL);
+
+ // If we're in an included file ... we actually
+ // leave the routine here, instead of trying
+ // to hunt down the TOKEN_EOF in rule 1 ... we
+ // would have to pillage the entire stack of the
+ // file that called this routine to get to that
+ // one!
+
+ if (m_nCompileFileLevel > 1)
+ {
+ return 0;
+ }
+ }
+ else if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_KEYWORD_INCLUDE)
+ {
+ // Note that this is at this level so that we
+ // can avoid giving a functional unit
+ // to an included file. This is the ONLY time
+ // that we really violate the structure of the
+ // grammar in this way.
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,3,1,pTopStackCurrentNode);
+ return 0;
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,1,2,NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT,0,0,NULL);
+ }
+ }
+
+ if (nTopStackRule == 1 && nTopStackTerm == 2)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_FUNCTIONAL_UNIT, pTopStackReturnNode, NULL);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,1,3,pNewNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,0,0,pNewNode);
+ }
+ if (nTopStackRule == 1 && nTopStackTerm == 3)
+ {
+ pTopStackCurrentNode->pRight = pTopStackReturnNode;
+ ModifySRStackReturnTree(pTopStackCurrentNode);
+ }
+
+ if (nTopStackRule == 3 && nTopStackTerm == 1)
+ {
+ if (m_nTokenStatus == CSCRIPTCOMPILER_TOKEN_STRING)
+ {
+
+ CExoString sStringToCompile;
+ m_pchToken[m_nTokenCharacters] = 0;
+ (sStringToCompile).Format("%s",m_pchToken);
+
+ // First things first, let's check to see if the file has
+ // already been included. If it has, ignore the directive
+ // completely!
+ BOOL bFileAlreadyIncluded = FALSE;
+ int32_t nCount = 0;
+ for (nCount = 0; nCount < m_nNextParseTreeFileName; nCount++)
+ {
+ if (m_ppsParseTreeFileNames[nCount]->CompareNoCase(sStringToCompile) == TRUE)
+ {
+ bFileAlreadyIncluded = TRUE;
+ }
+ }
+
+ if (bFileAlreadyIncluded == TRUE)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,0,0,pTopStackCurrentNode);
+ return 0;
+ }
+
+ // If we have got to here, the file hasn't already been included,
+ // and we should prepare to load it in!
+
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,3,2,pTopStackCurrentNode);
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,0,0,pTopStackCurrentNode);
+
+ // Want a TokenInitialize() here, since that is the
+ // state we'll be returning to once we've finished
+ // parsing this file.
+ TokenInitialize();
+ return CompileFile(sStringToCompile);
+ }
+ }
+
+ if (nTopStackRule == 3 && nTopStackTerm == 2)
+ {
+ // This is where we have to handle the reacquisition of
+ // the code from the previous script. pTopStackReturnNode
+ // points to a series of FUNCTIONAL_UNIT nodes. These
+ // have to be added to the queue as (0,1,3) units that
+ // are all detached from one another to allow the code
+ // for this script to operate correctly.
+
+ CScriptParseTreeNode *pRunnerNode;
+ CScriptParseTreeNode *pNextNode;
+ CScriptParseTreeNode *pLastNode;
+
+ pLastNode = NULL;
+ pRunnerNode = pTopStackReturnNode;
+
+ while (pRunnerNode != NULL)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,1,3,pRunnerNode);
+ pLastNode = pRunnerNode;
+ pNextNode = pRunnerNode->pRight;
+ pRunnerNode->pRight = NULL;
+ pRunnerNode = pNextNode;
+ }
+
+ // Now that we've inserted everything in place, set up
+ // to read the next functional unit!
+ if (pLastNode == NULL)
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,0,0,pTopStackCurrentNode);
+ }
+ else
+ {
+ PushSRStack(CSCRIPTCOMPILER_GRAMMAR_PROGRAM,0,0,pLastNode);
+ }
+
+ }
+ break;
+ default:
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER;
+ return nError;
+ } // case
+ }
+
+ // To alleviate warnings from Warning Level 4.
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::AddUserDefinedIdentifier()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/17/2000
+// Description: Adds a user-defined identifier that has been compiled into the
+// list.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::AddUserDefinedIdentifier(CScriptParseTreeNode *pFunctionDeclaration, BOOL bFunctionImplementation)
+{
+
+ // First, get the identifier name which should be in
+ // pLeft->pLeft->pcStringData;
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_psIdentifier) = *(pFunctionDeclaration->pLeft->pLeft->m_psStringData);
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierHash) = HashString(*(pFunctionDeclaration->pLeft->pLeft->m_psStringData));
+ (m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierLength) = pFunctionDeclaration->pLeft->pLeft->m_psStringData->GetLength();
+
+ // Return Type is in pLeft->pLeft->pLeft ... read the
+ // operation to see the type of variable.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdentifierType = 1;
+
+ int32_t nOperationReturnType = pFunctionDeclaration->pLeft->pLeft->pLeft->nOperation;
+
+ if (nOperationReturnType == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER;
+ }
+ else if (nOperationReturnType == CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER;
+ }
+ else if (nOperationReturnType == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER;
+ }
+ else if (nOperationReturnType == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER;
+ }
+ else if (nOperationReturnType == CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER;
+ }
+ else if (nOperationReturnType == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStructureReturnName = *(pFunctionDeclaration->pLeft->pLeft->pLeft->m_psStringData);
+ }
+ else if (nOperationReturnType >= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0 &&
+ nOperationReturnType <= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nReturnType = CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER + (nOperationReturnType - CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0);
+ }
+
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_FUNCTION_DECLARATION;
+ return nError;
+ }
+
+ // User defined functions NEVER have a list here.
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nIdIdentifier = -1;
+
+ // The list of function types is availble via pLeft->pRight.
+ // The list of "parameter names" spawns off to the left ...
+ // This allows us to pull the variables off of the list in
+ // reverse stack order (i.e. 3rd parameter, 2nd parameter,
+ // first parameter) when executing this as a linked list!
+ // Thus, you're going to want to count the number of
+ // parameter names first, and then trace through them and
+ // discover the variable names.
+
+ CScriptParseTreeNode *pNode = pFunctionDeclaration->pLeft->pRight;
+ int32_t nTotalParameters = 0;
+
+ while (pNode != NULL)
+ {
+ ++nTotalParameters;
+ pNode = pNode->pLeft;
+ }
+
+ while (nTotalParameters > m_pcIdentifierList[m_nOccupiedIdentifiers].m_nParameterSpace)
+ {
+ int nReturnValue = m_pcIdentifierList[m_nOccupiedIdentifiers].ExpandParameterSpace();
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ }
+
+ pNode = pFunctionDeclaration->pLeft->pRight;
+ int32_t nCurrentParameters = 0;
+ int32_t nParameterType;
+ BOOL bOptionalParametersStarted = FALSE;
+
+ // MGB - If a previous declaration and implementation match, an identifier
+ // gets removed from the stack. Thus, m_nOccupiedIdentifiers should be cleared.
+ // This is the biggest "remaining" bug, since it prevents a future function from
+ // compiling.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nParameters = 0;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nNonOptionalParameters = 0;
+
+ if (pNode != NULL)
+ {
+ while (pNode != NULL)
+ {
+ nParameterType = pNode->pRight->nOperation;
+ char nNewParameterType;
+
+ if (nParameterType == CSCRIPTCOMPILER_OPERATION_KEYWORD_INT)
+ {
+ nNewParameterType = CSCRIPTCOMPILER_TOKEN_KEYWORD_INT;
+ }
+ else if (nParameterType == CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT)
+ {
+ nNewParameterType = CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT;
+ }
+ else if (nParameterType == CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT)
+ {
+ nNewParameterType = CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT;
+ }
+ else if (nParameterType == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING)
+ {
+ nNewParameterType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING;
+ }
+ else if (nParameterType == CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID)
+ {
+ nNewParameterType = CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID;
+ }
+ else if (nParameterType == CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT)
+ {
+ nNewParameterType = CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT;
+ }
+ else if (nParameterType >= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0 &&
+ nParameterType <= CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE9)
+ {
+ nNewParameterType = (char) (CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 + (nParameterType - CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0));
+ }
+ else
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_PARSING_FUNCTION_DECLARATION;
+ return nError;
+ }
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pchParameters[nCurrentParameters] = nNewParameterType;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = FALSE;
+
+ // If we've started processing optional parameters for this function
+ // declaration, all further parameters MUST be optional. So sayeth Mark.
+
+ if (bOptionalParametersStarted == TRUE && pNode->pRight->pRight == NULL)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_OPTIONAL_PARAMETER_CANNOT_FOLLOW_OPTIONAL_PARAMETER;
+ return nError;
+ }
+
+ if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStructureParameterNames[nCurrentParameters] = *(pNode->pRight->m_psStringData);
+ if (pNode->pRight->pRight != NULL && *(pNode->pRight->m_psStringData) != "vector")
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_TYPE_DOES_NOT_HAVE_AN_OPTIONAL_PARAMETER;
+ return nError;
+ }
+ if (pNode->pRight->pRight != NULL && *(pNode->pRight->m_psStringData) == "vector")
+ {
+ CScriptParseTreeNode *pNodeToDelete = pNode->pRight->pRight;
+
+ if (pNode->pRight->pRight->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_VECTOR)
+ {
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION;
+ return nError;
+ }
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = TRUE;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pfOptionalParameterVectorData[nCurrentParameters * 3] = pNode->pRight->pRight->fVectorData[0];
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pfOptionalParameterVectorData[nCurrentParameters * 3 + 1] = pNode->pRight->pRight->fVectorData[1];
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pfOptionalParameterVectorData[nCurrentParameters * 3 + 2] = pNode->pRight->pRight->fVectorData[2];
+ bOptionalParametersStarted = TRUE;
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+ }
+ }
+ else if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_INT)
+ {
+ if (pNode->pRight->pRight != NULL)
+ {
+ CScriptParseTreeNode *pNodeToDelete = pNode->pRight->pRight;
+
+ // MGB - March 25, 2003 - May have a constant or a constant with a negation attached to
+ // its right hand branch. This piece of code should be able to handle both for integers.
+ BOOL bValidConstant = FALSE;
+
+ // Are we a valid constant?
+ if (pNode->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER ||
+ (pNode->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_NEGATION &&
+ pNode->pRight->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER))
+ {
+ bValidConstant = TRUE;
+ }
+
+ // Delete things if we are not a valid constant, and error out.
+ if (bValidConstant == FALSE)
+ {
+ pNode->pRight->pRight = NULL;
+ if (pNodeToDelete->pRight != NULL)
+ {
+ DeleteScriptParseTreeNode(pNodeToDelete->pRight);
+ }
+ pNodeToDelete->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION;
+ return nError;
+ }
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = TRUE;
+
+ if (pNode->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER)
+ {
+ // Store the fetched value.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pnOptionalParameterIntegerData[nCurrentParameters] = pNode->pRight->pRight->nIntegerData;
+ }
+ else
+ {
+ // Negate the fetched value, since we have a negation at the front of the constant.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pnOptionalParameterIntegerData[nCurrentParameters] = -(pNode->pRight->pRight->pRight->nIntegerData);
+ }
+
+ bOptionalParametersStarted = TRUE;
+
+ // Delete the appropriate nodes!
+ pNode->pRight->pRight = NULL;
+ if (pNodeToDelete->pRight != NULL)
+ {
+ DeleteScriptParseTreeNode(pNodeToDelete->pRight);
+ }
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+ }
+ }
+ else if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT)
+ {
+ if (pNode->pRight->pRight != NULL)
+ {
+ CScriptParseTreeNode *pNodeToDelete = pNode->pRight->pRight;
+
+ if (pNode->pRight->pRight->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_OBJECT)
+ {
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION;
+ return nError;
+ }
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = TRUE;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_poidOptionalParameterObjectData[nCurrentParameters] = pNode->pRight->pRight->nIntegerData;
+ bOptionalParametersStarted = TRUE;
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+
+ }
+
+ }
+ else if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT)
+ {
+ if (pNode->pRight->pRight != NULL)
+ {
+ CScriptParseTreeNode *pNodeToDelete = pNode->pRight->pRight;
+
+ // MGB - March 25, 2003 - May have a constant or a constant with a negation attached to
+ // its right hand branch. This piece of code should be able to handle both for floating points.
+ BOOL bValidConstant = FALSE;
+
+ // Are we a valid constant?
+ if (pNode->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT ||
+ (pNode->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_NEGATION &&
+ pNode->pRight->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT))
+ {
+ bValidConstant = TRUE;
+ }
+
+ // Delete things if we are not a valid constant, and error out.
+ if (bValidConstant == FALSE)
+ {
+ pNode->pRight->pRight = NULL;
+ if (pNodeToDelete->pRight != NULL)
+ {
+ DeleteScriptParseTreeNode(pNodeToDelete->pRight);
+ }
+ pNodeToDelete->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION;
+ return nError;
+ }
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = TRUE;
+
+ if (pNode->pRight->pRight->nOperation == CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT)
+ {
+ // Store the fetched value.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pfOptionalParameterFloatData[nCurrentParameters] = pNode->pRight->pRight->fFloatData;
+ }
+ else
+ {
+ // Negate the fetched value, since we have a negation at the front of the constant.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pfOptionalParameterFloatData[nCurrentParameters] = -(pNode->pRight->pRight->pRight->fFloatData);
+ }
+
+ bOptionalParametersStarted = TRUE;
+
+ // Delete the appropriate nodes!
+ pNode->pRight->pRight = NULL;
+ if (pNodeToDelete->pRight != NULL)
+ {
+ DeleteScriptParseTreeNode(pNodeToDelete->pRight);
+ }
+ DeleteScriptParseTreeNode(pNodeToDelete);
+ }
+ }
+ else if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING)
+ {
+ if (pNode->pRight->pRight != NULL)
+ {
+ CScriptParseTreeNode *pNodeToDelete = pNode->pRight->pRight;
+
+ if (pNode->pRight->pRight->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING)
+ {
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION;
+ return nError;
+ }
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = TRUE;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psOptionalParameterStringData[nCurrentParameters] = *(pNode->pRight->pRight->m_psStringData);
+ bOptionalParametersStarted = TRUE;
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+
+ }
+ }
+
+ else if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2 /* location */)
+ {
+ if (pNode->pRight->pRight != NULL)
+ {
+ CScriptParseTreeNode *pNodeToDelete = pNode->pRight->pRight;
+
+ if (pNode->pRight->pRight->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_LOCATION)
+ {
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION;
+ return nError;
+ }
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = TRUE;
+ // LOCATION constants reusing the integer data because i'm lazy. If you ever add more than LOCATION_INVALID
+ // you will probably have to expand that to carry actual locations. While you're at that, move the
+ // CScriptLocation out of sharedcore and into include/ somewhere.
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pnOptionalParameterIntegerData[nCurrentParameters] = pNode->pRight->pRight->nIntegerData;
+ bOptionalParametersStarted = TRUE;
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+ }
+ }
+
+ else if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7 /* json */)
+ {
+ if (pNode->pRight->pRight != NULL)
+ {
+ CScriptParseTreeNode *pNodeToDelete = pNode->pRight->pRight;
+
+ if (pNode->pRight->pRight->nOperation != CSCRIPTCOMPILER_OPERATION_CONSTANT_JSON)
+ {
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION;
+ return nError;
+ }
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_pbOptionalParameters[nCurrentParameters] = TRUE;
+ // Json data is loaded into the string array, same as strings. all json data is kept as raw
+ // strings while living inside the compiler; only when hitting the VM it attempts to parse.
+ // (BORLAND is too simple to understand nlohmann::json)
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_psOptionalParameterStringData[nCurrentParameters] = *pNode->pRight->pRight->m_psStringData;
+ bOptionalParametersStarted = TRUE;
+ pNode->pRight->pRight = NULL;
+ DeleteScriptParseTreeNode(pNodeToDelete);
+ }
+ }
+
+ else if (nNewParameterType == CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID ||
+ (nNewParameterType >= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 &&
+ nNewParameterType <= CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9))
+ {
+ if (pNode->pRight->pRight != NULL)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_TYPE_DOES_NOT_HAVE_AN_OPTIONAL_PARAMETER;
+ return nError;
+ }
+ }
+
+ ++nCurrentParameters;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nParameters = nCurrentParameters;
+ if (bOptionalParametersStarted == FALSE)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nNonOptionalParameters = nCurrentParameters;
+ }
+
+ pNode = pNode->pLeft;
+
+ }
+ }
+
+ // Check to see if the function is already in the list. If
+ // it is, then we don't need to do anything about this one.
+
+ int32_t nHashLocation = GetHashEntryByName(m_pcIdentifierList[m_nOccupiedIdentifiers].m_psIdentifier.CStr());
+ BOOL bFoundIdenticalFunction = FALSE;
+
+ if (nHashLocation != STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER)
+ {
+ int32_t nIdentifierType = m_pIdentifierHashTable[nHashLocation].m_nIdentifierType;
+ int32_t nIdentifierIndex = m_pIdentifierHashTable[nHashLocation].m_nIdentifierIndex;
+
+ if (nIdentifierType == CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER)
+ {
+ if (m_pcIdentifierList[nIdentifierIndex].m_nIdentifierType == 1)
+ {
+ if (m_pcIdentifierList[nIdentifierIndex].m_nParameters == m_pcIdentifierList[m_nOccupiedIdentifiers].m_nParameters)
+ {
+ BOOL bParameterListDifferent = FALSE;
+
+ int32_t count2;
+ for (count2 = 0; count2 < m_pcIdentifierList[nIdentifierIndex].m_nParameters; count2++)
+ {
+ if ((m_pcIdentifierList[nIdentifierIndex].m_pchParameters[count2] != m_pcIdentifierList[m_nOccupiedIdentifiers].m_pchParameters[count2]) ||
+ (m_pcIdentifierList[nIdentifierIndex].m_pchParameters[count2] == CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER &&
+ m_pcIdentifierList[nIdentifierIndex].m_psStructureParameterNames[count2] != m_pcIdentifierList[m_nOccupiedIdentifiers].m_psStructureParameterNames[count2]))
+ {
+ bParameterListDifferent = TRUE;
+ }
+ }
+
+ if (bParameterListDifferent == FALSE)
+ {
+ bFoundIdenticalFunction = TRUE;
+ if (bFunctionImplementation == TRUE)
+ {
+ if (m_pcIdentifierList[nIdentifierIndex].m_bImplementationInPlace == TRUE)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_DUPLICATE_FUNCTION_IMPLEMENTATION;
+ // If you don't want the name of the duplicate function.
+ //return OutputWalkTreeError(nError, NULL);
+ // If you want the name of the duplicate function, use this.
+ return OutputIdentifierError(m_pcIdentifierList[nIdentifierIndex].m_psIdentifier,nError,1);
+ }
+ else
+ {
+ m_pcIdentifierList[nIdentifierIndex].m_bImplementationInPlace = TRUE;
+ }
+ }
+ }
+ }
+
+ // If the function name is the same, it better be identical, or
+ // we should gork right here.
+ if (bFoundIdenticalFunction == FALSE)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_IMPLEMENTATION_AND_DEFINITION_DIFFER;
+ return nError;
+ }
+
+ }
+ }
+ }
+
+
+ if (bFoundIdenticalFunction == FALSE)
+ {
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_bImplementationInPlace = bFunctionImplementation;
+
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceStart = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinarySourceFinish = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationStart = -1;
+ m_pcIdentifierList[m_nOccupiedIdentifiers].m_nBinaryDestinationFinish = -1;
+
+ HashManagerAdd(CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER, m_nOccupiedIdentifiers);
+
+ m_nOccupiedIdentifiers++;
+ if (m_nOccupiedIdentifiers >= CSCRIPTCOMPILER_MAX_IDENTIFIERS)
+ {
+ int nError = STRREF_CSCRIPTCOMPILER_ERROR_IDENTIFIER_LIST_FULL;
+ return nError;
+ }
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::AddToGlobalVariableList
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/09/2001
+// Description: Adds the current statement to the global variable compile tree.
+///////////////////////////////////////////////////////////////////////////////
+int32_t CScriptCompiler::AddToGlobalVariableList(CScriptParseTreeNode *pGlobalVariableNode)
+{
+ if (m_pGlobalVariableParseTree == NULL)
+ {
+ CScriptParseTreeNode *pNewNode = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_GLOBAL_VARIABLES,NULL,NULL);
+ m_pGlobalVariableParseTree = pNewNode;
+ }
+
+ // Create a new "statement" for this declaration.
+ CScriptParseTreeNode *pNewNode2 = CreateScriptParseTreeNode(CSCRIPTCOMPILER_OPERATION_STATEMENT,pGlobalVariableNode,NULL);
+
+ // This guarantees the connection will be made between the variable
+ // declaration and the line it is on, not the line the statement
+ // terminates on.
+ if (pGlobalVariableNode != NULL)
+ {
+ pNewNode2->nLine = pGlobalVariableNode->nLine;
+ }
+
+
+ // Look for the last statement in the list of statements and attach
+ // this node to them.
+ CScriptParseTreeNode *pFindLastStatement = m_pGlobalVariableParseTree;
+
+ while (pFindLastStatement->pRight != NULL)
+ {
+ pFindLastStatement = pFindLastStatement->pRight;
+ }
+
+ pFindLastStatement->pRight = pNewNode2;
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::PrintParseSourceError()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/15/2001
+// Description: This routine will generate an error log based on the value
+// passed in.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::PrintParseSourceError(int32_t nParsingError)
+{
+ CExoString strRes = m_cAPI.TlkResolve(-nParsingError);
+
+ CExoString *psFileName = &(m_pcIncludeFileStack[m_nCompileFileLevel-1].m_sCompiledScriptName);
+ CExoString sErrorText;
+
+ if (nParsingError != STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER)
+ {
+ sErrorText.Format("%s",strRes.CStr());
+ }
+ else
+ {
+ sErrorText.Format("%s (%s)",strRes.CStr(),m_sUndefinedIdentifier.CStr());
+ }
+
+ OutputError(nParsingError,psFileName,m_nLines,sErrorText);
+
+ nParsingError = STRREF_CSCRIPTCOMPILER_ERROR_ALREADY_PRINTED;
+
+ return CleanUpDuringCompile(nParsingError);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::DeleteCompileStack()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 08/05/99
+// Description: This routine will delete all of the nodes that can be
+// accessed from the compiler's run time stack.
+///////////////////////////////////////////////////////////////////////////////
+
+void CScriptCompiler::DeleteCompileStack()
+{
+ int32_t i;
+ for (i=0; i <= m_nSRStackStates; i++)
+ {
+ if (m_pSRStack[i].pCurrentTree != NULL)
+ {
+ DeleteParseTree(TRUE,m_pSRStack[i].pCurrentTree);
+ }
+ if (m_pSRStack[i].pReturnTree != NULL)
+ {
+ DeleteParseTree(TRUE,m_pSRStack[i].pReturnTree);
+ }
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::CleanUpDuringCompile()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/26/2000
+// Description: This routine will delete all of the data associated with the
+// current compile that is going on.
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::CleanUpDuringCompile(int32_t nReturnValue)
+{
+ DeleteCompileStack();
+ --m_nCompileFileLevel;
+ if (m_nCompileFileLevel > 0)
+ {
+ ShutdownIncludeFile(m_nCompileFileLevel);
+ }
+ DeleteParseTree(FALSE, m_pGlobalVariableParseTree);
+ m_pGlobalVariableParseTree = NULL;
+ ClearUserDefinedIdentifiers();
+ ClearAllSymbolLists();
+ return nReturnValue;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CScriptCompiler::ParseSource()
+///////////////////////////////////////////////////////////////////////////////
+// Created By: Mark Brockington
+// Created On: 01/15/2001
+// Description: This routine will generate a parse tree from the string
+// specified in pScript (of length nScriptLength).
+///////////////////////////////////////////////////////////////////////////////
+
+int32_t CScriptCompiler::ParseSource(char *pScript, int32_t nScriptLength)
+{
+
+ int32_t i; // location in the string
+ int32_t nParseNextCharReturn; // returned value from ParseNextCharacter
+
+ int32_t ch; // character at location pScript[i]
+ int32_t chNext; // character at location pScript[i+1]. Yes, I freakin' cheat and
+ // look ahead a character. Gonna make something out of it, weasel boy?
+ // I didn't think so.
+
+ if (m_nOccupiedIdentifiers == 0)
+ {
+ int32_t nReturnValue = ParseIdentifierFile();
+ if (nReturnValue < 0)
+ {
+ return nReturnValue;
+ }
+ }
+
+ ///////////////////////////////////////////////
+ //
+ // Initialize with the first two characters.
+ //
+ ///////////////////////////////////////////////
+
+ if ( nScriptLength < 1 )
+ {
+ ch = -1;
+ }
+ else
+ {
+ ch = pScript[0];
+ }
+
+ if ( nScriptLength < 2 )
+ {
+ chNext = -1;
+ }
+ else
+ {
+ chNext = pScript[1];
+ }
+
+ i = 2;
+
+ ///////////////////////////////////////////////
+ //
+ // Loop through all remaining characters.
+ //
+ ///////////////////////////////////////////////
+
+ while (ch != -1)
+ {
+ nParseNextCharReturn = ParseNextCharacter(ch,chNext,pScript + i,nScriptLength - i);
+
+ if (nParseNextCharReturn < 0)
+ {
+ return PrintParseSourceError(nParseNextCharReturn);
+ }
+
+ while (nParseNextCharReturn >= 0)
+ {
+ // Process the location of the next character.
+ if (ch == '\n')
+ {
+ ++m_nLines;
+ m_nCharacterOnLine = 1;
+ }
+ else
+ {
+ ++m_nCharacterOnLine;
+ }
+
+ // Fetch the "next" character and update the status
+ // of the current character that we are looking at.
+ ch = chNext;
+
+ if ( i >= nScriptLength )
+ {
+ chNext = -1;
+ }
+ else
+ {
+ chNext = (unsigned char) pScript[i];
+ }
+
+ --nParseNextCharReturn;
+
+ ++i;
+ }
+
+ }
+
+ ///////////////////////////////////////////////
+ //
+ // Parse an EOF.
+ //
+ ///////////////////////////////////////////////
+
+ nParseNextCharReturn = ParseNextCharacter(-1,-1, nullptr, 0);
+
+ if (nParseNextCharReturn < 0)
+ {
+
+ return PrintParseSourceError(nParseNextCharReturn);
+ }
+
+ return 0;
+}
diff --git a/src/Native Compiler/scripterrors.h b/src/Native Compiler/scripterrors.h
new file mode 100644
index 0000000..19cc4f2
--- /dev/null
+++ b/src/Native Compiler/scripterrors.h
@@ -0,0 +1,175 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Script Project
+//::
+//:: Copyright (c) 2002, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ScriptErrors.h
+//::
+//:: A project-specific header file, specifying error constants that relate
+//:: to string references in the game code.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: Oct. 24, 2002
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+// All error codes in the following file relate to negative values of string references.
+
+#ifndef __SCRIPTERRORS_H__
+#define __SCRIPTERRORS_H__
+
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_CHARACTER -560
+#define STRREF_CSCRIPTCOMPILER_ERROR_FATAL_COMPILER_ERROR -561
+#define STRREF_CSCRIPTCOMPILER_ERROR_PROGRAM_COMPOUND_STATEMENT_AT_START -562
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNEXPECTED_END_COMPOUND_STATEMENT -563
+#define STRREF_CSCRIPTCOMPILER_ERROR_AFTER_COMPOUND_STATEMENT_AT_END -564
+#define STRREF_CSCRIPTCOMPILER_ERROR_PARSING_VARIABLE_LIST -565
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_STATE_IN_COMPILER -566
+#define STRREF_CSCRIPTCOMPILER_ERROR_INVALID_DECLARATION_TYPE -567
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_EXPRESSION -568
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_EXPRESSION -569
+#define STRREF_CSCRIPTCOMPILER_ERROR_BAD_START_OF_STATEMENT -570
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_LEFT_BRACKET_ON_ARG_LIST -571
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_RIGHT_BRACKET_ON_ARG_LIST -572
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_EXPRESSION -573
+#define STRREF_CSCRIPTCOMPILER_ERROR_PARSING_ASSIGNMENT_STATEMENT -574
+#define STRREF_CSCRIPTCOMPILER_ERROR_BAD_LVALUE -575
+#define STRREF_CSCRIPTCOMPILER_ERROR_BAD_CONSTANT_TYPE -576
+#define STRREF_CSCRIPTCOMPILER_ERROR_IDENTIFIER_LIST_FULL -577
+#define STRREF_CSCRIPTCOMPILER_ERROR_NON_INTEGER_ID_FOR_INTEGER_CONSTANT -578
+#define STRREF_CSCRIPTCOMPILER_ERROR_NON_FLOAT_ID_FOR_FLOAT_CONSTANT -579
+#define STRREF_CSCRIPTCOMPILER_ERROR_NON_STRING_ID_FOR_STRING_CONSTANT -580
+#define STRREF_CSCRIPTCOMPILER_ERROR_VARIABLE_ALREADY_USED_WITHIN_SCOPE -581
+#define STRREF_CSCRIPTCOMPILER_ERROR_VARIABLE_DEFINED_WITHOUT_TYPE -582
+#define STRREF_CSCRIPTCOMPILER_ERROR_INCORRECT_VARIABLE_STATE_LEFT_ON_STACK -583
+#define STRREF_CSCRIPTCOMPILER_ERROR_NON_INTEGER_EXPRESSION_WHERE_INTEGER_REQUIRED -584
+#define STRREF_CSCRIPTCOMPILER_ERROR_VOID_EXPRESSION_WHERE_NON_VOID_REQUIRED -585
+#define STRREF_CSCRIPTCOMPILER_ERROR_INVALID_PARAMETERS_FOR_ASSIGNMENT -586
+#define STRREF_CSCRIPTCOMPILER_ERROR_DECLARATION_DOES_NOT_MATCH_PARAMETERS -587
+#define STRREF_CSCRIPTCOMPILER_ERROR_LOGICAL_OPERATION_HAS_INVALID_OPERANDS -588
+#define STRREF_CSCRIPTCOMPILER_ERROR_EQUALITY_TEST_HAS_INVALID_OPERANDS -589
+#define STRREF_CSCRIPTCOMPILER_ERROR_COMPARISON_TEST_HAS_INVALID_OPERANDS -590
+#define STRREF_CSCRIPTCOMPILER_ERROR_SHIFT_OPERATION_HAS_INVALID_OPERANDS -591
+#define STRREF_CSCRIPTCOMPILER_ERROR_ARITHMETIC_OPERATION_HAS_INVALID_OPERANDS -592
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNKNOWN_OPERATION_IN_SEMANTIC_CHECK -593
+#define STRREF_CSCRIPTCOMPILER_ERROR_SCRIPT_TOO_LARGE -594
+#define STRREF_CSCRIPTCOMPILER_ERROR_RETURN_STATEMENT_HAS_NO_PARAMETERS -595
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_WHILE_AFTER_DO_KEYWORD -596
+#define STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_DEFINITION_MISSING_NAME -597
+#define STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_DEFINITION_MISSING_PARAMETER_LIST -598
+#define STRREF_CSCRIPTCOMPILER_ERROR_MALFORMED_PARAMETER_LIST -599
+#define STRREF_CSCRIPTCOMPILER_ERROR_BAD_TYPE_SPECIFIER -600
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_STRUCTURE -601
+#define STRREF_CSCRIPTCOMPILER_ERROR_ELLIPSIS_IN_IDENTIFIER -602
+#define STRREF_CSCRIPTCOMPILER_ERROR_FILE_NOT_FOUND -603
+#define STRREF_CSCRIPTCOMPILER_ERROR_INCLUDE_RECURSIVE -604
+#define STRREF_CSCRIPTCOMPILER_ERROR_INCLUDE_TOO_MANY_LEVELS -605
+#define STRREF_CSCRIPTCOMPILER_ERROR_PARSING_RETURN_STATEMENT -606
+#define STRREF_CSCRIPTCOMPILER_ERROR_PARSING_IDENTIFIER_LIST -607
+#define STRREF_CSCRIPTCOMPILER_ERROR_PARSING_FUNCTION_DECLARATION -608
+#define STRREF_CSCRIPTCOMPILER_ERROR_DUPLICATE_FUNCTION_IMPLEMENTATION -609
+#define STRREF_CSCRIPTCOMPILER_ERROR_TOKEN_TOO_LONG -610
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_STRUCTURE -611
+#define STRREF_CSCRIPTCOMPILER_ERROR_LEFT_OF_STRUCTURE_PART_NOT_STRUCTURE - 612
+#define STRREF_CSCRIPTCOMPILER_ERROR_RIGHT_OF_STRUCTURE_PART_NOT_FIELD_IN_STRUCTURE -613
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_FIELD_IN_STRUCTURE -614
+#define STRREF_CSCRIPTCOMPILER_ERROR_STRUCTURE_REDEFINED -615
+#define STRREF_CSCRIPTCOMPILER_ERROR_VARIABLE_USED_TWICE_IN_SAME_STRUCTURE -616
+#define STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_IMPLEMENTATION_AND_DEFINITION_DIFFER -617
+#define STRREF_CSCRIPTCOMPILER_ERROR_MISMATCHED_TYPES -618
+#define STRREF_CSCRIPTCOMPILER_ERROR_INTEGER_NOT_AT_TOP_OF_STACK -619
+#define STRREF_CSCRIPTCOMPILER_ERROR_RETURN_TYPE_AND_FUNCTION_TYPE_MISMATCHED -620
+#define STRREF_CSCRIPTCOMPILER_ERROR_NOT_ALL_CONTROL_PATHS_RETURN_A_VALUE -621
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNDEFINED_IDENTIFIER -622
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_FUNCTION_MAIN_IN_SCRIPT -623
+#define STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_MAIN_MUST_HAVE_VOID_RETURN_VALUE -624
+#define STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_MAIN_MUST_HAVE_NO_PARAMETERS -625
+#define STRREF_CSCRIPTCOMPILER_ERROR_NON_VOID_FUNCTION_CANNOT_BE_A_STATEMENT -626
+#define STRREF_CSCRIPTCOMPILER_ERROR_BAD_VARIABLE_NAME -627
+#define STRREF_CSCRIPTCOMPILER_ERROR_NON_OPTIONAL_PARAMETER_CANNOT_FOLLOW_OPTIONAL_PARAMETER -628
+#define STRREF_CSCRIPTCOMPILER_ERROR_TYPE_DOES_NOT_HAVE_AN_OPTIONAL_PARAMETER -629
+#define STRREF_CSCRIPTCOMPILER_ERROR_NON_CONSTANT_IN_FUNCTION_DECLARATION -630
+#define STRREF_CSCRIPTCOMPILER_ERROR_PARSING_CONSTANT_VECTOR -631
+#define STRREF_CSCRIPTCOMPILER_ERROR_OPERAND_MUST_BE_AN_INTEGER_LVALUE -1594
+#define STRREF_CSCRIPTCOMPILER_ERROR_CONDITIONAL_REQUIRES_SECOND_EXPRESSION -1595
+#define STRREF_CSCRIPTCOMPILER_ERROR_CONDITIONAL_MUST_HAVE_MATCHING_RETURN_TYPES -1596
+#define STRREF_CSCRIPTCOMPILER_ERROR_MULTIPLE_DEFAULT_STATEMENTS_WITHIN_SWITCH -1597
+#define STRREF_CSCRIPTCOMPILER_ERROR_MULTIPLE_CASE_CONSTANT_STATEMENTS_WITHIN_SWITCH -1598
+#define STRREF_CSCRIPTCOMPILER_ERROR_CASE_PARAMETER_NOT_A_CONSTANT_INTEGER -1599
+#define STRREF_CSCRIPTCOMPILER_ERROR_SWITCH_MUST_EVALUATE_TO_AN_INTEGER -1600
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_COLON_AFTER_DEFAULT_LABEL -1601
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_COLON_AFTER_CASE_LABEL -1602
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_SEMICOLON_AFTER_STATEMENT -1603
+#define STRREF_CSCRIPTCOMPILER_ERROR_BREAK_OUTSIDE_OF_LOOP_OR_CASE_STATEMENT -4834
+#define STRREF_CSCRIPTCOMPILER_ERROR_TOO_MANY_PARAMETERS_ON_FUNCTION -4835
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNABLE_TO_OPEN_FILE_FOR_WRITING -4836
+#define STRREF_CSCRIPTCOMPILER_ERROR_UNTERMINATED_STRING_CONSTANT -4855
+#define STRREF_CSCRIPTCOMPILER_ERROR_NO_FUNCTION_INTSC_IN_SCRIPT -5182
+#define STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_INTSC_MUST_HAVE_VOID_RETURN_VALUE -5183
+#define STRREF_CSCRIPTCOMPILER_ERROR_FUNCTION_INTSC_MUST_HAVE_NO_PARAMETERS -5184
+#define STRREF_CSCRIPTCOMPILER_ERROR_JUMPING_OVER_DECLARATION_STATEMENTS_CASE_DISALLOWED -6804
+#define STRREF_CSCRIPTCOMPILER_ERROR_JUMPING_OVER_DECLARATION_STATEMENTS_DEFAULT_DISALLOWED -6805
+#define STRREF_CSCRIPTCOMPILER_ERROR_ELSE_WITHOUT_CORRESPONDING_IF -6823
+#define STRREF_CSCRIPTCOMPILER_ERROR_IF_CONDITION_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT -10407
+// New Errors!
+#define STRREF_CSCRIPTCOMPILER_ERROR_INVALID_TYPE_FOR_CONST_KEYWORD -3741
+#define STRREF_CSCRIPTCOMPILER_ERROR_CONST_KEYWORD_CANNOT_BE_USED_ON_NON_GLOBAL_VARIABLES -3742
+#define STRREF_CSCRIPTCOMPILER_ERROR_INVALID_VALUE_ASSIGNED_TO_CONSTANT -3752
+#define STRREF_CSCRIPTCOMPILER_ERROR_SWITCH_CONDITION_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT -9081
+#define STRREF_CSCRIPTCOMPILER_ERROR_WHILE_CONDITION_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT -9082
+#define STRREF_CSCRIPTCOMPILER_ERROR_FOR_STATEMENT_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT -9083
+#define STRREF_CSCRIPTCOMPILER_ERROR_CANNOT_INCLUDE_THIS_FILE_TWICE -9155
+#define STRREF_CSCRIPTCOMPILER_ERROR_ELSE_CANNOT_BE_FOLLOWED_BY_A_NULL_STATEMENT -40104
+
+#define STRREF_CVIRTUALMACHINE_ERROR_TOO_MANY_INSTRUCTIONS -632
+#define STRREF_CVIRTUALMACHINE_ERROR_TOO_MANY_LEVELS_OF_RECURSION -633
+#define STRREF_CVIRTUALMACHINE_ERROR_FILE_NOT_OPENED -634
+#define STRREF_CVIRTUALMACHINE_ERROR_FILE_NOT_COMPILED_SUCCESSFULLY -635
+#define STRREF_CVIRTUALMACHINE_ERROR_INVALID_AUX_CODE -636
+#define STRREF_CVIRTUALMACHINE_ERROR_NULL_VIRTUAL_MACHINE_NODE -637
+#define STRREF_CVIRTUALMACHINE_ERROR_STACK_OVERFLOW -638
+#define STRREF_CVIRTUALMACHINE_ERROR_STACK_UNDERFLOW -639
+#define STRREF_CVIRTUALMACHINE_ERROR_INVALID_OP_CODE -640
+#define STRREF_CVIRTUALMACHINE_ERROR_INVALID_EXTRA_DATA_ON_OP_CODE -641
+#define STRREF_CVIRTUALMACHINE_ERROR_INVALID_COMMAND -642
+#define STRREF_CVIRTUALMACHINE_ERROR_FAKE_SHORTCUT_LOGICAL_OPERATION -643
+#define STRREF_CVIRTUALMACHINE_ERROR_DIVIDE_BY_ZERO -644
+#define STRREF_CVIRTUALMACHINE_ERROR_FAKE_ABORT_SCRIPT -645
+#define STRREF_CVIRTUALMACHINE_ERROR_IP_OUT_OF_CODE_SEGMENT -646
+#define STRREF_CVIRTUALMACHINE_ERROR_COMMAND_IMPLEMENTER_NOT_SET -647
+#define STRREF_CVIRTUALMACHINE_ERROR_UNKNOWN_TYPE_ON_RUN_TIME_STACK -648
+
+// This is not actually a string reference, but a separate error code
+// to prevent the same error from being reported inside an include file
+// and in the main file that contains the include. So, you don't have to
+// put this one into the string table.
+// THIS ERROR CAN NOT MATCH ANY OF THE OTHER ERRORS LISTED IN THIS FILE!
+#define STRREF_CSCRIPTCOMPILER_ERROR_ALREADY_PRINTED -1
+
+#endif // __SCRIPTERRORS_H__
diff --git a/src/Native Compiler/scriptinternal.h b/src/Native Compiler/scriptinternal.h
new file mode 100644
index 0000000..fb2f7d3
--- /dev/null
+++ b/src/Native Compiler/scriptinternal.h
@@ -0,0 +1,772 @@
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+// This file is part of the NWScript compiler open source release.
+//
+// The initial source release is licensed under GPL-3.0.
+//
+// All subsequent changes you submit are required to be licensed under MIT.
+//
+// However, the project overall will still be GPL-3.0.
+//
+// The intent is for the base game to be able to pick up changes you explicitly
+// submit for inclusion painlessly, while ensuring the overall project source code
+// remains available for everyone.
+//
+
+///////////////////////////////////////////////////////////////////////////////
+// BIOWARE CORP. CONFIDENTIAL INFORMATION. //
+// COPYRIGHT BIOWARE CORP. ALL RIGHTS RESERVED //
+///////////////////////////////////////////////////////////////////////////////
+
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Script Project
+//::
+//:: Copyright (c) 2002, BioWare Corp.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: ScriptInternal.h
+//::
+//:: Header file for constants and non-exposed classes used inside Script
+//:: project.
+//::
+//::///////////////////////////////////////////////////////////////////////////
+//::
+//:: Created By: Mark Brockington
+//:: Created On: Oct. 8, 2002
+//::
+//::///////////////////////////////////////////////////////////////////////////
+
+#ifndef __SCRIPTINTERNAL_H__
+#define __SCRIPTINTERNAL_H__
+
+#define CSCRIPTCOMPILER_MAX_STACK_ENTRIES 1024
+#define CSCRIPTCOMPILER_MAX_OPERATIONS 88
+#define CSCRIPTCOMPILER_MAX_IDENTIFIERS 65536
+#define CSCRIPTCOMPILER_SIZE_IDENTIFIER_HASH_TABLE 131072 // NOTE: This should be larger than MAX_IDENTIFIERS
+#define CSCRIPTCOMPILER_MASK_SIZE_IDENTIFIER_HASH_TABLE 0x0001ffff
+#define CSCRIPTCOMPILER_MAX_VARIABLES 1024
+#define CSCRIPTCOMPILER_MAX_CODE_SIZE 524288 // 512K.
+#define CSCRIPTCOMPILER_MAX_DEBUG_OUTPUT_SIZE 2097152 // 2048K, 1048576 = 1024K.
+#define CSCRIPTCOMPILER_MAX_STRUCTURES 256
+#define CSCRIPTCOMPILER_MAX_STRUCTURE_FIELDS 4096
+#define CSCRIPTCOMPILER_MAX_KEYWORDS 42
+
+#define CSCRIPTCOMPILER_BINARY_ADDRESS_LENGTH 13
+
+
+#define CSCRIPTCOMPILER_TOKEN_UNKNOWN 0
+#define CSCRIPTCOMPILER_TOKEN_DIVIDE 1
+#define CSCRIPTCOMPILER_TOKEN_CPLUSCOMMENT 2
+#define CSCRIPTCOMPILER_TOKEN_CCOMMENT 3
+#define CSCRIPTCOMPILER_TOKEN_INTEGER 4
+#define CSCRIPTCOMPILER_TOKEN_FLOAT 5
+#define CSCRIPTCOMPILER_TOKEN_IDENTIFIER 6
+#define CSCRIPTCOMPILER_TOKEN_STRING 7
+#define CSCRIPTCOMPILER_TOKEN_LOGICAL_AND 8
+#define CSCRIPTCOMPILER_TOKEN_LOGICAL_OR 9
+#define CSCRIPTCOMPILER_TOKEN_MINUS 10
+#define CSCRIPTCOMPILER_TOKEN_LEFT_BRACE 11
+#define CSCRIPTCOMPILER_TOKEN_RIGHT_BRACE 12
+#define CSCRIPTCOMPILER_TOKEN_LEFT_BRACKET 13
+#define CSCRIPTCOMPILER_TOKEN_RIGHT_BRACKET 14
+#define CSCRIPTCOMPILER_TOKEN_SEMICOLON 15
+#define CSCRIPTCOMPILER_TOKEN_COMMA 16
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_IF 17
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ELSE 18
+#define CSCRIPTCOMPILER_TOKEN_EOF 19
+#define CSCRIPTCOMPILER_TOKEN_COND_GREATER_EQUAL 20
+#define CSCRIPTCOMPILER_TOKEN_COND_LESS_EQUAL 21
+#define CSCRIPTCOMPILER_TOKEN_COND_GREATER_THAN 22
+#define CSCRIPTCOMPILER_TOKEN_COND_LESS_THAN 23
+#define CSCRIPTCOMPILER_TOKEN_COND_NOT_EQUAL 24
+#define CSCRIPTCOMPILER_TOKEN_COND_EQUAL 25
+#define CSCRIPTCOMPILER_TOKEN_PLUS 26
+#define CSCRIPTCOMPILER_TOKEN_MODULUS 27
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_EQUAL 28
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_INT 29
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_FLOAT 30
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_STRING 31
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT 32
+#define CSCRIPTCOMPILER_TOKEN_VARIABLE 33
+#define CSCRIPTCOMPILER_TOKEN_INTEGER_IDENTIFIER 34
+#define CSCRIPTCOMPILER_TOKEN_FLOAT_IDENTIFIER 35
+#define CSCRIPTCOMPILER_TOKEN_STRING_IDENTIFIER 36
+#define CSCRIPTCOMPILER_TOKEN_OBJECT_IDENTIFIER 37
+#define CSCRIPTCOMPILER_TOKEN_VOID_IDENTIFIER 38
+#define CSCRIPTCOMPILER_TOKEN_INCLUSIVE_OR 39
+#define CSCRIPTCOMPILER_TOKEN_EXCLUSIVE_OR 40
+#define CSCRIPTCOMPILER_TOKEN_BOOLEAN_AND 41
+#define CSCRIPTCOMPILER_TOKEN_SHIFT_LEFT 42
+#define CSCRIPTCOMPILER_TOKEN_SHIFT_RIGHT 43
+#define CSCRIPTCOMPILER_TOKEN_MULTIPLY 44
+#define CSCRIPTCOMPILER_TOKEN_HEX_INTEGER 45
+#define CSCRIPTCOMPILER_TOKEN_UNSIGNED_SHIFT_RIGHT 46
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ACTION 47
+#define CSCRIPTCOMPILER_TOKEN_TILDE 48
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_RETURN 49
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_WHILE 50
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_FOR 51
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_DO 52
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_VOID 53
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_STRUCT 54
+#define CSCRIPTCOMPILER_TOKEN_STRUCTURE_PART_SPECIFY 55
+#define CSCRIPTCOMPILER_TOKEN_STRUCTURE_IDENTIFIER 56
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_INCLUDE 57
+#define CSCRIPTCOMPILER_TOKEN_BOOLEAN_NOT 58
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_VECTOR 59
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFINE 60
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_NUM_STRUCTURES_DEFINITION 61
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE_DEFINITION 62
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE0 63
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE1 64
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE2 65
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE3 66
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE4 67
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE5 68
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE6 69
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE7 70
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE8 71
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_ENGINE_STRUCTURE9 72
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE0_IDENTIFIER 73
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE1_IDENTIFIER 74
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE2_IDENTIFIER 75
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE3_IDENTIFIER 76
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE4_IDENTIFIER 77
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE5_IDENTIFIER 78
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE6_IDENTIFIER 79
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE7_IDENTIFIER 80
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE8_IDENTIFIER 81
+#define CSCRIPTCOMPILER_TOKEN_ENGINE_STRUCTURE9_IDENTIFIER 82
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_SELF 83
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_OBJECT_INVALID 84
+#define CSCRIPTCOMPILER_TOKEN_VECTOR_IDENTIFIER 85
+#define CSCRIPTCOMPILER_TOKEN_LEFT_SQUARE_BRACKET 86
+#define CSCRIPTCOMPILER_TOKEN_RIGHT_SQUARE_BRACKET 87
+#define CSCRIPTCOMPILER_TOKEN_INCREMENT 88
+#define CSCRIPTCOMPILER_TOKEN_DECREMENT 89
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MINUS 90
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_PLUS 91
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MULTIPLY 92
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_DIVIDE 93
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_MODULUS 94
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_AND 95
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_XOR 96
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_OR 97
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_LEFT 98
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_SHIFT_RIGHT 99
+#define CSCRIPTCOMPILER_TOKEN_ASSIGNMENT_USHIFT_RIGHT 100
+#define CSCRIPTCOMPILER_TOKEN_QUESTION_MARK 101
+#define CSCRIPTCOMPILER_TOKEN_COLON 102
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_CASE 103
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_BREAK 104
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_SWITCH 105
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_DEFAULT 106
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_CONTINUE 107
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_CONST 108
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_NULL 109
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_FALSE 110
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_TRUE 111
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_OBJECT 112
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_ARRAY 113
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_JSON_STRING 114
+#define CSCRIPTCOMPILER_TOKEN_KEYWORD_LOCATION_INVALID 115
+#define CSCRIPTCOMPILER_TOKEN_RAW_STRING 116
+
+const char *TokenKeywordToString(int nTokenKeyword);
+
+#define CSCRIPTCOMPILER_GRAMMAR_PROGRAM 0
+#define CSCRIPTCOMPILER_GRAMMAR_FUNCTIONAL_UNIT 1
+#define CSCRIPTCOMPILER_GRAMMAR_AFTER_PROGRAM 2
+#define CSCRIPTCOMPILER_GRAMMAR_FUNCTION_PARAM_LIST 3
+#define CSCRIPTCOMPILER_GRAMMAR_AFTER_FUNCTION_PARAM 4
+#define CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_LIST 5
+#define CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST 6
+#define CSCRIPTCOMPILER_GRAMMAR_NON_INIT_DECL_VARLIST_SEPARATOR 7
+#define CSCRIPTCOMPILER_GRAMMAR_WITHIN_COMPOUND_STATEMENT 8
+#define CSCRIPTCOMPILER_GRAMMAR_WITHIN_STATEMENT_LIST 9
+#define CSCRIPTCOMPILER_GRAMMAR_WITHIN_A_STATEMENT 10
+#define CSCRIPTCOMPILER_GRAMMAR_ANY_TYPE_SPECIFIER 11
+#define CSCRIPTCOMPILER_GRAMMAR_NON_VOID_TYPE_SPECIFIER 12
+#define CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST 13
+#define CSCRIPTCOMPILER_GRAMMAR_DECL_VARLIST_SEPARATOR 14
+#define CSCRIPTCOMPILER_GRAMMAR_ARGUMENT_EXPRESSION_LIST 15
+#define CSCRIPTCOMPILER_GRAMMAR_AFTER_ARGUMENT_EXPRESSION 16
+#define CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_EXPRESSION 17
+#define CSCRIPTCOMPILER_GRAMMAR_NON_VOID_EXPRESSION 18
+#define CSCRIPTCOMPILER_GRAMMAR_EXPRESSION 19
+#define CSCRIPTCOMPILER_GRAMMAR_ASSIGNMENT_EXPRESSION 20
+#define CSCRIPTCOMPILER_GRAMMAR_CONDITIONAL_EXPRESSION 21
+#define CSCRIPTCOMPILER_GRAMMAR_LOGICAL_OR_EXPRESSION 22
+#define CSCRIPTCOMPILER_GRAMMAR_LOGICAL_AND_EXPRESSION 23
+#define CSCRIPTCOMPILER_GRAMMAR_INCLUSIVE_OR_EXPRESSION 24
+#define CSCRIPTCOMPILER_GRAMMAR_EXCLUSIVE_OR_EXPRESSION 25
+#define CSCRIPTCOMPILER_GRAMMAR_BOOLEAN_AND_EXPRESSION 26
+#define CSCRIPTCOMPILER_GRAMMAR_EQUALITY_EXPRESSION 27
+#define CSCRIPTCOMPILER_GRAMMAR_RELATIONAL_EXPRESSION 28
+#define CSCRIPTCOMPILER_GRAMMAR_SHIFT_EXPRESSION 29
+#define CSCRIPTCOMPILER_GRAMMAR_ADDITIVE_EXPRESSION 30
+#define CSCRIPTCOMPILER_GRAMMAR_MULTIPLICATIVE_EXPRESSION 31
+#define CSCRIPTCOMPILER_GRAMMAR_UNARY_EXPRESSION 32
+#define CSCRIPTCOMPILER_GRAMMAR_POST_EXPRESSION 33
+#define CSCRIPTCOMPILER_GRAMMAR_PRIMARY_EXPRESSION 34
+#define CSCRIPTCOMPILER_GRAMMAR_CONSTANT 35
+
+const char *GrammarToString(int nGrammar);
+
+#define CSCRIPTCOMPILER_OPERATION_COMPOUND_STATEMENT 0
+#define CSCRIPTCOMPILER_OPERATION_STATEMENT 1
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_DECLARATION 2
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_INT 3
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_FLOAT 4
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_STRING 5
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_OBJECT 6
+#define CSCRIPTCOMPILER_OPERATION_VARIABLE_LIST 7
+#define CSCRIPTCOMPILER_OPERATION_VARIABLE 8
+#define CSCRIPTCOMPILER_OPERATION_STATEMENT_LIST 9
+#define CSCRIPTCOMPILER_OPERATION_IF_BLOCK 10
+#define CSCRIPTCOMPILER_OPERATION_IF_CHOICE 11
+#define CSCRIPTCOMPILER_OPERATION_IF_CONDITION 12
+#define CSCRIPTCOMPILER_OPERATION_ACTION 13
+#define CSCRIPTCOMPILER_OPERATION_ACTION_ID 14
+#define CSCRIPTCOMPILER_OPERATION_ASSIGNMENT 15
+#define CSCRIPTCOMPILER_OPERATION_ACTION_ARG_LIST 16
+#define CSCRIPTCOMPILER_OPERATION_CONSTANT_INTEGER 17
+#define CSCRIPTCOMPILER_OPERATION_CONSTANT_FLOAT 18
+#define CSCRIPTCOMPILER_OPERATION_CONSTANT_STRING 19
+#define CSCRIPTCOMPILER_OPERATION_INTEGER_EXPRESSION 20
+#define CSCRIPTCOMPILER_OPERATION_NON_VOID_EXPRESSION 21
+#define CSCRIPTCOMPILER_OPERATION_LOGICAL_OR 22
+#define CSCRIPTCOMPILER_OPERATION_LOGICAL_AND 23
+#define CSCRIPTCOMPILER_OPERATION_INCLUSIVE_OR 24
+#define CSCRIPTCOMPILER_OPERATION_EXCLUSIVE_OR 25
+#define CSCRIPTCOMPILER_OPERATION_BOOLEAN_AND 26
+#define CSCRIPTCOMPILER_OPERATION_CONDITION_EQUAL 27
+#define CSCRIPTCOMPILER_OPERATION_CONDITION_NOT_EQUAL 28
+#define CSCRIPTCOMPILER_OPERATION_CONDITION_GEQ 29
+#define CSCRIPTCOMPILER_OPERATION_CONDITION_GT 30
+#define CSCRIPTCOMPILER_OPERATION_CONDITION_LT 31
+#define CSCRIPTCOMPILER_OPERATION_CONDITION_LEQ 32
+#define CSCRIPTCOMPILER_OPERATION_SHIFT_LEFT 33
+#define CSCRIPTCOMPILER_OPERATION_SHIFT_RIGHT 34
+#define CSCRIPTCOMPILER_OPERATION_ADD 35
+#define CSCRIPTCOMPILER_OPERATION_SUBTRACT 36
+#define CSCRIPTCOMPILER_OPERATION_MULTIPLY 37
+#define CSCRIPTCOMPILER_OPERATION_DIVIDE 38
+#define CSCRIPTCOMPILER_OPERATION_MODULUS 39
+#define CSCRIPTCOMPILER_OPERATION_NEGATION 40
+#define CSCRIPTCOMPILER_OPERATION_ACTION_PARAMETER 41
+#define CSCRIPTCOMPILER_OPERATION_UNSIGNED_SHIFT_RIGHT 42
+#define CSCRIPTCOMPILER_OPERATION_STRUCTURE_PART 43
+#define CSCRIPTCOMPILER_OPERATION_ONES_COMPLEMENT 44
+#define CSCRIPTCOMPILER_OPERATION_WHILE_BLOCK 45
+#define CSCRIPTCOMPILER_OPERATION_WHILE_CHOICE 46
+#define CSCRIPTCOMPILER_OPERATION_WHILE_CONDITION 47
+#define CSCRIPTCOMPILER_OPERATION_DOWHILE_BLOCK 48
+#define CSCRIPTCOMPILER_OPERATION_DOWHILE_CONDITION 49
+#define CSCRIPTCOMPILER_OPERATION_FUNCTIONAL_UNIT 50
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_STRUCT 51
+#define CSCRIPTCOMPILER_OPERATION_STRUCTURE_DEFINITION 52
+#define CSCRIPTCOMPILER_OPERATION_FUNCTION_IDENTIFIER 53
+#define CSCRIPTCOMPILER_OPERATION_FUNCTION_DECLARATION 54
+#define CSCRIPTCOMPILER_OPERATION_FUNCTION 55
+#define CSCRIPTCOMPILER_OPERATION_FUNCTION_PARAM_NAME 56
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_VOID 57
+#define CSCRIPTCOMPILER_OPERATION_RETURN 58
+#define CSCRIPTCOMPILER_OPERATION_BOOLEAN_NOT 59
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE0 60
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE1 61
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE2 62
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE3 63
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE4 64
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE5 65
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE6 66
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE7 67
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE8 68
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_ENGINE_STRUCTURE9 69
+#define CSCRIPTCOMPILER_OPERATION_CONSTANT_OBJECT 70
+#define CSCRIPTCOMPILER_OPERATION_KEYWORD_VECTOR 71
+#define CSCRIPTCOMPILER_OPERATION_CONSTANT_VECTOR 72
+#define CSCRIPTCOMPILER_OPERATION_GLOBAL_VARIABLES 73
+#define CSCRIPTCOMPILER_OPERATION_POST_INCREMENT 74
+#define CSCRIPTCOMPILER_OPERATION_POST_DECREMENT 75
+#define CSCRIPTCOMPILER_OPERATION_PRE_INCREMENT 76
+#define CSCRIPTCOMPILER_OPERATION_PRE_DECREMENT 77
+#define CSCRIPTCOMPILER_OPERATION_COND_BLOCK 78
+#define CSCRIPTCOMPILER_OPERATION_COND_CHOICE 79
+#define CSCRIPTCOMPILER_OPERATION_COND_CONDITION 80
+#define CSCRIPTCOMPILER_OPERATION_SWITCH_BLOCK 81
+#define CSCRIPTCOMPILER_OPERATION_SWITCH_CONDITION 82
+#define CSCRIPTCOMPILER_OPERATION_DEFAULT 83
+#define CSCRIPTCOMPILER_OPERATION_CASE 84
+#define CSCRIPTCOMPILER_OPERATION_BREAK 85
+#define CSCRIPTCOMPILER_OPERATION_CONTINUE 86
+#define CSCRIPTCOMPILER_OPERATION_WHILE_CONTINUE 87
+#define CSCRIPTCOMPILER_OPERATION_STATEMENT_NO_DEBUG 88
+#define CSCRIPTCOMPILER_OPERATION_FOR_BLOCK 89
+#define CSCRIPTCOMPILER_OPERATION_CONST_DECLARATION 90
+#define CSCRIPTCOMPILER_OPERATION_CONSTANT_JSON 91
+#define CSCRIPTCOMPILER_OPERATION_CONSTANT_LOCATION 92
+
+const char *OperationToString(int nOperation);
+
+#define CSCRIPTCOMPILER_IDENT_STATE_START_OF_LINE 0
+#define CSCRIPTCOMPILER_IDENT_STATE_AFTER_TYPE_DECLARATION 1
+#define CSCRIPTCOMPILER_IDENT_STATE_AFTER_FUNCTION_IDENTIFIER 2
+#define CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST 3
+#define CSCRIPTCOMPILER_IDENT_STATE_BEFORE_CONSTANT_IDENTIFIER 4
+#define CSCRIPTCOMPILER_IDENT_STATE_AFTER_CONSTANT_IDENTIFIER 5
+#define CSCRIPTCOMPILER_IDENT_STATE_DEFINE_STATEMENT 6
+#define CSCRIPTCOMPILER_IDENT_STATE_DEFINE_NUM_ENGINE_STRUCTURE 7
+#define CSCRIPTCOMPILER_IDENT_STATE_DEFINE_SINGLE_ENGINE_STRUCTURE 8
+#define CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_PARAMETER 9
+#define CSCRIPTCOMPILER_IDENT_STATE_IN_VECTOR_CONSTANT 10
+#define CSCRIPTCOMPILER_IDENT_STATE_IN_PARAMETER_LIST_CONSTANT 11
+
+#define CVIRTUALMACHINE_MAX_RECURSION_LEVELS 8
+// niv, 17 mar 2017, #28735: now configured in ini
+// #define CVIRTUALMACHINE_MAX_INSTRUCT_EXECUTE 131072 //8192
+#define CVIRTUALMACHINE_MAX_RUNTIME_VARS 128
+#define CVIRTUALMACHINE_MAX_SUBROUTINES 128
+
+#define CVIRTUALMACHINE_BINARY_SCRIPT_HEADER 13 // 9 for the NCS crud, and
+// 4 for the size of the file.
+
+// Format of the byte-encoded data.
+#define CVIRTUALMACHINE_OPERATION_BASE_SIZE 2
+#define CVIRTUALMACHINE_OPCODE_LOCATION 0
+#define CVIRTUALMACHINE_AUXCODE_LOCATION 1
+#define CVIRTUALMACHINE_EXTRA_DATA_LOCATION 2
+
+
+#define CVIRTUALMACHINE_OPCODE_ASSIGNMENT 0x01
+#define CVIRTUALMACHINE_OPCODE_RUNSTACK_ADD 0x02
+#define CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY 0x03
+#define CVIRTUALMACHINE_OPCODE_CONSTANT 0x04
+#define CVIRTUALMACHINE_OPCODE_EXECUTE_COMMAND 0x05
+#define CVIRTUALMACHINE_OPCODE_LOGICAL_AND 0x06
+#define CVIRTUALMACHINE_OPCODE_LOGICAL_OR 0x07
+#define CVIRTUALMACHINE_OPCODE_INCLUSIVE_OR 0x08
+#define CVIRTUALMACHINE_OPCODE_EXCLUSIVE_OR 0x09
+#define CVIRTUALMACHINE_OPCODE_BOOLEAN_AND 0x0a
+#define CVIRTUALMACHINE_OPCODE_EQUAL 0x0b
+#define CVIRTUALMACHINE_OPCODE_NOT_EQUAL 0x0c
+#define CVIRTUALMACHINE_OPCODE_GEQ 0x0d
+#define CVIRTUALMACHINE_OPCODE_GT 0x0e
+#define CVIRTUALMACHINE_OPCODE_LT 0x0f
+#define CVIRTUALMACHINE_OPCODE_LEQ 0x10
+#define CVIRTUALMACHINE_OPCODE_SHIFT_LEFT 0x11
+#define CVIRTUALMACHINE_OPCODE_SHIFT_RIGHT 0x12
+#define CVIRTUALMACHINE_OPCODE_USHIFT_RIGHT 0x13
+#define CVIRTUALMACHINE_OPCODE_ADD 0x14
+#define CVIRTUALMACHINE_OPCODE_SUB 0x15
+#define CVIRTUALMACHINE_OPCODE_MUL 0x16
+#define CVIRTUALMACHINE_OPCODE_DIV 0x17
+#define CVIRTUALMACHINE_OPCODE_MODULUS 0x18
+#define CVIRTUALMACHINE_OPCODE_NEGATION 0x19
+#define CVIRTUALMACHINE_OPCODE_ONES_COMPLEMENT 0x1a
+// New Instructions
+#define CVIRTUALMACHINE_OPCODE_MODIFY_STACK_POINTER 0x1b // move the stack pointer arbitrarily
+// to delete useless objects.
+#define CVIRTUALMACHINE_OPCODE_STORE_IP 0x1c // store the instruction pointer for
+// use when saving action.
+#define CVIRTUALMACHINE_OPCODE_JMP 0x1d // jump unconditionally
+#define CVIRTUALMACHINE_OPCODE_JSR 0x1e // jump to a subroutine
+#define CVIRTUALMACHINE_OPCODE_JZ 0x1f // jump if top integer on stack is 0
+#define CVIRTUALMACHINE_OPCODE_RET 0x20 // return from a JSR.
+#define CVIRTUALMACHINE_OPCODE_DE_STRUCT 0x21 // structure part.
+#define CVIRTUALMACHINE_OPCODE_BOOLEAN_NOT 0x22
+#define CVIRTUALMACHINE_OPCODE_DECREMENT 0x23
+#define CVIRTUALMACHINE_OPCODE_INCREMENT 0x24
+#define CVIRTUALMACHINE_OPCODE_JNZ 0x25
+#define CVIRTUALMACHINE_OPCODE_ASSIGNMENT_BASE 0x26
+#define CVIRTUALMACHINE_OPCODE_RUNSTACK_COPY_BASE 0x27
+#define CVIRTUALMACHINE_OPCODE_DECREMENT_BASE 0x28
+#define CVIRTUALMACHINE_OPCODE_INCREMENT_BASE 0x29
+#define CVIRTUALMACHINE_OPCODE_SAVE_BASE_POINTER 0x2A
+#define CVIRTUALMACHINE_OPCODE_RESTORE_BASE_POINTER 0x2B
+#define CVIRTUALMACHINE_OPCODE_STORE_STATE 0x2C // An extended version of Store_IP, it
+// also saves the stack information that
+// we need to keep stack sizes down in
+// the save games.
+#define CVIRTUALMACHINE_OPCODE_NO_OPERATION 0x2D
+
+// For OPCODE_LOOP, determine when to evaluate the operation.
+#define CVIRTUALMACHINE_AUXCODE_EVAL_INPLACE 0x70
+#define CVIRTUALMACHINE_AUXCODE_EVAL_POSTPLACE 0x71
+
+#define CVIRTUALMACHINE_AUXCODE_TYPE_VOID 0x01
+#define CVIRTUALMACHINE_AUXCODE_TYPE_COMMAND 0x02
+#define CVIRTUALMACHINE_AUXCODE_TYPE_INTEGER 0x03
+#define CVIRTUALMACHINE_AUXCODE_TYPE_FLOAT 0x04
+#define CVIRTUALMACHINE_AUXCODE_TYPE_STRING 0x05
+#define CVIRTUALMACHINE_AUXCODE_TYPE_OBJECT 0x06
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST0 0x10
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST1 0x11
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST2 0x12 // 8193.35 (CONST): uint32_t 0 = LOCATION_INVALID
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST3 0x13
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST4 0x14
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST5 0x15
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST6 0x16
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST7 0x17 // 8193.35 (CONST): uint16_t size + string
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST8 0x18
+#define CVIRTUALMACHINE_AUXCODE_TYPE_ENGST9 0x19
+
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_INTEGER 0x20
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_FLOAT 0x21
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_OBJECT_OBJECT 0x22
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_STRING_STRING 0x23
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_STRUCT_STRUCT 0x24
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_INTEGER_FLOAT 0x25
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_INTEGER 0x26
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST0_ENGST0 0x30
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST1_ENGST1 0x31
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST2_ENGST2 0x32
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST3_ENGST3 0x33
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST4_ENGST4 0x34
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST5_ENGST5 0x35
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST6_ENGST6 0x36
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST7_ENGST7 0x37
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST8_ENGST8 0x38
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_ENGST9_ENGST9 0x39
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_VECTOR_VECTOR 0x3a
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_VECTOR_FLOAT 0x3b
+#define CVIRTUALMACHINE_AUXCODE_TYPETYPE_FLOAT_VECTOR 0x3c
+
+// stuff for saving out ScriptSituations and Stacks
+#define CVIRTUALMACHINE_GFF_CODESIZE "CodeSize"
+#define CVIRTUALMACHINE_GFF_CODE "Code"
+#define CVIRTUALMACHINE_GFF_INSTRUCTIONPTR "InstructionPtr"
+#define CVIRTUALMACHINE_GFF_SECONDARYPTR "SecondaryPtr"
+
+#define CVIRTUALMACHINE_GFF_NDBSIZE "NDBSize"
+#define CVIRTUALMACHINE_GFF_NDB "NDB"
+
+#define CVIRTUALMACHINE_GFF_NAME "Name"
+#define CVIRTUALMACHINE_GFF_SCRIPTCHUNK "ScriptChunk"
+#define CVIRTUALMACHINE_GFF_SCRIPTEVENTID "ScriptEventID"
+#define CVIRTUALMACHINE_GFF_STACKSIZE "StackSize"
+#define CVIRTUALMACHINE_GFF_STACK "Stack"
+
+#define CVIRTUALMACHINE_GFF_STACKTYPE 0
+
+#define CVIRTUALMACHINESTACK_BASEPOINTER "BasePointer"
+#define CVIRTUALMACHINESTACK_STACKPOINTER "StackPointer"
+#define CVIRTUALMACHINESTACK_TOTALSIZE "TotalSize"
+
+#define CVIRTUALMACHINESTACK_STACKLIST "Stack"
+#define CVIRTUALMACHINESTACK_STACKTYPE "Type"
+#define CVIRTUALMACHINESTACK_STACKVALUE "Value"
+
+#define CVIRTUALMACHINE_GFF_JMPLIST "JmpList"
+#define CVIRTUALMACHINE_GFF_JMP_LABEL "Label"
+#define CVIRTUALMACHINE_GFF_JMP_VM_INSTPTR "VMInstPtr"
+#define CVIRTUALMACHINE_GFF_JMP_INSTPTR "InstPtr"
+#define CVIRTUALMACHINE_GFF_JMP_STACKPTR "StackPtr"
+#define CVIRTUALMACHINE_GFF_JMP_INSTPTRLEVEL "InstPtrLevel"
+#define CVIRTUALMACHINE_GFF_JMP_FROMJMP "FromJmp"
+#define CVIRTUALMACHINE_GFF_JMP_RETVAL "RetVal"
+
+#define CVIRTUALMACHINE_MAX_MESSAGE_SIZE 4096
+
+class CScriptParseTreeNode
+{
+
+public:
+ int32_t nOperation;
+ CExoString *m_psStringData;
+ int32_t nIntegerData;
+ int32_t nIntegerData2;
+ int32_t nIntegerData3;
+ int32_t nIntegerData4;
+ float fFloatData;
+ float fVectorData[3];
+ // json is reusing m_psStringData
+ int32_t m_nFileReference;
+ int32_t nLine;
+ int32_t nChar;
+ CScriptParseTreeNode *pLeft;
+ CScriptParseTreeNode *pRight;
+ int32_t nType;
+ CExoString *m_psTypeName;
+ /* int32_t m_nNodeLocation; ???? */
+ int32_t m_nStackPointer;
+
+ CScriptParseTreeNode() { m_psStringData = NULL; m_psTypeName = NULL; Clean(); }
+
+ void Clean()
+ {
+ if (m_psStringData != NULL)
+ {
+ delete m_psStringData;
+ m_psStringData = NULL;
+ }
+ if (m_psTypeName != NULL)
+ {
+ delete m_psTypeName;
+ m_psTypeName = NULL;
+ }
+
+ nOperation = 0;
+ nIntegerData = 0;
+ nIntegerData2 = 0;
+ nIntegerData3 = 0;
+ nIntegerData4 = 0;
+ fFloatData = 0.0f;
+ pLeft = NULL ;
+ pRight = NULL;
+ fVectorData[0] = 0.0f;
+ fVectorData[1] = 0.0f;
+ fVectorData[2] = 0.0f;
+ m_nFileReference = -1;
+ nLine = 0;
+ nChar = 0;
+ nType = 0;
+ m_nStackPointer = 0;
+ }
+
+ ~CScriptParseTreeNode()
+ {
+ if (m_psStringData != NULL)
+ {
+ delete m_psStringData;
+ m_psStringData = NULL;
+ }
+ if (m_psTypeName != NULL)
+ {
+ delete m_psTypeName;
+ m_psTypeName = NULL;
+ }
+ }
+
+ void DebugDump(const char *prefix = "", FILE *out = NULL)
+ {
+ if (!out) out = stdout;
+ fprintf(out, "%s[%p] (pLeft=%p, pRight=%p)\n", prefix, this, pLeft, pRight);
+ fprintf(out, " Operation: %s\n", OperationToString(nOperation));
+ fprintf(out, " Type: %s\n", TokenKeywordToString(nType));
+ fprintf(out, " IntegerData: %d %d %d %d\n", nIntegerData, nIntegerData2, nIntegerData3, nIntegerData4);
+ fprintf(out, " FloatData: %f %f %f %f\n", fFloatData, fVectorData[0], fVectorData[1], fVectorData[2]);
+ fprintf(out, " StringData: \"%s\"\n", m_psStringData ? m_psStringData->CStr() : "");
+ fprintf(out, " TypeName: \"%s\"\n", m_psTypeName ? m_psTypeName->CStr() : "");
+ fprintf(out, " File/Line/Char/SP: %d %d %d %d\n", m_nFileReference, nLine, nChar, m_nStackPointer);
+ }
+};
+
+#define CSCRIPTCOMPILER_PARSETREENODEBLOCK_SIZE 4096
+
+class CScriptParseTreeNodeBlock
+{
+public:
+ CScriptParseTreeNode m_pNodes[CSCRIPTCOMPILER_PARSETREENODEBLOCK_SIZE];
+ CScriptParseTreeNodeBlock *m_pNextBlock;
+
+ CScriptParseTreeNodeBlock()
+ {
+ m_pNextBlock = NULL;
+ CleanBlockEntries();
+ }
+
+ void CleanBlockEntries()
+ {
+ uint32_t nCount;
+ for (nCount = 0; nCount < CSCRIPTCOMPILER_PARSETREENODEBLOCK_SIZE; ++nCount)
+ {
+ m_pNodes[nCount].Clean();
+ }
+ }
+};
+
+class CScriptCompilerStackEntry
+{
+public:
+ int32_t nState;
+ int32_t nRule;
+ int32_t nTerm;
+ CScriptParseTreeNode *pCurrentTree;
+ CScriptParseTreeNode *pReturnTree;
+};
+
+class CScriptCompilerKeyWordEntry
+{
+public:
+ CScriptCompilerKeyWordEntry()
+ {
+ m_sAlphanumericName = "";
+ m_nHashValue = 0;
+ m_nNameLength = 0;
+ m_nTokenToTranslate = 0;
+ }
+
+ void Add(CExoString sName, int32_t nHashValue, int32_t nTokenToTranslate)
+ {
+ EXOASSERT(m_nHashValue == 0);
+ m_sAlphanumericName = sName;
+ m_nHashValue = nHashValue;
+ m_nNameLength = sName.GetLength();
+ m_nTokenToTranslate = nTokenToTranslate;
+ }
+
+ inline CExoString *GetPointerToName() { return &m_sAlphanumericName; }
+ inline char *GetAlphanumericName() { return m_sAlphanumericName.CStr(); }
+ inline uint32_t GetHash() { return m_nHashValue; }
+ inline uint32_t GetLength() { return m_nNameLength; }
+ inline int32_t GetTokenToTranslate() { return m_nTokenToTranslate; }
+
+private:
+ CExoString m_sAlphanumericName;
+ uint32_t m_nHashValue;
+ uint32_t m_nNameLength;
+ int32_t m_nTokenToTranslate;
+};
+
+#define CSCRIPTCOMPILER_HASH_MANAGER_TYPE_UNKNOWN 0
+#define CSCRIPTCOMPILER_HASH_MANAGER_TYPE_IDENTIFIER 1
+#define CSCRIPTCOMPILER_HASH_MANAGER_TYPE_KEYWORD 2
+#define CSCRIPTCOMPILER_HASH_MANAGER_TYPE_ENGINE_STRUCTURE 3
+
+class CScriptCompilerIdentifierHashTableEntry
+{
+public:
+ CScriptCompilerIdentifierHashTableEntry()
+ {
+ m_nHashValue = 0;
+ m_nIdentifierType = CSCRIPTCOMPILER_HASH_MANAGER_TYPE_UNKNOWN;
+ m_nIdentifierIndex = 0;
+ }
+
+ uint32_t m_nHashValue;
+ uint32_t m_nIdentifierType;
+ uint32_t m_nIdentifierIndex;
+};
+
+class CScriptCompilerIdListEntry
+{
+public:
+ CExoString m_psIdentifier;
+ uint32_t m_nIdentifierLength;
+ uint32_t m_nIdentifierHash;
+ int32_t m_nIdentifierType;
+ int32_t m_nReturnType;
+ int32_t m_bImplementationInPlace;
+ CExoString m_psStructureReturnName;
+ //INT m_nIdentifierOrder;
+
+ // For constants ...
+ CExoString m_psStringData;
+ int32_t m_nIntegerData;
+ float m_fFloatData;
+ float m_fVectorData[3];
+
+ // For identifiers ..
+ int32_t m_nIdIdentifier;
+ int32_t m_nParameters;
+ int32_t m_nNonOptionalParameters;
+
+ int32_t m_nParameterSpace;
+
+ // For each parameter ...
+ char *m_pchParameters;
+ CExoString *m_psStructureParameterNames;
+ // For the optional part of each parameter ...
+ BOOL *m_pbOptionalParameters;
+ int32_t *m_pnOptionalParameterIntegerData;
+ float *m_pfOptionalParameterFloatData;
+ CExoString *m_psOptionalParameterStringData;
+ OBJECT_ID *m_poidOptionalParameterObjectData;
+ float *m_pfOptionalParameterVectorData;
+ // json is reusing string data
+
+ // For user-defined identifiers
+ int32_t m_nBinarySourceStart;
+ int32_t m_nBinarySourceFinish;
+ int32_t m_nBinaryDestinationStart;
+ int32_t m_nBinaryDestinationFinish;
+
+ CScriptCompilerIdListEntry();
+ ~CScriptCompilerIdListEntry();
+ int32_t ExpandParameterSpace();
+};
+
+class CScriptCompilerVarStackEntry
+{
+public:
+ CExoString m_psVarName;
+ int32_t m_nVarType;
+ int32_t m_nVarLevel;
+ int32_t m_nVarRunTimeLocation;
+ CExoString m_sVarStructureName;
+
+ CScriptCompilerVarStackEntry()
+ {
+ m_nVarType = 0;
+ m_nVarLevel = 0;
+ m_nVarRunTimeLocation = 0;
+ }
+
+};
+
+class CScriptCompilerStructureEntry
+{
+public:
+ CExoString m_psName;
+ int32_t m_nFieldStart;
+ int32_t m_nFieldEnd;
+ int32_t m_nByteSize;
+
+ CScriptCompilerStructureEntry()
+ {
+ m_nFieldStart = 0;
+ m_nFieldEnd = 0;
+ m_nByteSize = 0;
+ }
+};
+
+class CScriptCompilerStructureFieldEntry
+{
+public:
+ uint8_t m_pchType;
+ CExoString m_psStructureName;
+ CExoString m_psVarName;
+ int32_t m_nLocation;
+
+ CScriptCompilerStructureFieldEntry()
+ {
+ m_pchType = 0;
+ m_nLocation = 0;
+ }
+
+};
+
+#define CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_UNKNOWN 0
+#define CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_ENTRY 1
+#define CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_FUNCTION_EXIT 2
+#define CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_BREAK 3
+#define CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_CONTINUE 4
+#define CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_SWITCH_CASE 5
+#define CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_SWITCH_DEFAULT 6
+
+class CScriptCompilerSymbolTableEntry
+{
+public:
+ uint32_t m_nSymbolType;
+ uint32_t m_nSymbolSubType1;
+ uint32_t m_nSymbolSubType2;
+ int32_t m_nLocationPointer;
+ int32_t m_nNextEntryPointer;
+
+ CScriptCompilerSymbolTableEntry()
+ {
+ m_nSymbolType = CSCRIPTCOMPILER_SYMBOL_TABLE_ENTRY_TYPE_UNKNOWN;
+ m_nSymbolSubType1 = 0;
+ m_nSymbolSubType2 = 0;
+ m_nLocationPointer = 0;
+ m_nNextEntryPointer = -1;
+ }
+};
+
+
+
+#endif // __SCRIPTINTERNAL_H__
diff --git a/src/Native Compiler/xxhash.c b/src/Native Compiler/xxhash.c
new file mode 100644
index 0000000..ff28749
--- /dev/null
+++ b/src/Native Compiler/xxhash.c
@@ -0,0 +1,1030 @@
+/*
+* xxHash - Fast Hash algorithm
+* Copyright (C) 2012-2016, Yann Collet
+*
+* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following disclaimer
+* in the documentation and/or other materials provided with the
+* distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+* You can contact the author at :
+* - xxHash homepage: http://www.xxhash.com
+* - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+
+/* *************************************
+* Tuning parameters
+***************************************/
+/*!XXH_FORCE_MEMORY_ACCESS :
+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
+ * The below switch allow to select different access method for improved performance.
+ * Method 0 (default) : use `memcpy()`. Safe and portable.
+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
+ * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
+ * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
+ * It can generate buggy code on targets which do not support unaligned memory accesses.
+ * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
+ * See http://stackoverflow.com/a/32095106/646947 for details.
+ * Prefer these methods in priority order (0 > 1 > 2)
+ */
+#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
+# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
+ || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
+ || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
+# define XXH_FORCE_MEMORY_ACCESS 2
+# elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \
+ (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
+ || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
+ || defined(__ARM_ARCH_7S__) ))
+# define XXH_FORCE_MEMORY_ACCESS 1
+# endif
+#endif
+
+/*!XXH_ACCEPT_NULL_INPUT_POINTER :
+ * If input pointer is NULL, xxHash default behavior is to dereference it, triggering a segfault.
+ * When this macro is enabled, xxHash actively checks input for null pointer.
+ * It it is, result for null input pointers is the same as a null-length input.
+ */
+#ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */
+# define XXH_ACCEPT_NULL_INPUT_POINTER 0
+#endif
+
+/*!XXH_FORCE_NATIVE_FORMAT :
+ * By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
+ * Results are therefore identical for little-endian and big-endian CPU.
+ * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
+ * Should endian-independence be of no importance for your application, you may set the #define below to 1,
+ * to improve speed for Big-endian CPU.
+ * This option has no impact on Little_Endian CPU.
+ */
+#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
+# define XXH_FORCE_NATIVE_FORMAT 0
+#endif
+
+/*!XXH_FORCE_ALIGN_CHECK :
+ * This is a minor performance trick, only useful with lots of very small keys.
+ * It means : check for aligned/unaligned input.
+ * The check costs one initial branch per hash;
+ * set it to 0 when the input is guaranteed to be aligned,
+ * or when alignment doesn't matter for performance.
+ */
+#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
+# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
+# define XXH_FORCE_ALIGN_CHECK 0
+# else
+# define XXH_FORCE_ALIGN_CHECK 1
+# endif
+#endif
+
+
+/* *************************************
+* Includes & Memory related functions
+***************************************/
+/*! Modify the local functions below should you wish to use some other memory routines
+* for malloc(), free() */
+#include
+static void* XXH_malloc(size_t s) { return malloc(s); }
+static void XXH_free (void* p) { free(p); }
+/*! and for memcpy() */
+#include
+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
+
+#include /* assert */
+
+#define XXH_STATIC_LINKING_ONLY
+#include "xxhash.h"
+
+
+/* *************************************
+* Compiler Specific Options
+***************************************/
+#ifdef _MSC_VER /* Visual Studio */
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+# define FORCE_INLINE static __forceinline
+#else
+# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# ifdef __GNUC__
+# define FORCE_INLINE static inline __attribute__((always_inline))
+# else
+# define FORCE_INLINE static inline
+# endif
+# else
+# define FORCE_INLINE static
+# endif /* __STDC_VERSION__ */
+#endif
+
+
+/* *************************************
+* Basic Types
+***************************************/
+#ifndef MEM_MODULE
+# if !defined (__VMS) \
+ && (defined (__cplusplus) \
+ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+# else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+# endif
+#endif
+
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
+
+/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
+static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
+
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+typedef union { U32 u32; } __attribute__((packed)) unalign;
+static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
+
+#else
+
+/* portable and safe solution. Generally efficient.
+ * see : http://stackoverflow.com/a/32095106/646947
+ */
+static U32 XXH_read32(const void* memPtr)
+{
+ U32 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+}
+
+#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+
+/* ****************************************
+* Compiler-specific Functions and Macros
+******************************************/
+#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
+#if defined(_MSC_VER)
+# define XXH_rotl32(x,r) _rotl(x,r)
+# define XXH_rotl64(x,r) _rotl64(x,r)
+#else
+# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
+# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
+#endif
+
+#if defined(_MSC_VER) /* Visual Studio */
+# define XXH_swap32 _byteswap_ulong
+#elif XXH_GCC_VERSION >= 403
+# define XXH_swap32 __builtin_bswap32
+#else
+static U32 XXH_swap32 (U32 x)
+{
+ return ((x << 24) & 0xff000000 ) |
+ ((x << 8) & 0x00ff0000 ) |
+ ((x >> 8) & 0x0000ff00 ) |
+ ((x >> 24) & 0x000000ff );
+}
+#endif
+
+
+/* *************************************
+* Architecture Macros
+***************************************/
+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
+
+/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
+#ifndef XXH_CPU_LITTLE_ENDIAN
+static int XXH_isLittleEndian(void)
+{
+ const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
+ return one.c[0];
+}
+# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian()
+#endif
+
+
+/* ***************************
+* Memory reads
+*****************************/
+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
+
+FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+ if (align==XXH_unaligned)
+ return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
+ else
+ return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
+}
+
+FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
+{
+ return XXH_readLE32_align(ptr, endian, XXH_unaligned);
+}
+
+static U32 XXH_readBE32(const void* ptr)
+{
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
+}
+
+
+/* *************************************
+* Macros
+***************************************/
+#define XXH_STATIC_ASSERT(c) { enum { XXH_sa = 1/(int)(!!(c)) }; } /* use after variable declarations */
+XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
+
+
+/* *******************************************************************
+* 32-bit hash functions
+*********************************************************************/
+static const U32 PRIME32_1 = 2654435761U;
+static const U32 PRIME32_2 = 2246822519U;
+static const U32 PRIME32_3 = 3266489917U;
+static const U32 PRIME32_4 = 668265263U;
+static const U32 PRIME32_5 = 374761393U;
+
+static U32 XXH32_round(U32 seed, U32 input)
+{
+ seed += input * PRIME32_2;
+ seed = XXH_rotl32(seed, 13);
+ seed *= PRIME32_1;
+ return seed;
+}
+
+/* mix all bits */
+static U32 XXH32_avalanche(U32 h32)
+{
+ h32 ^= h32 >> 15;
+ h32 *= PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= PRIME32_3;
+ h32 ^= h32 >> 16;
+ return(h32);
+}
+
+#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
+
+static U32
+XXH32_finalize(U32 h32, const void* ptr, size_t len,
+ XXH_endianess endian, XXH_alignment align)
+
+{
+ const BYTE* p = (const BYTE*)ptr;
+
+#define PROCESS1 \
+ h32 += (*p++) * PRIME32_5; \
+ h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
+
+#define PROCESS4 \
+ h32 += XXH_get32bits(p) * PRIME32_3; \
+ p+=4; \
+ h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
+
+ switch(len&15) /* or switch(bEnd - p) */
+ {
+ case 12: PROCESS4;
+ /* fallthrough */
+ case 8: PROCESS4;
+ /* fallthrough */
+ case 4: PROCESS4;
+ return XXH32_avalanche(h32);
+
+ case 13: PROCESS4;
+ /* fallthrough */
+ case 9: PROCESS4;
+ /* fallthrough */
+ case 5: PROCESS4;
+ PROCESS1;
+ return XXH32_avalanche(h32);
+
+ case 14: PROCESS4;
+ /* fallthrough */
+ case 10: PROCESS4;
+ /* fallthrough */
+ case 6: PROCESS4;
+ PROCESS1;
+ PROCESS1;
+ return XXH32_avalanche(h32);
+
+ case 15: PROCESS4;
+ /* fallthrough */
+ case 11: PROCESS4;
+ /* fallthrough */
+ case 7: PROCESS4;
+ /* fallthrough */
+ case 3: PROCESS1;
+ /* fallthrough */
+ case 2: PROCESS1;
+ /* fallthrough */
+ case 1: PROCESS1;
+ /* fallthrough */
+ case 0: return XXH32_avalanche(h32);
+ }
+ assert(0);
+ return h32; /* reaching this point is deemed impossible */
+}
+
+
+FORCE_INLINE U32
+XXH32_endian_align(const void* input, size_t len, U32 seed,
+ XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* bEnd = p + len;
+ U32 h32;
+
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+ if (p==NULL) {
+ len=0;
+ bEnd=p=(const BYTE*)(size_t)16;
+ }
+#endif
+
+ if (len>=16) {
+ const BYTE* const limit = bEnd - 15;
+ U32 v1 = seed + PRIME32_1 + PRIME32_2;
+ U32 v2 = seed + PRIME32_2;
+ U32 v3 = seed + 0;
+ U32 v4 = seed - PRIME32_1;
+
+ do {
+ v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
+ v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
+ v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
+ v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
+ } while (p < limit);
+
+ h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7)
+ + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
+ } else {
+ h32 = seed + PRIME32_5;
+ }
+
+ h32 += (U32)len;
+
+ return XXH32_finalize(h32, p, len&15, endian, align);
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
+{
+#if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH32_state_t state;
+ XXH32_reset(&state, seed);
+ XXH32_update(&state, input, len);
+ return XXH32_digest(&state);
+#else
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if (XXH_FORCE_ALIGN_CHECK) {
+ if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+ } }
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+
+
+/*====== Hash streaming ======*/
+
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
+{
+ return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
+{
+ XXH_free(statePtr);
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
+{
+ memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
+{
+ XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+ memset(&state, 0, sizeof(state));
+ state.v1 = seed + PRIME32_1 + PRIME32_2;
+ state.v2 = seed + PRIME32_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME32_1;
+ /* do not write into reserved, planned to be removed in a future version */
+ memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
+ return XXH_OK;
+}
+
+
+FORCE_INLINE XXH_errorcode
+XXH32_update_endian(XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+ if (input==NULL)
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+ return XXH_OK;
+#else
+ return XXH_ERROR;
+#endif
+
+ { const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+
+ state->total_len_32 += (unsigned)len;
+ state->large_len |= (len>=16) | (state->total_len_32>=16);
+
+ if (state->memsize + len < 16) { /* fill in tmp buffer */
+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
+ state->memsize += (unsigned)len;
+ return XXH_OK;
+ }
+
+ if (state->memsize) { /* some data left from previous update */
+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
+ { const U32* p32 = state->mem32;
+ state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
+ state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
+ state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
+ state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian));
+ }
+ p += 16-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p <= bEnd-16) {
+ const BYTE* const limit = bEnd - 16;
+ U32 v1 = state->v1;
+ U32 v2 = state->v2;
+ U32 v3 = state->v3;
+ U32 v4 = state->v4;
+
+ do {
+ v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
+ v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
+ v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
+ v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
+ } while (p<=limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < bEnd) {
+ XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
+ state->memsize = (unsigned)(bEnd-p);
+ }
+ }
+
+ return XXH_OK;
+}
+
+
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
+ else
+ return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+FORCE_INLINE U32
+XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
+{
+ U32 h32;
+
+ if (state->large_len) {
+ h32 = XXH_rotl32(state->v1, 1)
+ + XXH_rotl32(state->v2, 7)
+ + XXH_rotl32(state->v3, 12)
+ + XXH_rotl32(state->v4, 18);
+ } else {
+ h32 = state->v3 /* == seed */ + PRIME32_5;
+ }
+
+ h32 += state->total_len_32;
+
+ return XXH32_finalize(h32, state->mem32, state->memsize, endian, XXH_aligned);
+}
+
+
+XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_digest_endian(state_in, XXH_littleEndian);
+ else
+ return XXH32_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+/*====== Canonical representation ======*/
+
+/*! Default XXH result types are basic unsigned 32 and 64 bits.
+* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
+* These functions allow transformation of hash result into and from its canonical format.
+* This way, hash values can be written into a file or buffer, remaining comparable across different systems.
+*/
+
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
+{
+ XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
+{
+ return XXH_readBE32(src);
+}
+
+
+#ifndef XXH_NO_LONG_LONG
+
+/* *******************************************************************
+* 64-bit hash functions
+*********************************************************************/
+
+/*====== Memory access ======*/
+
+#ifndef MEM_MODULE
+# define MEM_MODULE
+# if !defined (__VMS) \
+ && (defined (__cplusplus) \
+ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include
+ typedef uint64_t U64;
+# else
+ /* if compiler doesn't support unsigned long long, replace by another 64-bit type */
+ typedef unsigned long long U64;
+# endif
+#endif
+
+
+#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
+
+/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
+static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
+
+#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
+
+/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
+/* currently only defined for gcc and icc */
+typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;
+static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }
+
+#else
+
+/* portable and safe solution. Generally efficient.
+ * see : http://stackoverflow.com/a/32095106/646947
+ */
+
+static U64 XXH_read64(const void* memPtr)
+{
+ U64 val;
+ memcpy(&val, memPtr, sizeof(val));
+ return val;
+}
+
+#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
+
+#if defined(_MSC_VER) /* Visual Studio */
+# define XXH_swap64 _byteswap_uint64
+#elif XXH_GCC_VERSION >= 403
+# define XXH_swap64 __builtin_bswap64
+#else
+static U64 XXH_swap64 (U64 x)
+{
+ return ((x << 56) & 0xff00000000000000ULL) |
+ ((x << 40) & 0x00ff000000000000ULL) |
+ ((x << 24) & 0x0000ff0000000000ULL) |
+ ((x << 8) & 0x000000ff00000000ULL) |
+ ((x >> 8) & 0x00000000ff000000ULL) |
+ ((x >> 24) & 0x0000000000ff0000ULL) |
+ ((x >> 40) & 0x000000000000ff00ULL) |
+ ((x >> 56) & 0x00000000000000ffULL);
+}
+#endif
+
+FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
+{
+ if (align==XXH_unaligned)
+ return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
+ else
+ return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
+}
+
+FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
+{
+ return XXH_readLE64_align(ptr, endian, XXH_unaligned);
+}
+
+static U64 XXH_readBE64(const void* ptr)
+{
+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
+}
+
+
+/*====== xxh64 ======*/
+
+static const U64 PRIME64_1 = 11400714785074694791ULL;
+static const U64 PRIME64_2 = 14029467366897019727ULL;
+static const U64 PRIME64_3 = 1609587929392839161ULL;
+static const U64 PRIME64_4 = 9650029242287828579ULL;
+static const U64 PRIME64_5 = 2870177450012600261ULL;
+
+static U64 XXH64_round(U64 acc, U64 input)
+{
+ acc += input * PRIME64_2;
+ acc = XXH_rotl64(acc, 31);
+ acc *= PRIME64_1;
+ return acc;
+}
+
+static U64 XXH64_mergeRound(U64 acc, U64 val)
+{
+ val = XXH64_round(0, val);
+ acc ^= val;
+ acc = acc * PRIME64_1 + PRIME64_4;
+ return acc;
+}
+
+static U64 XXH64_avalanche(U64 h64)
+{
+ h64 ^= h64 >> 33;
+ h64 *= PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= PRIME64_3;
+ h64 ^= h64 >> 32;
+ return h64;
+}
+
+
+#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
+
+static U64
+XXH64_finalize(U64 h64, const void* ptr, size_t len,
+ XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)ptr;
+
+#define PROCESS1_64 \
+ h64 ^= (*p++) * PRIME64_5; \
+ h64 = XXH_rotl64(h64, 11) * PRIME64_1;
+
+#define PROCESS4_64 \
+ h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; \
+ p+=4; \
+ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+
+#define PROCESS8_64 { \
+ U64 const k1 = XXH64_round(0, XXH_get64bits(p)); \
+ p+=8; \
+ h64 ^= k1; \
+ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; \
+}
+
+ switch(len&31) {
+ case 24: PROCESS8_64;
+ /* fallthrough */
+ case 16: PROCESS8_64;
+ /* fallthrough */
+ case 8: PROCESS8_64;
+ return XXH64_avalanche(h64);
+
+ case 28: PROCESS8_64;
+ /* fallthrough */
+ case 20: PROCESS8_64;
+ /* fallthrough */
+ case 12: PROCESS8_64;
+ /* fallthrough */
+ case 4: PROCESS4_64;
+ return XXH64_avalanche(h64);
+
+ case 25: PROCESS8_64;
+ /* fallthrough */
+ case 17: PROCESS8_64;
+ /* fallthrough */
+ case 9: PROCESS8_64;
+ PROCESS1_64;
+ return XXH64_avalanche(h64);
+
+ case 29: PROCESS8_64;
+ /* fallthrough */
+ case 21: PROCESS8_64;
+ /* fallthrough */
+ case 13: PROCESS8_64;
+ /* fallthrough */
+ case 5: PROCESS4_64;
+ PROCESS1_64;
+ return XXH64_avalanche(h64);
+
+ case 26: PROCESS8_64;
+ /* fallthrough */
+ case 18: PROCESS8_64;
+ /* fallthrough */
+ case 10: PROCESS8_64;
+ PROCESS1_64;
+ PROCESS1_64;
+ return XXH64_avalanche(h64);
+
+ case 30: PROCESS8_64;
+ /* fallthrough */
+ case 22: PROCESS8_64;
+ /* fallthrough */
+ case 14: PROCESS8_64;
+ /* fallthrough */
+ case 6: PROCESS4_64;
+ PROCESS1_64;
+ PROCESS1_64;
+ return XXH64_avalanche(h64);
+
+ case 27: PROCESS8_64;
+ /* fallthrough */
+ case 19: PROCESS8_64;
+ /* fallthrough */
+ case 11: PROCESS8_64;
+ PROCESS1_64;
+ PROCESS1_64;
+ PROCESS1_64;
+ return XXH64_avalanche(h64);
+
+ case 31: PROCESS8_64;
+ /* fallthrough */
+ case 23: PROCESS8_64;
+ /* fallthrough */
+ case 15: PROCESS8_64;
+ /* fallthrough */
+ case 7: PROCESS4_64;
+ /* fallthrough */
+ case 3: PROCESS1_64;
+ /* fallthrough */
+ case 2: PROCESS1_64;
+ /* fallthrough */
+ case 1: PROCESS1_64;
+ /* fallthrough */
+ case 0: return XXH64_avalanche(h64);
+ }
+
+ /* impossible to reach */
+ assert(0);
+ return 0; /* unreachable, but some compilers complain without it */
+}
+
+FORCE_INLINE U64
+XXH64_endian_align(const void* input, size_t len, U64 seed,
+ XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* bEnd = p + len;
+ U64 h64;
+
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+ if (p==NULL) {
+ len=0;
+ bEnd=p=(const BYTE*)(size_t)32;
+ }
+#endif
+
+ if (len>=32) {
+ const BYTE* const limit = bEnd - 32;
+ U64 v1 = seed + PRIME64_1 + PRIME64_2;
+ U64 v2 = seed + PRIME64_2;
+ U64 v3 = seed + 0;
+ U64 v4 = seed - PRIME64_1;
+
+ do {
+ v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
+ v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
+ v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
+ v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
+ } while (p<=limit);
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+
+ } else {
+ h64 = seed + PRIME64_5;
+ }
+
+ h64 += (U64) len;
+
+ return XXH64_finalize(h64, p, len, endian, align);
+}
+
+
+XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
+{
+#if 0
+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
+ XXH64_state_t state;
+ XXH64_reset(&state, seed);
+ XXH64_update(&state, input, len);
+ return XXH64_digest(&state);
+#else
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if (XXH_FORCE_ALIGN_CHECK) {
+ if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+ else
+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+ } }
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+ else
+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+/*====== Hash Streaming ======*/
+
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
+{
+ return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
+}
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
+{
+ XXH_free(statePtr);
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
+{
+ memcpy(dstState, srcState, sizeof(*dstState));
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
+{
+ XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
+ memset(&state, 0, sizeof(state));
+ state.v1 = seed + PRIME64_1 + PRIME64_2;
+ state.v2 = seed + PRIME64_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME64_1;
+ /* do not write into reserved, planned to be removed in a future version */
+ memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
+ return XXH_OK;
+}
+
+FORCE_INLINE XXH_errorcode
+XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
+{
+ if (input==NULL)
+#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
+ return XXH_OK;
+#else
+ return XXH_ERROR;
+#endif
+
+ { const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+
+ state->total_len += len;
+
+ if (state->memsize + len < 32) { /* fill in tmp buffer */
+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
+ state->memsize += (U32)len;
+ return XXH_OK;
+ }
+
+ if (state->memsize) { /* tmp buffer is full */
+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
+ state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
+ state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
+ state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
+ state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
+ p += 32-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p+32 <= bEnd) {
+ const BYTE* const limit = bEnd - 32;
+ U64 v1 = state->v1;
+ U64 v2 = state->v2;
+ U64 v3 = state->v3;
+ U64 v4 = state->v4;
+
+ do {
+ v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
+ v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
+ v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
+ v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
+ } while (p<=limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < bEnd) {
+ XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
+ state->memsize = (unsigned)(bEnd-p);
+ }
+ }
+
+ return XXH_OK;
+}
+
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
+ else
+ return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
+{
+ U64 h64;
+
+ if (state->total_len >= 32) {
+ U64 const v1 = state->v1;
+ U64 const v2 = state->v2;
+ U64 const v3 = state->v3;
+ U64 const v4 = state->v4;
+
+ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
+ h64 = XXH64_mergeRound(h64, v1);
+ h64 = XXH64_mergeRound(h64, v2);
+ h64 = XXH64_mergeRound(h64, v3);
+ h64 = XXH64_mergeRound(h64, v4);
+ } else {
+ h64 = state->v3 /*seed*/ + PRIME64_5;
+ }
+
+ h64 += (U64) state->total_len;
+
+ return XXH64_finalize(h64, state->mem64, (size_t)state->total_len, endian, XXH_aligned);
+}
+
+XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH64_digest_endian(state_in, XXH_littleEndian);
+ else
+ return XXH64_digest_endian(state_in, XXH_bigEndian);
+}
+
+
+/*====== Canonical representation ======*/
+
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
+{
+ XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
+ memcpy(dst, &hash, sizeof(*dst));
+}
+
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
+{
+ return XXH_readBE64(src);
+}
+
+#endif /* XXH_NO_LONG_LONG */
diff --git a/src/Native Compiler/xxhash.h b/src/Native Compiler/xxhash.h
new file mode 100644
index 0000000..d6bad94
--- /dev/null
+++ b/src/Native Compiler/xxhash.h
@@ -0,0 +1,328 @@
+/*
+ xxHash - Extremely Fast Hash algorithm
+ Header File
+ Copyright (C) 2012-2016, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+/* Notice extracted from xxHash homepage :
+
+xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
+It also successfully passes all tests from the SMHasher suite.
+
+Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
+
+Name Speed Q.Score Author
+xxHash 5.4 GB/s 10
+CrapWow 3.2 GB/s 2 Andrew
+MumurHash 3a 2.7 GB/s 10 Austin Appleby
+SpookyHash 2.0 GB/s 10 Bob Jenkins
+SBox 1.4 GB/s 9 Bret Mulvey
+Lookup3 1.2 GB/s 9 Bob Jenkins
+SuperFastHash 1.2 GB/s 1 Paul Hsieh
+CityHash64 1.05 GB/s 10 Pike & Alakuijala
+FNV 0.55 GB/s 5 Fowler, Noll, Vo
+CRC32 0.43 GB/s 9
+MD5-32 0.33 GB/s 10 Ronald L. Rivest
+SHA1-32 0.28 GB/s 10
+
+Q.Score is a measure of quality of the hash function.
+It depends on successfully passing SMHasher test set.
+10 is a perfect score.
+
+A 64-bit version, named XXH64, is available since r35.
+It offers much better speed, but for 64-bit applications only.
+Name Speed on 64 bits Speed on 32 bits
+XXH64 13.8 GB/s 1.9 GB/s
+XXH32 6.8 GB/s 6.0 GB/s
+*/
+
+#ifndef XXHASH_H_5627135585666179
+#define XXHASH_H_5627135585666179 1
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* ****************************
+* Definitions
+******************************/
+#include /* size_t */
+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+
+
+/* ****************************
+ * API modifier
+ ******************************/
+/** XXH_INLINE_ALL (and XXH_PRIVATE_API)
+ * This is useful to include xxhash functions in `static` mode
+ * in order to inline them, and remove their symbol from the public list.
+ * Inlining can offer dramatic performance improvement on small keys.
+ * Methodology :
+ * #define XXH_INLINE_ALL
+ * #include "xxhash.h"
+ * `xxhash.c` is automatically included.
+ * It's not useful to compile and link it as a separate module.
+ */
+#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
+# ifndef XXH_STATIC_LINKING_ONLY
+# define XXH_STATIC_LINKING_ONLY
+# endif
+# if defined(__GNUC__)
+# define XXH_PUBLIC_API static __inline __attribute__((unused))
+# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+# define XXH_PUBLIC_API static inline
+# elif defined(_MSC_VER)
+# define XXH_PUBLIC_API static __inline
+# else
+ /* this version may generate warnings for unused static functions */
+# define XXH_PUBLIC_API static
+# endif
+#else
+# define XXH_PUBLIC_API /* do nothing */
+#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */
+
+/*! XXH_NAMESPACE, aka Namespace Emulation :
+ *
+ * If you want to include _and expose_ xxHash functions from within your own library,
+ * but also want to avoid symbol collisions with other libraries which may also include xxHash,
+ *
+ * you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
+ * with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).
+ *
+ * Note that no change is required within the calling program as long as it includes `xxhash.h` :
+ * regular symbol name will be automatically translated by this header.
+ */
+#ifdef XXH_NAMESPACE
+# define XXH_CAT(A,B) A##B
+# define XXH_NAME2(A,B) XXH_CAT(A,B)
+# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
+# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
+# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
+# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
+# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
+# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
+# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
+# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
+# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
+# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
+# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
+# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
+# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
+# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
+# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
+# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
+# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
+# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
+# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
+#endif
+
+
+/* *************************************
+* Version
+***************************************/
+#define XXH_VERSION_MAJOR 0
+#define XXH_VERSION_MINOR 6
+#define XXH_VERSION_RELEASE 5
+#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
+XXH_PUBLIC_API unsigned XXH_versionNumber (void);
+
+
+/*-**********************************************************************
+* 32-bit hash
+************************************************************************/
+typedef unsigned int XXH32_hash_t;
+
+/*! XXH32() :
+ Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input".
+ The memory between input & input+length must be valid (allocated and read-accessible).
+ "seed" can be used to alter the result predictably.
+ Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */
+XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
+
+/*====== Streaming ======*/
+typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
+XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
+
+XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
+
+/*
+ * Streaming functions generate the xxHash of an input provided in multiple segments.
+ * Note that, for small input, they are slower than single-call functions, due to state management.
+ * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.
+ *
+ * XXH state must first be allocated, using XXH*_createState() .
+ *
+ * Start a new hash by initializing state with a seed, using XXH*_reset().
+ *
+ * Then, feed the hash state by calling XXH*_update() as many times as necessary.
+ * The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
+ *
+ * Finally, a hash value can be produced anytime, by using XXH*_digest().
+ * This function returns the nn-bits hash as an int or long long.
+ *
+ * It's still possible to continue inserting input into the hash state after a digest,
+ * and generate some new hashes later on, by calling again XXH*_digest().
+ *
+ * When done, free XXH state space if it was allocated dynamically.
+ */
+
+/*====== Canonical representation ======*/
+
+typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
+XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
+XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
+
+/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
+ * The canonical representation uses human-readable write convention, aka big-endian (large digits first).
+ * These functions allow transformation of hash result into and from its canonical format.
+ * This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
+ */
+
+
+#ifndef XXH_NO_LONG_LONG
+/*-**********************************************************************
+* 64-bit hash
+************************************************************************/
+typedef unsigned long long XXH64_hash_t;
+
+/*! XXH64() :
+ Calculate the 64-bit hash of sequence of length "len" stored at memory address "input".
+ "seed" can be used to alter the result predictably.
+ This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark).
+*/
+XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
+
+/*====== Streaming ======*/
+typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
+XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
+
+XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
+XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
+
+/*====== Canonical representation ======*/
+typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
+#endif /* XXH_NO_LONG_LONG */
+
+
+
+#ifdef XXH_STATIC_LINKING_ONLY
+
+/* ================================================================================================
+ This section contains declarations which are not guaranteed to remain stable.
+ They may change in future versions, becoming incompatible with a different version of the library.
+ These declarations should only be used with static linking.
+ Never use them in association with dynamic linking !
+=================================================================================================== */
+
+/* These definitions are only present to allow
+ * static allocation of XXH state, on stack or in a struct for example.
+ * Never **ever** use members directly. */
+
+#if !defined (__VMS) \
+ && (defined (__cplusplus) \
+ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
+# include
+
+struct XXH32_state_s {
+ uint32_t total_len_32;
+ uint32_t large_len;
+ uint32_t v1;
+ uint32_t v2;
+ uint32_t v3;
+ uint32_t v4;
+ uint32_t mem32[4];
+ uint32_t memsize;
+ uint32_t reserved; /* never read nor write, might be removed in a future version */
+}; /* typedef'd to XXH32_state_t */
+
+struct XXH64_state_s {
+ uint64_t total_len;
+ uint64_t v1;
+ uint64_t v2;
+ uint64_t v3;
+ uint64_t v4;
+ uint64_t mem64[4];
+ uint32_t memsize;
+ uint32_t reserved[2]; /* never read nor write, might be removed in a future version */
+}; /* typedef'd to XXH64_state_t */
+
+# else
+
+struct XXH32_state_s {
+ unsigned total_len_32;
+ unsigned large_len;
+ unsigned v1;
+ unsigned v2;
+ unsigned v3;
+ unsigned v4;
+ unsigned mem32[4];
+ unsigned memsize;
+ unsigned reserved; /* never read nor write, might be removed in a future version */
+}; /* typedef'd to XXH32_state_t */
+
+# ifndef XXH_NO_LONG_LONG /* remove 64-bit support */
+struct XXH64_state_s {
+ unsigned long long total_len;
+ unsigned long long v1;
+ unsigned long long v2;
+ unsigned long long v3;
+ unsigned long long v4;
+ unsigned long long mem64[4];
+ unsigned memsize;
+ unsigned reserved[2]; /* never read nor write, might be removed in a future version */
+}; /* typedef'd to XXH64_state_t */
+# endif
+
+# endif
+
+
+#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
+# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */
+#endif
+
+#endif /* XXH_STATIC_LINKING_ONLY */
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* XXHASH_H_5627135585666179 */
diff --git a/src/Plugin Controls/CompilerSettingsDialog.cpp b/src/Plugin Controls/CompilerSettingsDialog.cpp
index 893206d..3bb0b1a 100644
--- a/src/Plugin Controls/CompilerSettingsDialog.cpp
+++ b/src/Plugin Controls/CompilerSettingsDialog.cpp
@@ -13,6 +13,7 @@
#include "Nsc.h"
#include "CompilerSettingsDialog.h"
+#include "WhatIsThisDialog.h"
#include "PluginControlsRC.h"
#include "PluginDarkMode.h"
@@ -20,6 +21,8 @@
using namespace NWScriptPlugin;
+static WhatIsThisDialog whatIsThisDialog;
+
intptr_t CALLBACK CompilerSettingsDialog::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
@@ -64,10 +67,23 @@ intptr_t CALLBACK CompilerSettingsDialog::run_dlgProc(UINT message, WPARAM wPara
ListBox_AddString(GetDlgItem(_hSelf, IDC_LSTADDPATH), s.c_str());
}
+ if (myset.compilerEngine == 0)
+ {
+ ::CheckRadioButton(_hSelf, IDC_USEBEAMDOGCOMPILER, IDC_USELEGACYCOMPILER, IDC_USEBEAMDOGCOMPILER);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPSTRICTMODE), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKNONBIOWAREXTENSIONS), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPMAKEFILE), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPDISABLESLASHPARSE), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CBOTARGETVERSION), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_LBLTARGETVERSION), false);
+ }
+ else
+ ::CheckRadioButton(_hSelf, IDC_USEBEAMDOGCOMPILER, IDC_USELEGACYCOMPILER, IDC_USELEGACYCOMPILER);
+
CheckDlgButton(_hSelf, IDC_CHKCOMPOPTIMIZE, myset.optimizeScript);
- CheckDlgButton(_hSelf, IDC_CHKNONBIOWAREXTENSIONS, myset.useNonBiowareExtenstions);
CheckDlgButton(_hSelf, IDC_CHKCOMPNDBSYMBOLS, myset.generateSymbols);
CheckDlgButton(_hSelf, IDC_CHKCOMPSTRICTMODE, myset.compilerFlags & NscCompilerFlag_StrictModeEnabled);
+ CheckDlgButton(_hSelf, IDC_CHKNONBIOWAREXTENSIONS, myset.useNonBiowareExtenstions);
CheckDlgButton(_hSelf, IDC_CHKCOMPMAKEFILE, myset.compilerFlags & NscCompilerFlag_GenerateMakeDeps);
CheckDlgButton(_hSelf, IDC_CHKCOMPDISABLESLASHPARSE, myset.compilerFlags & NscCompilerFlag_DisableDoubleQuote);
@@ -151,6 +167,28 @@ intptr_t CALLBACK CompilerSettingsDialog::run_dlgProc(UINT message, WPARAM wPara
return FALSE;
}
+ case IDC_USEBEAMDOGCOMPILER:
+ {
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPSTRICTMODE), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKNONBIOWAREXTENSIONS), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPMAKEFILE), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPDISABLESLASHPARSE), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CBOTARGETVERSION), false);
+ EnableWindow(GetDlgItem(_hSelf, IDC_LBLTARGETVERSION), false);
+ return FALSE;
+ }
+
+ case IDC_USELEGACYCOMPILER:
+ {
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPSTRICTMODE), true);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKNONBIOWAREXTENSIONS), true);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPMAKEFILE), true);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CHKCOMPDISABLESLASHPARSE), true);
+ EnableWindow(GetDlgItem(_hSelf, IDC_CBOTARGETVERSION), true);
+ EnableWindow(GetDlgItem(_hSelf, IDC_LBLTARGETVERSION), true);
+ return FALSE;
+ }
+
case IDC_BTADDPATH:
{
TCHAR path[MAX_PATH] = { 0 };
@@ -241,6 +279,30 @@ intptr_t CALLBACK CompilerSettingsDialog::run_dlgProc(UINT message, WPARAM wPara
}
break;
}
+
+ case WM_NOTIFY:
+ {
+ switch (wParam)
+ {
+ case IDC_LNKWHATISTHIS:
+ {
+ NMHDR* nmhdr = reinterpret_cast(lParam);
+ switch (nmhdr->code)
+ {
+ case NM_CLICK:
+ case NM_RETURN:
+
+ whatIsThisDialog.init(_hInst, _hSelf);
+ whatIsThisDialog.doDialog();
+
+ return TRUE;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
}
// Signals done processing messages
@@ -312,6 +374,8 @@ bool CompilerSettingsDialog::keepSettings()
myset.ignoreInstallPaths = IsDlgButtonChecked(_hSelf, IDC_CHKIGNOREINSTALLPATHS);
+ myset.compilerEngine = (IsDlgButtonChecked(_hSelf, IDC_USEBEAMDOGCOMPILER) ? 0 : 1);
+
// If user has unsaved input in additional folders, save for him.
GetDlgItemText(_hSelf, IDC_TXTADDPATH, tempBuffer, std::size(tempBuffer));
if (tempBuffer[0] > 0)
diff --git a/src/Plugin Controls/LoggerDialog.cpp b/src/Plugin Controls/LoggerDialog.cpp
index 7f9d370..73de6b7 100644
--- a/src/Plugin Controls/LoggerDialog.cpp
+++ b/src/Plugin Controls/LoggerDialog.cpp
@@ -309,10 +309,10 @@ intptr_t LoggerDialog::childrenDlgProc(UINT message, WPARAM wParam, LPARAM lPara
// Dispatch to Plugin for processing.
generic_string fileName = r.fileName.empty() ? TEXT("") : r.fileName + TEXT(".") + r.fileExt;
- int lineNumber = r.lineNumber.empty() ? -1 : stoi(r.lineNumber);
+ int lineNumber = r.lineNumber.empty() || r.lineNumber[0] == '-' ? -1 : stoi(r.lineNumber);
// Only dispatch messages with valid line numbers
- if (navigateToFileCallback && lineNumber > -1)
+ if (navigateToFileCallback && (lineNumber > -1 || !fileName.empty()))
{
// HACK: To correct the file navigation issue, we store the current lineNumber being passed
// to navigateToFileCallback, so the timer on it can refer back to it.
diff --git a/src/Plugin Controls/PluginControls.rc b/src/Plugin Controls/PluginControls.rc
index dfafabb..c5529d5 100644
--- a/src/Plugin Controls/PluginControls.rc
+++ b/src/Plugin Controls/PluginControls.rc
@@ -114,17 +114,17 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "&OK",IDOK,143,293,50,14
PUSHBUTTON "&Cancel",IDCANCEL,254,293,50,14
- GROUPBOX "Neverwinter Nights Installation Folders (for loading nwscript.nss and other game resources)",IDC_STATIC,7,7,411,90
- LTEXT "Neverwinter Nights 1 (or Enhanced Edition)",IDC_STATIC,87,20,293,8
- CONTROL "Use this",IDC_USENWN1,"Button",BS_AUTORADIOBUTTON | WS_GROUP,32,33,41,10
- CONTROL "Use this",IDC_USENWN2,"Button",BS_AUTORADIOBUTTON,32,63,41,10
- EDITTEXT IDC_TXTNWN1INSTALL,86,31,294,14,ES_AUTOHSCROLL
- PUSHBUTTON "...",IDC_BTNWN1INSTALL,386,31,20,14
- LTEXT "Neverwinter Nights 2",IDC_STATIC,87,50,291,8
- EDITTEXT IDC_TXTNWN2INSTALL,85,60,294,14,ES_AUTOHSCROLL
- PUSHBUTTON "...",IDC_BTNWN2INSTALL,385,60,20,14
+ GROUPBOX "Neverwinter Nights Installation Folders",IDC_STATIC,7,7,284,90
+ LTEXT "Neverwinter Nights 1 (or Enhanced Edition)",IDC_STATIC,58,20,174,8
+ CONTROL "Use this",IDC_USENWN1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,15,33,41,10
+ CONTROL "Use this",IDC_USENWN2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,15,63,41,10
+ EDITTEXT IDC_TXTNWN1INSTALL,57,31,195,14,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BTNWN1INSTALL,261,31,20,14
+ LTEXT "Neverwinter Nights 2",IDC_STATIC,58,50,173,8
+ EDITTEXT IDC_TXTNWN2INSTALL,57,60,195,14,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BTNWN2INSTALL,261,60,20,14
CONTROL "Ignore installation paths.",IDC_CHKIGNOREINSTALLPATHS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,88,82,96,10
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,57,82,96,10
GROUPBOX "Additional Include Paths",IDC_STATIC,7,104,224,137
EDITTEXT IDC_TXTADDPATH,12,119,186,14,ES_AUTOHSCROLL
PUSHBUTTON "...",IDC_BTSEARCHPATH,204,119,20,14
@@ -134,20 +134,25 @@ BEGIN
GROUPBOX "Compiler Options",IDC_STATIC,248,104,170,137
CONTROL "Optimize script",IDC_CHKCOMPOPTIMIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,120,63,10
CONTROL "Enable non-Bioware's extensions",IDC_CHKNONBIOWAREXTENSIONS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,136,121,10
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,168,121,10
CONTROL "Generate (.ndb) debug symbols files",IDC_CHKCOMPNDBSYMBOLS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,153,132,10
- CONTROL "Enable strict mode",IDC_CHKCOMPSTRICTMODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,169,75,10
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,136,132,10
+ CONTROL "Enable strict mode",IDC_CHKCOMPSTRICTMODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,185,75,10
CONTROL "Create makefile (.d) dependencies files",IDC_CHKCOMPMAKEFILE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,185,141,10
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,152,141,10
CONTROL "Disable parsing of \\"" and \\\\ tokens",IDC_CHKCOMPDISABLESLASHPARSE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,263,201,135,10
COMBOBOX IDC_CBOTARGETVERSION,262,219,48,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Target game version",IDC_STATIC,317,220,67,8
+ LTEXT "Target game version",IDC_LBLTARGETVERSION,317,220,67,8
GROUPBOX "Output Directory",IDC_STATIC,7,246,411,40
CONTROL "Same of the script file",IDC_CHKOUTPUTDIR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,264,85,10
EDITTEXT IDC_TXTOUTPUTDIR,115,261,263,14,ES_AUTOHSCROLL
PUSHBUTTON "...",IDC_BTOUTPUTDIR,383,261,20,14
+ GROUPBOX "Compiler Engine",IDC_STATIC,300,7,118,90
+ CONTROL "Beamdog's Native Compiler",IDC_USEBEAMDOGCOMPILER,
+ "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,310,33,102,10
+ CONTROL "Legacy NscLib Compiler",IDC_USELEGACYCOMPILER,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,310,61,90,10
+ CONTROL "What is this?",IDC_LNKWHATISTHIS,"SysLink",0x0,334,81,41,11
END
IDD_BATCHPROCESS DIALOGEX 0, 0, 409, 171
@@ -231,6 +236,16 @@ BEGIN
CONTROL "",IDC_BTFILTERINFO,"Button",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE,396,5,17,14
END
+IDD_WHATISTHIS DIALOGEX 0, 0, 347, 195
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_WINDOWEDGE
+CAPTION "What is this?"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&OK",IDOK,147,174,50,14
+ CONTROL "",IDC_TXTHELP,"RichEdit50W",WS_BORDER | WS_VSCROLL | WS_TABSTOP | 0x804,7,7,333,158
+END
+
/////////////////////////////////////////////////////////////////////////////
//
@@ -323,6 +338,14 @@ BEGIN
TOPMARGIN, 2
BOTTOMMARGIN, 123
END
+
+ IDD_WHATISTHIS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 340
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 188
+ END
END
#endif // APSTUDIO_INVOKED
@@ -387,6 +410,11 @@ BEGIN
0
END
+IDD_WHATISTHIS AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
/////////////////////////////////////////////////////////////////////////////
//
@@ -459,6 +487,8 @@ IDI_REPAIR SVG "..\\..\\Media\\icons-svg\\Repai
IDI_APPLICATIONACCESS SVG "..\\..\\Media\\icons-svg\\ApplicationAccess.svg"
+IDI_HELPTABLECONTENTS SVG "..\\..\\Media\\icons-svg\\HelpTableOfContents.svg"
+
/////////////////////////////////////////////////////////////////////////////
//
@@ -469,6 +499,10 @@ IDR_ABOUTDOC RTF "..\\..\\Media\\OnlineHelp.rtf"
IDR_ABOUTDOCDARK RTF "..\\..\\Media\\OnlineHelp-Dark.rtf"
+IDR_COMPILERENGINE RTF "..\\..\\Media\\CompilerEngine.rtf"
+
+IDR_COMPILERENGINEDARK RTF "..\\..\\Media\\CompilerEngine-Dark.rtf"
+
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/src/Plugin Controls/PluginControlsRC.h b/src/Plugin Controls/PluginControlsRC.h
index 3ed68c2..07225f6 100644
--- a/src/Plugin Controls/PluginControlsRC.h
+++ b/src/Plugin Controls/PluginControlsRC.h
@@ -1,6 +1,6 @@
//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by PluginControls.rc
+// Arquivo de inclusão gerado pelo Microsoft Visual C++.
+// Usado por PluginControls.rc
//
#define IDD_ABOUT 102
#define IDB_HEREBEDRAGONS 103
@@ -46,6 +46,11 @@
#define IDI_REPAIR 187
#define IDB_NWSCRIPTLOGO_SIMPLIFIED 188
#define IDI_APPLICATIONACCESS 189
+#define IDD_WHATISTHIS 190
+#define IDR_COMPILERENGINE 192
+#define IDR_COMPILERENGINEDARK 193
+#define IDR_SVG1 194
+#define IDI_HELPTABLECONTENTS 194
#define IDC_LNKHOMEPAGE 1000
#define IDC_TXTABOUT 1001
#define IDC_LBLPLUGINNAME 1002
@@ -115,6 +120,12 @@
#define IDC_PCTNWSCRIPTFILELOGOBOX 1079
#define IDC_PCTABOUTLOGOBOX 1080
#define IDC_PCTFILEACCESSLOGOBOX 1081
+#define IDC_USEBEAMDOGCOMPILER 1082
+#define IDC_USELEGACYCOMPILER 1083
+#define IDC_WHATISTHIS 1084
+#define IDC_LNKWHATISTHIS 1084
+#define IDC_LBLTARGETVERSION 1085
+#define IDC_TXTHELP 1086
#define IDC_STATIC -1
#define IDC_HEREBEDRAGONS -1
#define IDC_LBLSOLUTION -1
@@ -123,9 +134,9 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 190
+#define _APS_NEXT_RESOURCE_VALUE 195
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1082
+#define _APS_NEXT_CONTROL_VALUE 1087
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/src/WarningDialog.cpp b/src/Plugin Controls/WarningDialog.cpp
similarity index 100%
rename from src/WarningDialog.cpp
rename to src/Plugin Controls/WarningDialog.cpp
diff --git a/src/WarningDialog.h b/src/Plugin Controls/WarningDialog.h
similarity index 100%
rename from src/WarningDialog.h
rename to src/Plugin Controls/WarningDialog.h
diff --git a/src/Plugin Controls/WhatIsThisDialog.cpp b/src/Plugin Controls/WhatIsThisDialog.cpp
new file mode 100644
index 0000000..abe69a8
--- /dev/null
+++ b/src/Plugin Controls/WhatIsThisDialog.cpp
@@ -0,0 +1,238 @@
+/** @file ProcessFilesDialog.cpp
+ * Process Files dialog box
+ *
+ **/
+ // Copyright (C) 2022 - Leonardo Silva
+ // The License.txt file describes the conditions under which this software may be distributed.
+
+#include "pch.h"
+//#include
+//#include
+//#include
+
+#include "PluginMain.h"
+#include "WhatIsThisDialog.h"
+
+#include "PluginControlsRC.h"
+#include "PluginDarkMode.h"
+
+
+using namespace NWScriptPlugin;
+
+BEGIN_ANCHOR_MAP(WhatIsThisDialog)
+ ANCHOR_MAP_ADDGLOBALSIZERESTRICTION(mainWindowSize)
+ ANCHOR_MAP_ENTRY(_hSelf, IDC_TXTHELP, ANF_ALL)
+ ANCHOR_MAP_ENTRY(_hSelf, IDOK, ANF_BOTTOM)
+ ANCHOR_MAP_ADDSIZERESTRICTION(_hSelf, IDC_TXTHELP, txtHelpSize)
+END_ANCHOR_MAP(_hSelf)
+
+
+
+DWORD CALLBACK EditStreamCallback2(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, PLONG pcb)
+{
+ IStream* pstm = (IStream*)dwCookie;
+ DWORD fail = FAILED(pstm->Read(lpBuff, cb, (ULONG*)pcb));
+ return fail;
+}
+
+void WhatIsThisDialog::LoadHelpTextEditor(int resourceID)
+{
+ _currentDocumentID = resourceID;
+
+ // Load resource
+ auto hResource = FindResourceW(_hInst, MAKEINTRESOURCE(_currentDocumentID), L"RTF");
+ HGLOBAL hMemory = NULL;
+ LPVOID ptr = NULL;
+ size_t _size = 0;
+
+ if (hResource)
+ {
+ _size = SizeofResource(_hInst, hResource);
+ hMemory = LoadResource(_hInst, hResource);
+
+ if (hMemory)
+ ptr = LockResource(hMemory);
+ }
+
+ // Copy image bytes into a real hglobal memory handle
+ hMemory = ::GlobalAlloc(GHND, _size);
+ if (hMemory)
+ {
+ void* pBuffer = ::GlobalLock(hMemory);
+ if (pBuffer && ptr)
+ memcpy(pBuffer, ptr, _size);
+ }
+
+ // Make a raw string of resources
+ std::string rawText;
+
+ if (ptr)
+ rawText.assign((char*)ptr, _size);
+
+ // HACK: change Bk Color of dark mode without messages
+ std::map replaceStrings;
+ replaceStrings.insert({ L"4210752", std::to_wstring(PluginDarkMode::getSofterBackgroundColor()) });
+ generic_string rawTextW = replaceStringsW(str2wstr(rawText), replaceStrings);
+
+ // Free memory allocated for resource
+ if (hMemory)
+ GlobalFree(hMemory);
+
+ // Now, redo the allocated space with the new size (with replaced texts) and copy modified text again
+ hMemory = ::GlobalAlloc(GHND, rawTextW.size());
+ if (hMemory)
+ {
+ void* pBuffer = ::GlobalLock(hMemory);
+ if (pBuffer)
+ memcpy(pBuffer, wstr2str(rawTextW).c_str(), rawTextW.size());
+ }
+
+ // Create stream on hMemory
+ IStream* pStream = nullptr;
+ HRESULT hr = CreateStreamOnHGlobal(hMemory, TRUE, &pStream);
+ if (SUCCEEDED(hr))
+ {
+ // Set paramenters
+ EDITSTREAM es = { (DWORD_PTR)pStream, 0, EditStreamCallback2 };
+ HWND editControl = GetDlgItem(_hSelf, IDC_TXTHELP);
+ SendMessage(editControl, EM_EXLIMITTEXT, 0, -1);
+ SendMessage(editControl, EM_SETEVENTMASK, 0, ENM_LINK);
+ //SendMessage(editControl, EM_SETOLECALLBACK, 0, reinterpret_cast(&_whatIsThisOleCallback));
+
+ // Load Document
+ SendMessage(editControl, EM_SETREADONLY, 0, 0); // Set readonly off or images may not load properly
+ SendMessage(editControl, EM_STREAMIN, SF_RTF, reinterpret_cast(&es));
+ SendMessage(editControl, EM_SETREADONLY, 1, 0);
+
+ // Retrieve raw buffer from TXTABOUT for replace strings and later use with hyperlink clicks
+ GETTEXTLENGTHEX tl = { GTL_NUMCHARS, 1200 };
+ _helpText.resize(SendMessage(editControl, EM_GETTEXTLENGTHEX, reinterpret_cast(&tl), 0) + 1);
+ GETTEXTEX tex = { (DWORD)_helpText.size() * sizeof(TCHAR), GT_RAWTEXT, 1200, NULL, NULL };
+ SendMessage(editControl, EM_GETTEXTEX, reinterpret_cast(&tex), reinterpret_cast(_helpText.data()));
+
+ if (PluginDarkMode::isEnabled())
+ SendMessage(editControl, EM_SETBKGNDCOLOR, 0, PluginDarkMode::getSofterBackgroundColor());
+ }
+
+ // Free memory allocated for resource again
+ if (hMemory)
+ GlobalFree(hMemory);
+
+}
+
+intptr_t CALLBACK WhatIsThisDialog::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ _dpiManager.resizeControl(_hSelf);
+ _dpiManager.resizeChildren(_hSelf, true);
+
+ mainWindowSize = { {_dpiManager.scaleX(537), _dpiManager.scaleY(356)} };
+ txtHelpSize = { { _dpiManager.scaleX(500), _dpiManager.scaleY(257) } };
+
+ // Make window zoomable
+ LONG extStyle = GetWindowLong(GetDlgItem(_hSelf, IDC_TXTHELP), GWL_EXSTYLE);
+ extStyle |= ES_EX_ZOOMABLE;
+ SetWindowLong(GetDlgItem(_hSelf, IDC_TXTHELP), GWL_EXSTYLE, extStyle);
+
+ PluginDarkMode::autoSetupWindowAndChildren(_hSelf);
+
+ LoadHelpTextEditor(PluginDarkMode::isEnabled() ? IDR_COMPILERENGINEDARK : IDR_COMPILERENGINE);
+
+ // Setup control anchors
+ InitAnchors();
+
+ // Load PNG image for window logo
+ HICON hAbout = loadSVGFromResourceIcon(_hInst, IDI_HELPTABLECONTENTS, PluginDarkMode::isEnabled(), _dpiManager.scaleX(16), _dpiManager.scaleY(16));
+ ::SendMessage(_hSelf, WM_SETICON, ICON_SMALL, reinterpret_cast(hAbout));
+
+ return TRUE;
+ }
+
+ /*
+ case WM_KEYDOWN:
+ {
+ WORD vkCode = LOWORD(wParam); // virtual-key code
+ WORD keyFlags = HIWORD(lParam);
+
+ switch (vkCode)
+ {
+ case VK_RETURN:
+ case VK_ESCAPE:
+ EndDialog(_hSelf, wParam);
+ return TRUE;
+ }
+ }
+ */
+
+ case WM_COMMAND:
+ {
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(_hSelf, wParam);
+ break;
+ }
+ break;
+ }
+
+ case WM_SIZE:
+ ANCHOR_MAP_HANDLESIZERS();
+
+ case WM_GETMINMAXINFO:
+ ANCHOR_MAP_HANDLERESTRICTORS(wParam, lParam);
+
+ case WM_NOTIFY:
+ {
+ switch (wParam)
+ {
+
+ case IDC_TXTHELP:
+ {
+ NMHDR* nmhdr = reinterpret_cast(lParam);
+ switch (nmhdr->code)
+ {
+ case EN_LINK:
+ {
+ ENLINK* enLinkInfo = (ENLINK*)lParam;
+ if (enLinkInfo->msg == WM_SETCURSOR)
+ {
+ SetCursor(LoadCursor(NULL, IDC_HAND));
+ }
+
+ if (enLinkInfo->msg == WM_LBUTTONUP)
+ {
+ LaunchHyperlink(*enLinkInfo);
+ }
+
+ return TRUE;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+
+ }
+
+ // Signals done processing messages
+ return FALSE;
+}
+
+void WhatIsThisDialog::LaunchHyperlink(const ENLINK& link)
+{
+ // Get text range from raw string
+ generic_string url = _helpText.substr(link.chrg.cpMin, link.chrg.cpMax - link.chrg.cpMin);
+ ShellExecute(NULL, L"open", url.c_str(), NULL, NULL, SW_SHOW);
+}
+
+
+INT_PTR WhatIsThisDialog::doDialog()
+{
+ return ShowModal(IDD_WHATISTHIS);
+}
diff --git a/src/Plugin Controls/WhatIsThisDialog.h b/src/Plugin Controls/WhatIsThisDialog.h
new file mode 100644
index 0000000..b4405ea
--- /dev/null
+++ b/src/Plugin Controls/WhatIsThisDialog.h
@@ -0,0 +1,56 @@
+/** @file ProcessFilesDialog.h
+ * Process Files dialog Box
+ *
+ **/
+ // Copyright (C) 2022 - Leonardo Silva
+ // The License.txt file describes the conditions under which this software may be distributed.
+
+#pragma once
+#include "ModalDialog.h"
+#include "AnchorMap.h"
+
+#include "Common.h"
+
+namespace NWScriptPlugin {
+
+ class WhatIsThisDialog : public ModalDialog
+ {
+ public:
+ WhatIsThisDialog() = default;
+
+ ~WhatIsThisDialog() {
+ if (_hWindowIcon)
+ DeleteObject(_hWindowIcon);
+ }
+
+ INT_PTR doDialog();
+
+ void setInterruptFlag(std::atomic& interruptFlagVariable) {
+ _interruptFlagVariable = &interruptFlagVariable;
+ }
+
+ void lockWindow(bool toLock) {
+ EnableWindow(_hSelf, !toLock);
+ }
+
+ protected:
+ virtual intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam);
+ std::atomic* _interruptFlagVariable;
+
+ private:
+
+ DECLARE_ANCHOR_MAP()
+
+ // Anchoring and size restriction informations
+ RECTSIZER mainWindowSize = {};
+ RECTSIZER txtHelpSize = {};
+
+ generic_string _helpText;
+ int _currentDocumentID = 0;
+
+ HICON _hWindowIcon = nullptr;
+
+ void LoadHelpTextEditor(int resourceID);
+ void LaunchHyperlink(const ENLINK& link);
+ };
+}
diff --git a/src/PluginMain.cpp b/src/PluginMain.cpp
index 407154c..0551c83 100644
--- a/src/PluginMain.cpp
+++ b/src/PluginMain.cpp
@@ -610,6 +610,18 @@ void Plugin::ProcessMessagesSci(SCNotification* notifyCode)
// Initially disable run last batch (until the user runs a batch in session)
EnablePluginMenuItem(PLUGINMENU_RUNLASTBATCH, false);
+ // Check whether to enable legacy options based on script engine chosen
+ if (Settings().compilerEngine == 0)
+ {
+ EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, false);
+ EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, false);
+ }
+ else
+ {
+ EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, true);
+ EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, true);
+ }
+
// Detects Dark Mode support. Can be done by messaging Notepad++ for newer versions
// Or if the messages aren't supported (on a previous version), checks the installation on Notepad++ config.xml.
// Note: Dark Mode is different from Dark Theme - 1st is for the plugin GUI, the second is for NWScript file lexing.
@@ -1201,8 +1213,26 @@ void Plugin::LockPluginMenu(bool toLock)
EnablePluginMenuItem(PLUGINMENU_DISASSEMBLESCRIPT, !toLock);
EnablePluginMenuItem(PLUGINMENU_BATCHPROCESSING, !toLock);
- EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, !toLock);
- EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, !toLock);
+ // These depend also on engine settings
+ if (!toLock)
+ {
+ if (Settings().compilerEngine == 0)
+ {
+ EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, false);
+ EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, false);
+ }
+ else
+ {
+ EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, true);
+ EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, true);
+ }
+ }
+ else
+ {
+ EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, false);
+ EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, false);
+ }
+
EnablePluginMenuItem(PLUGINMENU_SHOWCONSOLE, !toLock);
EnablePluginMenuItem(PLUGINMENU_SETTINGS, !toLock);
EnablePluginMenuItem(PLUGINMENU_USERPREFERENCES, !toLock);
@@ -2846,7 +2876,7 @@ void Plugin::NavigateToCode(const generic_string& fileName, size_t lineNum, cons
// Navigate to line
// HACK: For some reason, the normal operation won't work if the file doesn't have the focus.
// So we schedule the execution to happen assynchronously with the smallest possible time frame.
- if (success)
+ if (success && lineNum > -1)
{
SetTimer(Instance().NotepadHwnd(), NAGIVATECALLBACKTIMER, USER_TIMER_MINIMUM, (TIMERPROC)RunScheduledReposition);
}
@@ -3085,6 +3115,20 @@ PLUGINCOMMAND Plugin::CompilerSettings()
compilerSettings.init(Instance().DllHModule(), Instance().NotepadHwnd());
compilerSettings.appendSettings(&Instance()._settings);
compilerSettings.doDialog();
+
+ // Disable or enable some menu options depending which engine was chosen
+ Plugin& inst = Instance();
+
+ if (inst.Settings().compilerEngine == 0)
+ {
+ inst.EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, false);
+ inst.EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, false);
+ }
+ else
+ {
+ inst.EnablePluginMenuItem(PLUGINMENU_FETCHPREPROCESSORTEXT, true);
+ inst.EnablePluginMenuItem(PLUGINMENU_VIEWSCRIPTDEPENDENCIES, true);
+ }
}
// Opens the user's preferences.
diff --git a/src/ProjectVersion.h b/src/ProjectVersion.h
index 0108781..c12bd3d 100644
--- a/src/ProjectVersion.h
+++ b/src/ProjectVersion.h
@@ -22,9 +22,9 @@
#define stringify(a) stringify_(a)
#define VERSION_MAJOR 1
-#define VERSION_MINOR 1
+#define VERSION_MINOR 2
#define VERSION_PATCH 0
-#define VERSION_BUILD 2150
+#define VERSION_BUILD 2300
#define VERSION_STRING stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." \
stringify(VERSION_PATCH) "." stringify(VERSION_BUILD)
diff --git a/src/Settings.cpp b/src/Settings.cpp
index b2197bf..8d7059b 100644
--- a/src/Settings.cpp
+++ b/src/Settings.cpp
@@ -52,6 +52,7 @@ void Settings::Load()
neverwinterTwoInstallDir = properDirNameW(GetString(TEXT("Compiler Settings"), TEXT("neverwinterTwoInstallDir")));
ignoreInstallPaths = GetBoolean(TEXT("Compiler Settings"), TEXT("ignoreInstallPaths"));
additionalIncludeDirs = GetString(TEXT("Compiler Settings"), TEXT("additionalIncludeDirs"));
+ compilerEngine = GetNumber(TEXT("Compiler Settings"), TEXT("compilerEngine"));
compilerFlags = GetNumber(TEXT("Compiler Settings"), TEXT("compilerFlags"));
optimizeScript = GetBoolean(TEXT("Compiler Settings"), TEXT("optimizeScript"));
useNonBiowareExtenstions = GetBoolean(TEXT("Compiler Settings"), TEXT("useNonBiowareExtenstions"));
@@ -173,6 +174,7 @@ void Settings::Save()
SetString(TEXT("Compiler Settings"), TEXT("neverwinterTwoInstallDir"), neverwinterTwoInstallDir);
SetBoolean(TEXT("Compiler Settings"), TEXT("ignoreInstallPaths"), ignoreInstallPaths);
SetString(TEXT("Compiler Settings"), TEXT("additionalIncludeDirs"), additionalIncludeDirs);
+ SetNumber(TEXT("Compiler Settings"), TEXT("compilerEngine "), compilerEngine);
SetNumber(TEXT("Compiler Settings"), TEXT("compilerFlags"), compilerFlags);
SetBoolean(TEXT("Compiler Settings"), TEXT("optimizeScript"), optimizeScript);
SetBoolean(TEXT("Compiler Settings"), TEXT("useNonBiowareExtenstions"), useNonBiowareExtenstions);
diff --git a/src/Settings.h b/src/Settings.h
index b1d2faf..f0ed7f2 100644
--- a/src/Settings.h
+++ b/src/Settings.h
@@ -51,6 +51,7 @@ namespace NWScriptPlugin {
generic_string neverwinterOneInstallDir;
generic_string neverwinterTwoInstallDir;
bool ignoreInstallPaths = false;
+ int compilerEngine = 0;
UINT32 compilerFlags = 0;
bool optimizeScript = true;
bool useNonBiowareExtenstions = false;