public Statement DecompileConditionalJump(bool isOpt = false) // TODO: guess for loop, probably requires a large restructure { PopByte(); var scopeStartOffset = StartPositions.Pop(); Statement statement = null; bool hasElse = false; var scopeStatements = new List <Statement>(); UInt16 scopeEndJmpOffset = 0; UInt16 afterScopeOffset = 0; Expression conditional = null; if (isOpt) { var obj = ReadObject(); var optCheck = Convert.ToBoolean(ReadByte()); afterScopeOffset = ReadUInt16(); String special = (optCheck ? "" : "!") + obj.ObjectName; conditional = new SymbolReference(null, null, null, special); } else { afterScopeOffset = ReadUInt16(); conditional = DecompileExpression(); } if (conditional == null) { return(null); } if (afterScopeOffset < scopeStartOffset) // end of do_until detection { scopeStartOffset = afterScopeOffset; var outerScope = Scopes[CurrentScope.Peek()]; var startStatement = StatementLocations[afterScopeOffset]; StatementLocations.Remove(afterScopeOffset); var index = outerScope.IndexOf(startStatement); scopeStatements = new List <Statement>(outerScope.Skip(index)); outerScope.RemoveRange(index, outerScope.Count - index); statement = new DoUntilLoop(conditional, new CodeBody(scopeStatements, null, null), null, null); } Scopes.Add(scopeStatements); CurrentScope.Push(Scopes.Count - 1); while (Position < afterScopeOffset) { if (CurrentIs(StandardByteCodes.Jump)) { var contPos = (UInt16)Position; PopByte(); scopeEndJmpOffset = ReadUInt16(); if (scopeEndJmpOffset == scopeStartOffset) { statement = new WhileLoop(conditional, new CodeBody(scopeStatements, null, null), null, null); break; } else if (Position < afterScopeOffset) // if we are not at the end of the scope, this is a continue statement in a loop rather than an else statement { var cont = new ContinueStatement(null, null); StatementLocations.Add(contPos, cont); scopeStatements.Add(cont); } else if (ForEachScopes.Count != 0 && scopeEndJmpOffset == ForEachScopes.Peek()) { var breakStatement = new BreakStatement(null, null); StatementLocations.Add(contPos, breakStatement); scopeStatements.Add(breakStatement); } else { hasElse = true; } continue; } var current = DecompileStatement(); if (current == null) { return(null); // ERROR ? } scopeStatements.Add(current); } CurrentScope.Pop(); List <Statement> elseStatements = new List <Statement>(); if (hasElse) { var endElseOffset = scopeEndJmpOffset; Scopes.Add(elseStatements); CurrentScope.Push(Scopes.Count - 1); while (Position < endElseOffset) { var current = DecompileStatement(); if (current == null) { return(null); // ERROR ? } elseStatements.Add(current); } CurrentScope.Pop(); } statement = statement ?? new IfStatement(conditional, new CodeBody(scopeStatements, null, null), null, null, elseStatements.Count != 0 ? new CodeBody(elseStatements, null, null) : null); StatementLocations.Add(scopeStartOffset, statement); return(statement); }
public Statement DecompileStatement(ushort?startPosition = null) { StartPositions.Push(startPosition ?? (ushort)Position); var token = PeekByte; switch (token) { // return [expression]; case (byte)OpCodes.Return: return(DecompileReturn()); // switch (expression) case (byte)OpCodes.Switch: return(DecompileSwitch()); // case expression : case (byte)OpCodes.Case: return(DecompileCase()); // if (expression) // while / for / do until case (byte)OpCodes.JumpIfNot: { PopByte(); var jump = new IfNotJump(ReadUInt16(), DecompileExpression(), Position - StartPositions.Peek()); StatementLocations.Add(StartPositions.Pop(), jump); return(jump); } case (byte)OpCodes.Jump: { PopByte(); ushort jumpLoc = ReadUInt16(); if (ForEachScopes.Count > 0 && jumpLoc == ForEachScopes.Peek()) { var brk = new BreakStatement(); StatementLocations.Add(StartPositions.Pop(), brk); return(brk); } var jump = new UnconditionalJump(jumpLoc); StatementLocations.Add(StartPositions.Pop(), jump); return(jump); } // continue (iterator) case (byte)OpCodes.IteratorNext: { PopByte(); var itNext = new ContinueStatement(); StatementLocations.Add(StartPositions.Pop(), itNext); if (PopByte() != (byte)OpCodes.Jump) { return(null); //there should always be a jump after an iteratornext that's not at the end of the loop } //skip the jump address PopByte(); PopByte(); return(itNext); } // break; case (byte)OpCodes.IteratorPop: { PopByte(); return(DecompileStatement(StartPositions.Pop())); } // stop; case (byte)OpCodes.Stop: PopByte(); var stopStatement = new StopStatement(null, null); StatementLocations.Add(StartPositions.Pop(), stopStatement); return(stopStatement); // Goto label case (byte)OpCodes.GotoLabel: PopByte(); var gotoLabel = new StateGoto(DecompileExpression()); StatementLocations.Add(StartPositions.Pop(), gotoLabel); return(gotoLabel); // assignable expression = expression; case (byte)OpCodes.Let: case (byte)OpCodes.LetBool: case (byte)OpCodes.LetDelegate: return(DecompileAssign()); // [skip x bytes] case (byte)OpCodes.Skip: // TODO: this should never occur as statement, possibly remove? PopByte(); ReadUInt16(); StartPositions.Pop(); return(DecompileStatement()); case (byte)OpCodes.Nothing: PopByte(); StartPositions.Pop(); return(DecompileStatement()); // TODO, should probably have a nothing expression or statement, this is ugly // foreach IteratorFunction(...) case (byte)OpCodes.Iterator: return(DecompileForEach()); // foreach arrayName(valuevariable[, indexvariable]) case (byte)OpCodes.DynArrayIterator: return(DecompileForEach(true)); case (byte)OpCodes.LabelTable: DecompileLabelTable(); StartPositions.Pop(); return(DecompileStatement()); case (byte)OpCodes.OptIfLocal: case (byte)OpCodes.OptIfInstance: { PopByte(); IEntry obj = ReadObject(); var condition = new SymbolReference(null, obj.ObjectName.Instanced); bool not = Convert.ToBoolean(ReadByte()); if (obj.ClassName == "BoolProperty") { var ifJump = new IfNotJump( ReadUInt16(), not ? (Expression)condition : new PreOpReference(new PreOpDeclaration("!", SymbolTable.BoolType, 0, null), condition), Position - StartPositions.Peek()); StatementLocations.Add(StartPositions.Pop(), ifJump); return(ifJump); } var nullJump = new NullJump(ReadUInt16(), condition, not) { SizeOfExpression = Position - StartPositions.Peek() }; StatementLocations.Add(StartPositions.Pop(), nullJump); return(nullJump); } case (byte)OpCodes.FilterEditorOnly: { PopByte(); var edFilter = new InEditorJump(ReadUInt16()); StatementLocations.Add(StartPositions.Pop(), edFilter); return(edFilter); } case (byte)OpCodes.EatReturnValue: PopByte(); ReadObject(); return(DecompileStatement(StartPositions.Pop())); case (byte)OpCodes.Assert: return(DecompileAssert()); default: var expr = DecompileExpression(); if (expr != null) { var statement = new ExpressionOnlyStatement(expr, null, null); StatementLocations.Add(StartPositions.Pop(), statement); return(statement); } // ERROR! return(null); } }