예제 #1
0
        public Statement DecompileForEach(bool isDynArray = false)
        {
            PopByte();
            var scopeStatements = new List <Statement>();

            var iteratorFunc = DecompileExpression();

            if (iteratorFunc == null)
            {
                return(null);
            }

            if (isDynArray)
            {
                Expression dynArrVar   = DecompileExpression();
                bool       hasIndex    = Convert.ToBoolean(ReadByte());
                Expression dynArrIndex = DecompileExpression();
                iteratorFunc = new DynArrayIterator(iteratorFunc, dynArrVar, dynArrIndex);
            }

            var scopeEnd = ReadUInt16(); // MemOff

            ForEachScopes.Push(scopeEnd);

            Scopes.Add(scopeStatements);
            CurrentScope.Push(Scopes.Count - 1);
            while (Position < Size)
            {
                if (CurrentIs(OpCodes.IteratorNext))
                {
                    PopByte(); // IteratorNext
                    if (PeekByte == (byte)OpCodes.IteratorPop)
                    {
                        StatementLocations[(ushort)(Position - 1)] = new IteratorNext();
                        StatementLocations[(ushort)Position]       = new IteratorPop();
                        PopByte(); // IteratorPop
                        break;
                    }
                    Position--;
                }

                var current = DecompileStatement();
                if (current == null)
                {
                    return(null); // ERROR ?
                }
                scopeStatements.Add(current);
            }
            CurrentScope.Pop();
            ForEachScopes.Pop();

            var statement = new ForEachLoop(iteratorFunc, new CodeBody(scopeStatements))
            {
                iteratorPopPos = Position - 1
            };

            StatementLocations.Add(StartPositions.Pop(), statement);
            return(statement);
        }
예제 #2
0
        public Statement DecompileJump()
        {
            PopByte();
            var       jumpOffs  = ReadUInt16(); // discard jump destination
            Statement statement = null;

            if (ForEachScopes.Count != 0 && jumpOffs == ForEachScopes.Peek()) // A jump to the IteratorPop of a ForEach means break afaik.
            {
                statement = new BreakStatement(null, null);
            }
            else
            {
                statement = new ContinueStatement(null, null);
            }

            StatementLocations.Add(StartPositions.Pop(), statement);
            return(statement);
        }
예제 #3
0
        public Statement DecompileForEach(bool isDynArray = false) // TODO: guess for loop, probably requires a large restructure
        {
            PopByte();
            var scopeStatements = new List <Statement>();

            var iteratorFunc = DecompileExpression();

            if (iteratorFunc == null)
            {
                return(null);
            }

            Expression dynArrVar   = null;
            Expression dynArrIndex = null;
            bool       unknByte    = false;

            if (isDynArray)
            {
                dynArrVar   = DecompileExpression();
                unknByte    = Convert.ToBoolean(ReadByte());
                dynArrIndex = DecompileExpression();
            }

            var scopeEnd = ReadUInt16(); // MemOff

            ForEachScopes.Push(scopeEnd);

            Scopes.Add(scopeStatements);
            CurrentScope.Push(Scopes.Count - 1);
            while (Position < Size)
            {
                if (CurrentIs(StandardByteCodes.IteratorNext) && PeekByte == (byte)StandardByteCodes.IteratorPop)
                {
                    PopByte(); // IteratorNext
                    PopByte(); // IteratorPop
                    break;
                }

                var current = DecompileStatement();
                if (current == null)
                {
                    return(null); // ERROR ?
                }
                scopeStatements.Add(current);
            }
            CurrentScope.Pop();
            ForEachScopes.Pop();

            if (isDynArray)
            {
                var builder = new CodeBuilderVisitor(); // what a wonderful hack, TODO.
                iteratorFunc.AcceptVisitor(builder);
                var arrayName  = new SymbolReference(null, null, null, builder.GetCodeString());
                var parameters = new List <Expression>()
                {
                    dynArrVar, dynArrIndex
                };
                iteratorFunc = new FunctionCall(arrayName, parameters, null, null);
            }

            var statement = new ForEachLoop(iteratorFunc, new CodeBody(scopeStatements, null, null), null, null);

            StatementLocations.Add(StartPositions.Pop(), statement);
            return(statement);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
            }
        }