Files
int2ssl/FalloutScriptStore.cpp
T

1137 lines
38 KiB
C++

/**
*
* Copyright (c) 2005-2009 Anchorite (TeamX), <anchorite2001@yandex.ru>
* Copyright (c) 2014-2015 Nirran, phobos2077
* Copyright (c) 2015 alexeevdv <mail@alexeevdv.ru>
* Distributed under the GNU GPL v3. For full terms see the file license.txt
*
*/
// C++ standard includes
#include <iostream>
#include <fstream>
// int2ssl includes
#include "FalloutScript.h"
#include "ObjectAttributes.h"
#include "Utility.h"
// Third party includes
extern std::string g_strIndentFill;
extern std::ofstream g_ifstream;
extern std::ofstream g_ofstream;
void CFalloutScript::StoreTree()
{
std::string strOutLine;
g_ofstream << "============== Procedures ==================" << std::endl;
g_ofstream << std::endl;
for(uint32_t nIndexOfProc = 0; nIndexOfProc < m_ProcTable.GetSize(); nIndexOfProc++)
{
g_ofstream << format("%d: %s (0x%08x)", nIndexOfProc, m_Namespace[m_ProcTable[nIndexOfProc].m_ulNameOffset].c_str(), m_ProcTable[nIndexOfProc].m_ulBodyOffset) << std::endl;
g_ofstream << "===============================" << std::endl;
if (m_ProcTable[nIndexOfProc].m_ulType & P_CONDITIONAL)
{
g_ofstream << "Condition" << std::endl;
g_ofstream << "===============================" << std::endl;
for(uint32_t i = 0; i < m_Conditions[nIndexOfProc].size(); i++)
{
g_ofstream << format("0x%08X: ", m_Conditions[nIndexOfProc][i].m_ulOffset) << std::endl;
m_Conditions[nIndexOfProc][i].StoreTree(0, 0);
}
g_ofstream << std::endl;
g_ofstream << "Body" << std::endl;
g_ofstream << "===============================" << std::endl;
}
for(uint32_t i = 0; i < m_ProcBodies[nIndexOfProc].size(); i++)
{
g_ofstream << format("0x%08X: ", m_ProcBodies[nIndexOfProc][i].m_ulOffset) << std::endl;
m_ProcBodies[nIndexOfProc][i].StoreTree(0, 0);
}
g_ofstream << std::endl;
}
}
void CFalloutScript::StoreSource()
{
StoreDefinitions();
g_ofstream << std::endl;
g_ofstream << std::endl;
StoreDeclarations();
}
void CFalloutScript::StoreDefinitions()
{
std::string c_strBogusProcedureName("..............");
std::string c_strArgumentTemplate("arg%u");
printf(" Storing definitions\n");
// Unnamed global variables
int32_t nNamesCount = m_Namespace.GetSize();
int32_t nDefinitionsCount = m_Definitions.GetSize();
std::string strDefinition;
uint32_t ulVarValue;
if (nNamesCount != nDefinitionsCount)
{
g_ofstream << "/*******************************************************" << std::endl
<< "* Some unreferenced imported varables found. *" << std::endl
<< "* Because of it it is impossible to specify *" << std::endl
<< "* the real names of global variables. *" << std::endl
<< "*******************************************************/" << std::endl
<< std::endl;
for(uint32_t i = 0; i < m_GlobalVar.size(); i++)
{
ulVarValue = m_GlobalVar[i].GetArgument();
strDefinition = "variable ";
strDefinition += m_GlobalVarsNames[i];
switch(m_GlobalVar[i].GetOperator())
{
case COpcode::O_STRINGOP:
strDefinition = format(strDefinition + " := \"%s\"", escape_str(m_Stringspace[ulVarValue]).c_str());
break;
case COpcode::O_FLOATOP:
strDefinition = format(strDefinition + " := %.5f", int2ssl::bit_cast<float>(ulVarValue));
break;
case COpcode::O_INTOP:
if (ulVarValue != 0)
{
strDefinition = format(strDefinition + " := %d", (long)ulVarValue);
}
break;
}
strDefinition += ";";
if ((m_GlobalVar[i].GetOperator() == COpcode::O_INTOP) && (ulVarValue & 0x80000000))
{
strDefinition = format(strDefinition + " /* (%d) */", ulVarValue);
}
g_ofstream << strDefinition << std::endl;
}
g_ofstream << std::endl;
}
// Named objects
uint32_t ulNameOffset;
CDefObject defObject;
enum OutDefObject {
OUT_NOTHING,
OUT_UNKNOWN_VARIABLE,
OUT_GLOBAL_VARIABLE,
OUT_EXPORTED_VARIABLE,
OUT_IMPORTED_VARIABLE,
OUT_PROCEDURE,
OUT_EXPORTED_PROCEDURE,
OUT_IMPORTED_PROCEDURE
};
OutDefObject lastOut = OUT_NOTHING;
OutDefObject currentOut = OUT_NOTHING;
CProcDescriptor procDescriptor;
for(int32_t i = 0; i < m_Namespace.GetSize(); i++)
{
ulNameOffset = m_Namespace.GetOffsetByIndex(i);
if (i == 0)
{
if (m_Namespace[ulNameOffset] == c_strBogusProcedureName)
{
continue;
}
else
{
std::cout << "Warning: Bogus procedure with name "
<< c_strBogusProcedureName
<< " not found at expected location" << std::endl;
}
}
if (m_Definitions.Lookup(ulNameOffset, defObject))
{
strDefinition = "";
switch(defObject.m_ObjectType)
{
case CDefObject::OBJECT_PROCEDURE:
procDescriptor = m_ProcTable[defObject.m_ulProcIndex];
if (procDescriptor.m_ulType & P_IMPORT)
{
strDefinition = "import ";
currentOut = OUT_IMPORTED_PROCEDURE;
}
else if (procDescriptor.m_ulType & P_EXPORT)
{
strDefinition = "export ";
currentOut = OUT_EXPORTED_PROCEDURE;
}
else
{
currentOut = OUT_PROCEDURE;
}
strDefinition += "procedure ";
strDefinition += m_Namespace[ulNameOffset];
if (procDescriptor.m_ulNumArgs != 0)
{
strDefinition += "(";
for(uint32_t i = 0; i < procDescriptor.m_ulNumArgs; i++)
{
if (i == 0)
{
strDefinition = format(strDefinition + "variable " + c_strArgumentTemplate.c_str(), i);
}
else
{
strDefinition = format(strDefinition + ", variable " + c_strArgumentTemplate.c_str(), i);
}
}
strDefinition += ")";
}
strDefinition += ";";
if (procDescriptor.m_ulType & P_NOTIMPLEMENTED)
{
strDefinition += " /* Prodedure defined, but not implemented */";
}
break;
case CDefObject::OBJECT_VARIABLE:
if (defObject.m_ulAttributes & V_IMPORT)
{
strDefinition = "import ";
currentOut = OUT_IMPORTED_VARIABLE;
}
else if (defObject.m_ulAttributes & V_EXPORT)
{
strDefinition = "export ";
currentOut = OUT_EXPORTED_VARIABLE;
}
else
{
currentOut = OUT_GLOBAL_VARIABLE;
}
strDefinition += "variable ";
strDefinition += m_Namespace[ulNameOffset];
if (!(defObject.m_ulAttributes & V_IMPORT))
{
switch(defObject.m_ulAttributes & 0xFFFF)
{
case COpcode::O_STRINGOP:
strDefinition = format(strDefinition + " := \"%s\"", escape_str(m_Stringspace[defObject.m_ulVarValue]).c_str());
break;
case COpcode::O_FLOATOP:
strDefinition = format(strDefinition + " := %.5f", int2ssl::bit_cast<float>(defObject.m_ulVarValue));
break;
case COpcode::O_INTOP:
if (defObject.m_ulVarValue != 0)
{
strDefinition = format(strDefinition + " := %d", (long)defObject.m_ulVarValue);
}
break;
}
}
strDefinition += ";";
}
}
else
{
currentOut = OUT_UNKNOWN_VARIABLE;
strDefinition = "/* ?import? variable ";
strDefinition += m_Namespace.GetStringByIndex(i) + "; */";
}
if ((currentOut != lastOut) && (lastOut != OUT_NOTHING))
{
g_ofstream << std::endl;
}
lastOut = currentOut;
g_ofstream << strDefinition << std::endl;
}
}
void CFalloutScript::StoreDeclarations()
{
std::string c_strBogusProcedureName("..............");
std::string c_strArgumentTemplate("arg%u");
std::string c_strLocalVarTemplate("LVar%u");
std::cout << " Storing declarations" << std::endl;
std::string strOutLine;
for(uint32_t i = 0; i < m_ProcTable.GetSize(); i++)
{
std::cout << format(" Procedure: %d", i) << std::endl;
// Bogus procedure
if ((i == 0) && (m_Namespace[m_ProcTable[i].m_ulNameOffset] == c_strBogusProcedureName))
{
continue;
}
// Empty procedure
if (m_ProcTable.GetSizeOfProc(i) == 0)
{
if ((m_ProcTable[i].m_ulType & P_IMPORT) != 0)
{
continue;
}
g_ofstream << "/*******************************************************" << std::endl
<< "* Found Procedure without body. *" << std::endl
<< "* *" << std::endl;
strOutLine = "* Name: ";
strOutLine+= m_Namespace[m_ProcTable[i].m_ulNameOffset];
while(strOutLine.length() < 55)
{
strOutLine += " ";
}
strOutLine += "*";
g_ofstream << strOutLine << std::endl
<< "* *" << std::endl;
if (!(m_ProcTable[i].m_ulType & P_NOTIMPLEMENTED))
{
g_ofstream << "* Other possible name(s): *" << std::endl;
for(uint32_t j = i + 1; j < m_ProcTable.GetSize(); j++)
{
if (m_ProcTable[j].m_ulBodyOffset == m_ProcTable[i].m_ulBodyOffset)
{
strOutLine = "* ";
strOutLine+= m_Namespace[m_ProcTable[j].m_ulNameOffset];
while(strOutLine.length() < 55)
{
strOutLine += " ";
}
strOutLine += "*";
g_ofstream << strOutLine << std::endl;
strOutLine = "* ";
}
}
}
else
{
g_ofstream << "* Not implemented *" << std::endl;
}
g_ofstream << "* *" << std::endl
<< "*******************************************************/" << std::endl
<< std::endl;
continue;
}
// 'Normal' procedure
CProcDescriptor procDescriptor = m_ProcTable[i];
if (procDescriptor.m_ulType & P_CRITICAL)
{
strOutLine = "critical ";
}
else
{
strOutLine = "";
}
strOutLine += "procedure ";
strOutLine+= m_Namespace[m_ProcTable[i].m_ulNameOffset];
if (procDescriptor.m_ulNumArgs != 0)
{
strOutLine += "(";
for(uint32_t i = 0; i < procDescriptor.m_ulNumArgs; i++)
{
if (i == 0)
{
strOutLine = format(strOutLine + "variable " + c_strArgumentTemplate.c_str(), i);
}
else
{
strOutLine = format(strOutLine + ", variable " + c_strArgumentTemplate.c_str(), i);
}
}
strOutLine += ")";
}
if (procDescriptor.m_ulType & P_TIMED)
{
strOutLine = format(strOutLine + " in %d", procDescriptor.m_ulTime);
}
else if (procDescriptor.m_ulType & P_CONDITIONAL)
{
strOutLine = format(strOutLine + " when (%s)", GetSource(m_Conditions[i][0], false, procDescriptor.m_ulNumArgs).c_str());
}
g_ofstream << strOutLine << std::endl;
bool bLocalVar = true;
uint32_t ulLocalVarIndex = procDescriptor.m_ulNumArgs;
int32_t nIndentLevel = 0;
//CNode::Type prevNodeType = CNode::TYPE_NORMAL;
for(uint32_t nNodeIndex = 0; nNodeIndex < m_ProcBodies[i].size(); nNodeIndex++)
{
if (m_ProcBodies[i][nNodeIndex].m_Type == CNode::TYPE_BEGIN_OF_BLOCK)
{
if ((nNodeIndex > 1) && (m_ProcBodies[i][nNodeIndex - 1].m_Type == CNode::TYPE_END_OF_BLOCK))
{
g_ofstream << GetIndentString(nIndentLevel) << "else begin" << std::endl;
nIndentLevel++;
}
else
{
g_ofstream << "begin" << std::endl;
nIndentLevel++;
}
//prevNodeType = CNode::TYPE_BEGIN_OF_BLOCK;
}
else if (m_ProcBodies[i][nNodeIndex].m_Type == CNode::TYPE_END_OF_BLOCK)
{
nIndentLevel--;
g_ofstream << GetIndentString(nIndentLevel) << "end" << std::endl;
//prevNodeType = CNode::TYPE_END_OF_BLOCK;
}
else
{
//prevNodeType = CNode::TYPE_NORMAL;
uint16_t wOperator = m_ProcBodies[i][nNodeIndex].m_Opcode.GetOperator();
if ((m_ProcBodies[i][nNodeIndex].m_Opcode.GetAttributes().m_Type == COpcode::COpcodeAttributes::TYPE_EXPRESSION) &&
(wOperator != COpcode::O_STRINGOP) && (wOperator != COpcode::O_FLOATOP) && (wOperator != COpcode::O_INTOP))
{
printf("Warning: Result of expression is left in stack. (Opcode 0x%04X at 0x%08X)\n", wOperator, m_ProcBodies[i][nNodeIndex].m_ulOffset);
}
switch(wOperator)
{
case COpcode::O_STRINGOP:
case COpcode::O_FLOATOP:
case COpcode::O_INTOP:
{
if (!bLocalVar)
{
printf("Warning: Free value found. Converted to definition of local variable\n");
}
std::string str = "variable ";
str += c_strLocalVarTemplate + " := ";
strOutLine = format(str.c_str(), ulLocalVarIndex);
g_ofstream << GetIndentString(nIndentLevel) << strOutLine << GetSource(m_ProcBodies[i][nNodeIndex], false, procDescriptor.m_ulNumArgs) << ";" << std::endl;
ulLocalVarIndex++;
break;
}
case COpcode::O_IF:
g_ofstream << GetIndentString(nIndentLevel) << GetSource(m_ProcBodies[i][nNodeIndex], false, procDescriptor.m_ulNumArgs) << " then ";
break;
case COpcode::O_WHILE:
if (m_ProcBodies[i][nNodeIndex].m_Type == CNode::TYPE_FOR_LOOP)
{
std::string str = GetIndentString(nIndentLevel) + "for (";
for (uint32_t j = 0; j < m_ProcBodies[i][nNodeIndex].m_Arguments.size(); j++)
{
if (j > 0)
{
str += "; ";
}
str += GetSource(m_ProcBodies[i][nNodeIndex].m_Arguments[j], false, procDescriptor.m_ulNumArgs);
}
str += ") ";
g_ofstream << str;
}
else
{
g_ofstream << GetIndentString(nIndentLevel) << GetSource(m_ProcBodies[i][nNodeIndex], false, procDescriptor.m_ulNumArgs) << " do ";
}
break;
default:
g_ofstream << GetIndentString(nIndentLevel) << GetSource(m_ProcBodies[i][nNodeIndex], false, procDescriptor.m_ulNumArgs) << ";" << std::endl;
if ((m_ProcBodies[i][nNodeIndex].m_Type != CNode::TYPE_BEGIN_OF_BLOCK) &&
(m_ProcBodies[i][nNodeIndex].m_Type != CNode::TYPE_END_OF_BLOCK))
{
bLocalVar = false;
}
}
}
}
g_ofstream << std::endl;
}
}
std::string CFalloutScript::GetSource(CNode& node, bool bLabel, uint32_t ulNumArgs)
{
std::string c_strArgumentTemplate("arg%u");
std::string c_strLocalVarTemplate("LVar%u");
std::string strResult("Damn!!!");
if (node.m_Type == CNode::TYPE_OMITTED_ARGUMENT)
{
return "/* Omitted argument */";
}
uint16_t wOperator = node.m_Opcode.GetOperator();
uint32_t ulArgument = node.m_Opcode.GetArgument();
// sslc additions:
if (wOperator == COpcode::O_JMP)
{
if (node.m_Type == CNode::TYPE_BREAK)
{
return "break";
}
else if (node.m_Type == CNode::TYPE_CONTINUE)
{
return "continue";
}
}
switch(wOperator)
{
case COpcode::O_STRINGOP:
try
{
if (bLabel)
{
strResult = m_Namespace[ulArgument];
}
else
{
strResult = "\"";
strResult += escape_str(m_Stringspace[ulArgument]);
strResult += "\"";
}
}
catch(const std::exception& e)
{
std::cout << "Warning: Restoration after exception. Object name replaced with '/* Fake object name */'" << std::endl;
strResult = "/* Fake object name */";
}
break;
case COpcode::O_FLOATOP:
strResult = format("%.5f", int2ssl::bit_cast<float>(ulArgument));
break;
case COpcode::O_INTOP:
try
{
if (bLabel)
{
strResult = m_Namespace[ulArgument];
}
else
{
strResult = format("%d", (long)ulArgument);
}
}
catch(const std::exception& e)
{
std::cout << "Warning: Restoration after exception. Object name replaced with '/* Fake object name */'" << std::endl;
strResult = "/* Fake object name */";
}
break;
case COpcode::O_POP_RETURN:
strResult = "return ";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs);
break;
case COpcode::O_LOOKUP_STRING_PROC:
strResult = GetSource(node.m_Arguments[0], false, ulNumArgs);
break;
case COpcode::O_FETCH_GLOBAL:
if (node.m_Arguments[0].m_Opcode.GetOperator() != COpcode::O_INTOP)
{
std::cout << "Error: Invalid argument to O_FETCH_GLOBAL opcode" << std::endl;
throw std::exception();
}
if (uint32_t(node.m_Arguments[0].m_Opcode.GetArgument()) > m_GlobalVarsNames.size() - 1)
{
printf("Error: Invalid index of global variable\n");
throw std::exception();
}
strResult = m_GlobalVarsNames[node.m_Arguments[0].m_Opcode.GetArgument()];
break;
case COpcode::O_STORE_GLOBAL:
if (node.m_Arguments[1].m_Opcode.GetOperator() != COpcode::O_INTOP)
{
printf("Error: Invalid argument to O_STORE_GLOBAL opcode\n");
throw std::exception();
}
if (uint32_t(node.m_Arguments[1].m_Opcode.GetArgument()) > m_GlobalVarsNames.size() - 1)
{
printf("Error: Invalid index of global variable\n");
throw std::exception();
}
strResult = m_GlobalVarsNames[node.m_Arguments[1].m_Opcode.GetArgument()];
strResult += " := ";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs);
break;
case COpcode::O_FETCH_EXTERNAL:
{
uint16_t wOperator = node.m_Arguments[0].m_Opcode.GetOperator();
if ((wOperator != COpcode::O_STRINGOP) && (wOperator != COpcode::O_INTOP))
{
printf("Error: Invalid argument to O_FETCH_EXTERNAL opcode\n");
throw std::exception();
}
}
strResult = GetSource(node.m_Arguments[0], true, ulNumArgs);
break;
case COpcode::O_STORE_EXTERNAL:
{
uint16_t wOperator = node.m_Arguments[1].m_Opcode.GetOperator();
if ((wOperator != COpcode::O_STRINGOP) && (wOperator != COpcode::O_INTOP))
{
printf("Error: Invalid argument to O_STORE_EXTERNAL opcode\n");
throw std::exception();
}
}
strResult = GetSource(node.m_Arguments[1], true, ulNumArgs);
strResult += " := ";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs);
break;
case COpcode::O_FETCH:
if (node.m_Arguments[0].m_Opcode.GetOperator() != COpcode::O_INTOP)
{
printf("Error: Invalid argument to O_FETCH opcode\n");
throw std::exception();
}
{
uint32_t ulVarNum = node.m_Arguments[0].m_Opcode.GetArgument();
if (ulVarNum < ulNumArgs)
{
strResult = format(c_strArgumentTemplate.c_str(), ulVarNum);
}
else
{
strResult = format(c_strLocalVarTemplate.c_str(), ulVarNum);
}
}
break;
case COpcode::O_STORE:
if (node.m_Arguments[1].m_Opcode.GetOperator() != COpcode::O_INTOP)
{
printf("Error: Invalid argument to O_STORE opcode\n");
throw std::exception();
}
{
uint32_t ulVarNum = node.m_Arguments[1].m_Opcode.GetArgument();
if (ulVarNum < ulNumArgs)
{
strResult = format(c_strArgumentTemplate.c_str(), ulVarNum);
}
else
{
strResult = format(c_strLocalVarTemplate.c_str(), ulVarNum);
}
strResult += " := ";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs);
}
break;
case COpcode::O_POP:
strResult = GetSource(node.m_Arguments[0], false, ulNumArgs);
if (node.m_Arguments[0].m_Opcode.GetOperator() == COpcode::O_CALL)
{
strResult = "call " + strResult;
}
break;
case COpcode::O_CALL:
if (node.m_Arguments[node.m_Arguments.size() - 1].m_Opcode.GetOperator() == COpcode::O_INTOP)
{
strResult = m_Namespace[m_ProcTable[node.m_Arguments[node.m_Arguments.size() - 1].m_Opcode.GetArgument()].m_ulNameOffset];
}
else
{
strResult = GetSource(node.m_Arguments[node.m_Arguments.size() - 1], false, ulNumArgs);
}
strResult += "(";
for(uint32_t nArgIndex = 0; nArgIndex < node.m_Arguments.size() - 1 - 1; nArgIndex++)
{
if (nArgIndex == 0)
{
strResult += GetSource(node.m_Arguments[nArgIndex], false, ulNumArgs);
}
else
{
strResult += ", ";
strResult += GetSource(node.m_Arguments[nArgIndex], false, ulNumArgs);
}
}
strResult += ")";
break;
case COpcode::O_CALL_AT:
strResult = "call ";
if (node.m_Arguments[1].m_Opcode.GetOperator() == COpcode::O_INTOP)
{
strResult += m_Namespace[m_ProcTable[node.m_Arguments[1].m_Opcode.GetArgument()].m_ulNameOffset];
}
else
{
strResult += GetSource(node.m_Arguments[1], false, ulNumArgs);
}
strResult += " in (";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs) + ")";
break;
case COpcode::O_CALL_CONDITION:
strResult = "call ";
if (node.m_Arguments[1].m_Opcode.GetOperator() == COpcode::O_INTOP)
{
strResult += m_Namespace[m_ProcTable[node.m_Arguments[1].m_Opcode.GetArgument()].m_ulNameOffset];
}
else
{
strResult += GetSource(node.m_Arguments[1], false, ulNumArgs);
}
strResult += " when (";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs) + ")";
break;
case COpcode::O_ADDREGION:
strResult = "addRegion ";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs) + " { ";
for(uint32_t nArgIndex = 1; nArgIndex < node.m_Arguments.size() - 1; nArgIndex++)
{
if (nArgIndex == 1)
{
strResult += GetSource(node.m_Arguments[nArgIndex], false, ulNumArgs);
}
else
{
strResult += ", ";
strResult += GetSource(node.m_Arguments[nArgIndex], false, ulNumArgs);
}
}
strResult += " }";
break;
case COpcode::O_REFRESHMOUSE:
{
uint32_t aulProcArg[1] = { 1 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 1);
}
break;
case COpcode::O_ADDBUTTONPROC:
{
uint32_t aulProcArg[4] = { 2, 3, 4, 5 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 4);
}
break;
case COpcode::O_ADDBUTTONRIGHTPROC:
{
uint32_t aulProcArg[2] = { 2, 3 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 2);
}
break;
case COpcode::O_SAYOPTION:
{
if (node.m_Arguments[1].m_Opcode.GetOperator() == COpcode::O_INTOP)
{
uint32_t aulProcArg[2] = { 2 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 1);
}
else
{
strResult = "sayOption(";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs) + ", " + GetSource(node.m_Arguments[1], false, ulNumArgs) + ")";
}
}
break;
case COpcode::O_ADDREGIONPROC:
{
uint32_t aulProcArg[4] = { 2, 3, 4, 5 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 4);
}
break;
case COpcode::O_ADDREGIONRIGHTPROC:
{
uint32_t aulProcArg[2] = { 2, 3 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 2);
}
break;
case COpcode::O_ADDNAMEDEVENT:
{
uint32_t aulProcArg[1] = { 2 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 1);
}
break;
case COpcode::O_ADDNAMEDHANDLER:
{
uint32_t aulProcArg[1] = { 2 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 1);
}
break;
case COpcode::O_ADDKEY:
{
uint32_t aulProcArg[1] = { 2 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 1);
}
break;
case COpcode::O_GSAY_OPTION:
{
uint32_t aulProcArg[1] = { 3 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 1);
}
break;
case COpcode::O_GIQ_OPTION:
{
uint32_t aulProcArg[1] = { 4 };
strResult = GetSource(node, ulNumArgs, aulProcArg, 1);
}
break;
case COpcode::O_CANCEL:
if (node.m_Arguments[0].m_Opcode.GetOperator() != COpcode::O_INTOP)
{
printf("Error: Invalid argument to O_CANCEL opcode\n");
throw std::exception();
}
strResult = "cancel(";
strResult += m_Namespace[m_ProcTable[node.m_Arguments[0].m_Opcode.GetArgument()].m_ulNameOffset] + ")";
break;
case COpcode::O_NEGATE:
if (node.m_Arguments[0].m_Opcode.GetAttributes().m_Category == COpcode::COpcodeAttributes::CATEGORY_INFIX)
{
strResult = "-(";
strResult += GetSource(node.m_Arguments[0], bLabel, ulNumArgs) + ")";
}
else
{
strResult = "-";
strResult += GetSource(node.m_Arguments[0], bLabel, ulNumArgs);
}
break;
default:
COpcode::COpcodeAttributes attributes = node.m_Opcode.GetAttributes();
uint32_t *procArgs = attributes.m_procArgs;
uint32_t numProcArgs = attributes.m_numProcArgs;
if (numProcArgs > 0)
{
strResult = GetSource(node, ulNumArgs, procArgs, numProcArgs);
break;
}
if (node.m_Type == CNode::TYPE_CONDITIONAL_EXPRESSION)
{
if (node.m_Arguments.size() != 5)
{
printf("Error: Invalid number of arguments in conditional expression\n");
throw std::exception();
}
std::string sPostfix[] = { " if ", " else ", ""};
uint16_t argIdx[] = {2, 1, 3};
strResult = "";
for (uint32_t i = 0; i < 3; i++)
{
CNode& arg = node.m_Arguments[argIdx[i]];
bool bParens = ArgNeedParens(node, arg, CFalloutScript::RIGHT_ASSOC);
strResult += (bParens ? "(" : "") + GetSource(arg, bLabel, ulNumArgs) + (bParens ? ")" : "") + sPostfix[i];
}
break;
}
switch(attributes.m_Category)
{
case COpcode::COpcodeAttributes::CATEGORY_INFIX:
if (ArgNeedParens(node, node.m_Arguments[0], CFalloutScript::LEFT_ASSOC))
{
strResult = "(";
strResult += GetSource(node.m_Arguments[0], false, ulNumArgs) + ")";
}
else
{
strResult = GetSource(node.m_Arguments[0], false, ulNumArgs);
}
strResult += " ";
strResult += attributes.m_strName + " ";
if (ArgNeedParens(node, node.m_Arguments[1], CFalloutScript::RIGHT_ASSOC))
{
strResult += "(";
strResult += GetSource(node.m_Arguments[1], false, ulNumArgs) + ")";
}
else
{
strResult += GetSource(node.m_Arguments[1], false, ulNumArgs);
}
break;
case COpcode::COpcodeAttributes::CATEGORY_PREFIX:
strResult = attributes.m_strName;
if (node.m_Arguments.size() != 0)
{
if (wOperator == COpcode::O_IF || wOperator == COpcode::O_WHILE)
{
strResult += " ";
}
strResult += "(";
for(uint32_t i = 0; i < node.m_Arguments.size(); i++)
{
if (i == 0)
{
strResult += GetSource(node.m_Arguments[i], false, ulNumArgs);
}
else
{
strResult += ", ";
strResult += GetSource(node.m_Arguments[i], false, ulNumArgs);
}
}
strResult += ")";
}
break;
}
}
return strResult;
}
std::string CFalloutScript::GetSource( CNode& node, uint32_t ulNumArgs, uint32_t aulProcArg[], uint32_t ulProcArgCount)
{
COpcode::COpcodeAttributes attributes = node.m_Opcode.GetAttributes();
std::string strResult = attributes.m_strName + "(";
std::string strArgument;
bool bIsProcArg;
for(uint32_t nArgIndex = 0; nArgIndex < node.m_Arguments.size(); nArgIndex++)
{
bIsProcArg = false;
for(uint32_t ulProcArgIndex = 0; ulProcArgIndex < ulProcArgCount; ulProcArgIndex++)
{
if (nArgIndex == aulProcArg[ulProcArgIndex] - 1)
{
bIsProcArg = true;
break;
}
}
if (bIsProcArg)
{
if (node.m_Arguments[nArgIndex].m_Opcode.GetOperator() == COpcode::O_INTOP)
{
try
{
strArgument = m_Namespace[m_ProcTable[node.m_Arguments[nArgIndex].m_Opcode.GetArgument()].m_ulNameOffset];
}
catch(const std::exception& e)
{
printf("Warning: Restoration after exception. Object name replaced with '/* Fake object name */'\n");
strArgument = format("/* Fake object name: %u (%d)*/", node.m_Arguments[nArgIndex].m_Opcode.GetArgument(), node.m_Arguments[nArgIndex].m_Opcode.GetArgument());
}
}
else
{
strArgument = GetSource(node.m_Arguments[nArgIndex], false, ulNumArgs);
}
}
else
{
strArgument = GetSource(node.m_Arguments[nArgIndex], false, ulNumArgs);
}
if (nArgIndex == 0)
{
strResult += strArgument;
}
else
{
strResult += ", ";
strResult += strArgument;
}
}
strResult += ")";
return strResult;
}
std::string CFalloutScript::GetIndentString(int32_t nLevel)
{
std::string strResult;
for(; nLevel > 0; nLevel--)
{
strResult += g_strIndentFill;
}
return strResult;
}
int CFalloutScript::GetPriority(uint16_t wOperator)
{
switch(wOperator)
{
case COpcode::O_IF:
return 0;
case COpcode::O_OR:
case COpcode::O_AND:
return 2;
case COpcode::O_GREATER:
case COpcode::O_LESS:
case COpcode::O_GREATER_EQUAL:
case COpcode::O_LESS_EQUAL:
case COpcode::O_EQUAL:
case COpcode::O_NOT_EQUAL:
return 3;
case COpcode::O_ADD:
case COpcode::O_SUB:
case COpcode::O_BWXOR:
case COpcode::O_BWOR:
case COpcode::O_BWAND:
return 4;
case COpcode::O_MUL:
case COpcode::O_DIV:
case COpcode::O_MOD:
case COpcode::O_TS_POW:
case COpcode::O_TS_DIV: // sfall unsigned division
return 5;
default:
return 6;
}
}
CFalloutScript::Assoc CFalloutScript::GetAssociation(uint16_t wOperator)
{
switch(wOperator)
{
case COpcode::O_GREATER:
case COpcode::O_LESS:
case COpcode::O_GREATER_EQUAL:
case COpcode::O_LESS_EQUAL:
case COpcode::O_EQUAL:
case COpcode::O_NOT_EQUAL:
return CFalloutScript::NON_ASSOC;
case COpcode::O_OR:
case COpcode::O_AND:
case COpcode::O_ADD:
case COpcode::O_SUB:
case COpcode::O_BWXOR:
case COpcode::O_BWOR:
case COpcode::O_BWAND:
case COpcode::O_MUL:
case COpcode::O_DIV:
case COpcode::O_MOD:
return CFalloutScript::LEFT_ASSOC;
default:
return CFalloutScript::NON_ASSOC;
}
}