/** * * Copyright (c) 2005-2009 Anchorite (TeamX), * Copyright (c) 20014-2015 Nirran, phobos2077 * Copyright (c) 20015 alexeevdv * Distributed under the GNU GPL v3. For full terms see the file license.txt * */ // C++ standard includes #include // int2ssl includes #include "FalloutScript.h" #include "ObjectAttributes.h" #include "Utility.h" // Third party includes extern std::string g_strIndentFill; void CFalloutScript::StoreTree(CArchive& ar) { std::string strOutLine; ar.WriteString("============== Procedures ==================\n"); ar.WriteString("\n"); for(int32_t nIndexOfProc = 0; nIndexOfProc < m_ProcTable.GetSize(); nIndexOfProc++) { strOutLine = format("%d: %s (0x%08x)\n", nIndexOfProc, m_Namespace[m_ProcTable[nIndexOfProc].m_ulNameOffset].c_str(), m_ProcTable[nIndexOfProc].m_ulBodyOffset); ar.WriteString(strOutLine); ar.WriteString("===============================\n"); if (m_ProcTable[nIndexOfProc].m_ulType & P_CONDITIONAL) { ar.WriteString("Condition\n"); ar.WriteString("===============================\n"); for(int32_t i = 0; i < m_Conditions[nIndexOfProc].size(); i++) { strOutLine = format("0x%08X: ", m_Conditions[nIndexOfProc][i].m_ulOffset); ar.WriteString(strOutLine); m_Conditions[nIndexOfProc][i].StoreTree(ar, 0, 0); } ar.WriteString("\n"); ar.WriteString("Body\n"); ar.WriteString("===============================\n"); } for(int32_t i = 0; i < m_ProcBodies[nIndexOfProc].size(); i++) { strOutLine = format("0x%08X: ", m_ProcBodies[nIndexOfProc][i].m_ulOffset); ar.WriteString(strOutLine); m_ProcBodies[nIndexOfProc][i].StoreTree(ar, 0, 0); } ar.WriteString("\n"); } } void CFalloutScript::StoreSource(CArchive& ar) { StoreDefinitions(ar); ar.WriteString("\n"); ar.WriteString("\n"); StoreDeclarations(ar); } void CFalloutScript::StoreDefinitions(CArchive& ar) { 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) { ar.WriteString("/*******************************************************\n"); ar.WriteString("* Some unreferenced imported varables found. *\n"); ar.WriteString("* Because of it it is impossible to specify *\n"); ar.WriteString("* the real names of global variables. *\n"); ar.WriteString("*******************************************************/\n"); ar.WriteString("\n"); for(int32_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\"", m_Stringspace[ulVarValue].c_str()); break; case COpcode::O_FLOATOP: strDefinition = format(strDefinition + " := %.5f", *((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); } ar.WriteString(strDefinition + "\n"); } ar.WriteString("\n"); } // 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::string msg = "Warning: Bogus procedure with name "; msg += c_strBogusProcedureName; msg += " not found at expected location\n"; printf(msg.c_str()); } } 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\"", m_Stringspace[defObject.m_ulVarValue].c_str()); break; case COpcode::O_FLOATOP: strDefinition = format(strDefinition + " := %.5f", *((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)) { ar.WriteString("\n"); } lastOut = currentOut; ar.WriteString(strDefinition + "\n"); } } void CFalloutScript::StoreDeclarations(CArchive& ar) { std::string c_strBogusProcedureName(".............."); std::string c_strArgumentTemplate("arg%u"); std::string c_strLocalVarTemplate("LVar%u"); printf(" Storing declarations\n"); std::string strOutLine; for(int32_t i = 0; i < m_ProcTable.GetSize(); i++) { printf(" Procedure: %d\r", i); // Bogus procedure if ((i == 0) && (m_Namespace[m_ProcTable[i].m_ulNameOffset] == c_strBogusProcedureName)) { continue; } // Empty procedure if (m_ProcTable.GetSizeOfProc(i) == 0) { ar.WriteString("/*******************************************************\n"); ar.WriteString("* Found Procedure without body. *\n"); ar.WriteString("* *\n"); strOutLine = "* Name: "; strOutLine+= m_Namespace[m_ProcTable[i].m_ulNameOffset]; while(strOutLine.length() < 55) { strOutLine += " "; } strOutLine += "*\n"; ar.WriteString(strOutLine); ar.WriteString("* *\n"); if (!(m_ProcTable[i].m_ulType & P_NOTIMPLEMENTED)) { ar.WriteString("* Other possible name(s): *\n"); for(int32_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 += "*\n"; ar.WriteString(strOutLine); strOutLine = "* "; } } } else { ar.WriteString("* Not implemented *\n"); } ar.WriteString("* *\n"); ar.WriteString("*******************************************************/\n"); ar.WriteString("\n"); 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()); } ar.WriteString(strOutLine + "\n"); bool bLocalVar = true; uint32_t ulLocalVarIndex = procDescriptor.m_ulNumArgs; int32_t nIndentLevel = 0; CNode::Type prevNodeType = CNode::TYPE_NORMAL; for(int32_t nNodeIndex = 0; nNodeIndex < m_ProcBodies[i].size(); nNodeIndex++) { if (m_ProcBodies[i][nNodeIndex].m_Type == CNode::TYPE_BEGIN_OF_BLOCK) { if ((nNodeIndex - 1 > 0) && (m_ProcBodies[i][nNodeIndex - 1].m_Type == CNode::TYPE_END_OF_BLOCK)) { ar.WriteString(GetIndentString(nIndentLevel) + "else begin\n"); nIndentLevel++; } else { ar.WriteString("begin\n"); nIndentLevel++; } prevNodeType = CNode::TYPE_BEGIN_OF_BLOCK; } else if (m_ProcBodies[i][nNodeIndex].m_Type == CNode::TYPE_END_OF_BLOCK) { nIndentLevel--; ar.WriteString(GetIndentString(nIndentLevel) + "end\n"); 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); ar.WriteString(GetIndentString(nIndentLevel) + strOutLine + GetSource(m_ProcBodies[i][nNodeIndex], false, procDescriptor.m_ulNumArgs) + ";\n"); ulLocalVarIndex++; break; } case COpcode::O_IF: ar.WriteString(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 (int32_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 += ") "; ar.WriteString(str); } else { ar.WriteString(GetIndentString(nIndentLevel) + GetSource(m_ProcBodies[i][nNodeIndex], false, procDescriptor.m_ulNumArgs) + " do "); } break; default: ar.WriteString(GetIndentString(nIndentLevel) + GetSource(m_ProcBodies[i][nNodeIndex], false, procDescriptor.m_ulNumArgs) + ";\n"); 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; } } } } ar.WriteString("\n"); } } 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 += m_Stringspace[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_FLOATOP: strResult = format("%.5f", *((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 (int32_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 (int32_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(int32_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(int32_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, bLabel, ulNumArgs, aulProcArg, 1); } break; case COpcode::O_ADDBUTTONPROC: { uint32_t aulProcArg[4] = { 2, 3, 4, 5 }; strResult = GetSource(node, bLabel, ulNumArgs, aulProcArg, 4); } break; case COpcode::O_ADDBUTTONRIGHTPROC: { uint32_t aulProcArg[2] = { 2, 3 }; strResult = GetSource(node, bLabel, 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, bLabel, 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, bLabel, ulNumArgs, aulProcArg, 4); } break; case COpcode::O_ADDREGIONRIGHTPROC: { uint32_t aulProcArg[2] = { 2, 3 }; strResult = GetSource(node, bLabel, ulNumArgs, aulProcArg, 2); } break; case COpcode::O_ADDNAMEDEVENT: { uint32_t aulProcArg[1] = { 2 }; strResult = GetSource(node, bLabel, ulNumArgs, aulProcArg, 1); } break; case COpcode::O_ADDNAMEDHANDLER: { uint32_t aulProcArg[1] = { 2 }; strResult = GetSource(node, bLabel, ulNumArgs, aulProcArg, 1); } break; case COpcode::O_ADDKEY: { uint32_t aulProcArg[1] = { 2 }; strResult = GetSource(node, bLabel, ulNumArgs, aulProcArg, 1); } break; case COpcode::O_GSAY_OPTION: { uint32_t aulProcArg[1] = { 3 }; strResult = GetSource(node, bLabel, ulNumArgs, aulProcArg, 1); } break; case COpcode::O_GIQ_OPTION: { uint32_t aulProcArg[1] = { 4 }; strResult = GetSource(node, bLabel, 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, bLabel, ulNumArgs, procArgs, numProcArgs); break; } if (node.m_Type == CNode::TYPE_CONDITIONAL_EXPRESSION) { if (node.m_Arguments.size() != 3) { printf("Error: Invalid number of arguments in conditional expression\n"); throw std::exception(); } std::string sPostfix[] = { " if ", " else ", ""}; strResult = ""; for(int32_t i = 0; i < node.m_Arguments.size(); i++) { bool bParens = ArgNeedParens(node, node.m_Arguments[i], CFalloutScript::RIGHT_ASSOC); strResult += (bParens ? "(" : "") + GetSource(node.m_Arguments[i], 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(int32_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, bool bLabel, 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(int32_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: 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; } }