public CodeBody Decompile() { // Skip native funcs var Func = DataContainer as ME3Function; if (Func != null && Func.FunctionFlags.HasFlag(FunctionFlags.Native)) { var comment = new ExpressionOnlyStatement(null, null, new SymbolReference(null, null, null, "// Native function")); return new CodeBody(new List<Statement>() { comment }, null, null); } Position = 0; _totalPadding = 0; CurrentScope = new Stack<int>(); var statements = new List<Statement>(); StatementLocations = new Dictionary<UInt16, Statement>(); StartPositions = new Stack<UInt16>(); Scopes = new List<List<Statement>>(); LabelTable = new List<LabelTableEntry>(); ForEachScopes = new Stack<UInt16>(); DecompileDefaultParameterValues(statements); Scopes.Add(statements); CurrentScope.Push(Scopes.Count - 1); while (Position < Size && !CurrentIs(StandardByteCodes.EndOfScript)) { var current = DecompileStatement(); if (current == null && CurrentByte == (byte)StandardByteCodes.EndOfScript) break; // Natural end after label table, no error if (current == null) break; // TODO: ERROR! statements.Add(current); } CurrentScope.Pop(); ; AddStateLabels(); return new CodeBody(statements, null, null); }
public bool VisitNode(ExpressionOnlyStatement node) { throw new NotImplementedException(); }
public bool VisitNode(ExpressionOnlyStatement node) { // expression; Write(""); node.Value.AcceptVisitor(this); return true; }
public Statement DecompileStatement() { StartPositions.Push((UInt16)Position); var token = CurrentByte; switch (token) { // return [expression]; case (byte)StandardByteCodes.Return: return DecompileReturn(); // switch (expression) case (byte)StandardByteCodes.Switch: return DecompileSwitch(); // case expression : case (byte)StandardByteCodes.Case: return DecompileCase(); // if (expression) // while / for / do until case (byte)StandardByteCodes.JumpIfNot: return DecompileConditionalJump(); // continue case (byte)StandardByteCodes.Jump: // TODO: UDK seems to compile this from break when inside ForEach, handle? return DecompileJump(); // continue (iterator) case (byte)StandardByteCodes.IteratorNext: PopByte(); // pop iteratornext token return DecompileJump(); // break; case (byte)StandardByteCodes.IteratorPop: return DecompileIteratorPop(); // stop; case (byte)StandardByteCodes.Stop: PopByte(); var stopStatement = new StopStatement(null, null); StatementLocations.Add(StartPositions.Pop(), stopStatement); return stopStatement; // Goto label case (byte)StandardByteCodes.GotoLabel: PopByte(); var labelExpr = DecompileExpression(); var func = new SymbolReference(null, null, null, "goto"); var call = new FunctionCall(func, new List<Expression>() { labelExpr }, null, null); var gotoLabel = new ExpressionOnlyStatement(null, null, call); StatementLocations.Add(StartPositions.Pop(), gotoLabel); return gotoLabel; // assignable expression = expression; case (byte)StandardByteCodes.Let: case (byte)StandardByteCodes.LetBool: case (byte)StandardByteCodes.LetDelegate: return DecompileAssign(); // [skip x bytes] case (byte)StandardByteCodes.Skip: // TODO: this should never occur as statement, possibly remove? PopByte(); ReadUInt16(); StartPositions.Pop(); return DecompileStatement(); case (byte)StandardByteCodes.Nothing: PopByte(); StartPositions.Pop(); return DecompileStatement(); // TODO, should probably have a nothing expression or statement, this is ugly // foreach IteratorFunction(...) case (byte)StandardByteCodes.Iterator: return DecompileForEach(); // foreach arrayName(valuevariable[, indexvariable]) case (byte)StandardByteCodes.DynArrayIterator: return DecompileForEach(isDynArray: true); case (byte)StandardByteCodes.LabelTable: DecompileLabelTable(); StartPositions.Pop(); return DecompileStatement(); #region unsupported case (byte)StandardByteCodes.OptIfLocal: // TODO: verify, handle syntax return DecompileConditionalJump(isOpt: true); case (byte)StandardByteCodes.OptIfInstance: // TODO: verify, handle syntax return DecompileConditionalJump(isOpt: true); #endregion default: var expr = DecompileExpression(); if (expr != null) { var statement = new ExpressionOnlyStatement(null, null, expr); StatementLocations.Add(StartPositions.Pop(), statement); return statement; } // ERROR! break; } return null; }
private void DecompileDefaultParameterValues(List<Statement> statements) { OptionalParams = new Stack<FunctionParameter>(); var func = DataContainer as ME3Function; if (func != null) // Gets all optional params for default value parsing { for (int n = 0; n < Parameters.Count; n++) { if (func.Parameters[n].PropertyFlags.HasFlag(PropertyFlags.OptionalParm)) OptionalParams.Push(Parameters[n]); } } while (CurrentByte == (byte)StandardByteCodes.DefaultParmValue || CurrentByte == (byte)StandardByteCodes.Nothing) { StartPositions.Push((UInt16)Position); var token = PopByte(); if (token == (byte)StandardByteCodes.DefaultParmValue) // default value assigned { ReadInt16(); //MemSize of value var value = DecompileExpression(); PopByte(); // end of value var builder = new CodeBuilderVisitor(); // what a wonderful hack, TODO. value.AcceptVisitor(builder); if (OptionalParams.Count != 0) { var parm = OptionalParams.Pop(); parm.Variables.First().Name += " = " + builder.GetCodeString(); StartPositions.Pop(); } else { // TODO: weird, research how to deal with this var comment = new SymbolReference(null, null, null, "// Orphaned Default Parm: " + builder.GetCodeString()); var statement = new ExpressionOnlyStatement(null, null, comment); StatementLocations.Add(StartPositions.Pop(), statement); statements.Add(statement); } } } }