Пример #1
0
        public SwitchStatement DecompileSwitch()
        {
            PopByte();
            var    objIndex        = ReadObject();
            var    unknByte        = ReadByte();
            var    expr            = DecompileExpression();
            var    scopeStatements = new List <Statement>();
            UInt16 endOffset       = 0xFFFF; // set it at max to begin with, so we can begin looping

            Scopes.Add(scopeStatements);
            CurrentScope.Push(Scopes.Count - 1);
            while (Position < endOffset && Position < Size)
            {
                if (CurrentIs(StandardByteCodes.Jump)) // break detected, save the endOffset
                {                                      // executes for all occurences, to handle them all.
                    StartPositions.Push((UInt16)Position);
                    PopByte();
                    endOffset = ReadUInt16();
                    var breakStatement = new BreakStatement(null, null);
                    StatementLocations.Add(StartPositions.Pop(), breakStatement);
                    scopeStatements.Add(breakStatement);
                    continue;
                }

                var current = DecompileStatement();
                if (current == null)
                {
                    return(null); // ERROR ?
                }
                scopeStatements.Add(current);
                if (current is DefaultStatement && endOffset == 0xFFFF)
                {
                    break; // If no break was detected, we end the switch rather than include the rest of ALL code in the default.
                }
            }
            CurrentScope.Pop();

            var statement = new SwitchStatement(expr, new CodeBody(scopeStatements, null, null), null, null);

            StatementLocations.Add(StartPositions.Pop(), statement);
            return(statement);
        }
Пример #2
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);
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        public Expression DecompileExpression()
        {
            StartPositions.Push((ushort)Position);
            var token = PeekByte;

            if (token >= 0x80) // native table
            {
                return(DecompileNativeFunction(PopByte()));
            }

            if (token >= 0x71) // extended native table, 0x70 is unused
            {
                var higher = ReadByte() & 0x0F;
                var lower  = ReadByte();
                int index  = (higher << 8) + lower;
                return(DecompileNativeFunction((ushort)index));
            }

            switch (token)
            {
            // variable lookups
            case (byte)OpCodes.DefaultVariable:

                PopByte();
                return(DecompileDefaultReference());

            case (byte)OpCodes.LocalVariable:
            case (byte)OpCodes.InstanceVariable:
            case (byte)OpCodes.LocalOutVariable:
            case (byte)OpCodes.LocalFloatVariable:
            case (byte)OpCodes.LocalIntVariable:
            case (byte)OpCodes.LocalByteVariable:
            case (byte)OpCodes.LocalObjectVariable:
            case (byte)OpCodes.InstanceFloatVariable:
            case (byte)OpCodes.InstanceIntVariable:
            case (byte)OpCodes.InstanceByteVariable:
            case (byte)OpCodes.InstanceObjectVariable:
                PopByte();
                return(DecompileObjectLookup());

            case (byte)OpCodes.Nothing:
                PopByte();
                StartPositions.Pop();
                return(DecompileExpression());    // TODO, solve this better? What about variable assignments etc?

            // array[index]
            case (byte)OpCodes.DynArrayElement:     //TODO: possibly separate this
            case (byte)OpCodes.ArrayElement:
                return(DecompileArrayRef());

            // new (...) class (.)
            case (byte)OpCodes.New:     // TODO: support in AST
                return(DecompileNew());

            // (class|object|struct).member
            case (byte)OpCodes.ClassContext:     // TODO: support in AST
                return(DecompileContext(isClass: true));

            case (byte)OpCodes.Context:
                return(DecompileContext());

            case (byte)OpCodes.StructMember:
                return(DecompileStructMember());

            // unknown, interface
            case (byte)OpCodes.InterfaceContext:
                PopByte();
                StartPositions.Pop();
                return(DecompileExpression());    // TODO: research this

            // class<Name>(Obj)
            case (byte)OpCodes.Metacast:
                return(DecompileCast(meta: true));   // TODO: ugly hack to make this qork quickly

            // Self
            case (byte)OpCodes.Self:
                PopByte();
                StartPositions.Pop();
                return(new SymbolReference(null, SELF, null, null));    // TODO: solve better

            // Skip(numBytes)
            case (byte)OpCodes.Skip: // handles skips in operator arguments
                PopByte();
                ReadInt16();         // MemSize
                StartPositions.Pop();
                return(DecompileExpression());

            // Function calls
            case (byte)OpCodes.FinalFunction:
                return(DecompileFunctionCall());

            case (byte)OpCodes.GlobalFunction:
                return(DecompileFunctionCall(byName: true, global: true));    // TODO: is this correct?

            case (byte)OpCodes.VirtualFunction:
                return(DecompileFunctionCall(byName: true));

            // int, eg. 5
            case (byte)OpCodes.IntConst:
                return(DecompileIntConst());

            // float, eg. 5.5
            case (byte)OpCodes.FloatConst:
                return(DecompileFloatConst());

            // "string"
            case (byte)OpCodes.StringConst:
                return(DecompileStringConst());

            // Object
            case (byte)OpCodes.ObjectConst:
                return(DecompileObjectConst());

            // 'name'
            case (byte)OpCodes.NameConst:
                return(DecompileNameConst());

            // rot(1, 2, 3)
            case (byte)OpCodes.RotationConst:
                return(DecompileRotationConst());     //TODO: properly

            // vect(1.0, 2.0, 3.0)
            case (byte)OpCodes.VectorConst:
                return(DecompileVectorConst());

            // byte, eg. 0B
            case (byte)OpCodes.ByteConst:
                return(DecompileByteConst(BYTE));

            case (byte)OpCodes.IntConstByte:
                return(DecompileByteConst(INT));

            // 0
            case (byte)OpCodes.IntZero:
                return(DecompileIntConstVal(0));

            // 1
            case (byte)OpCodes.IntOne:
                return(DecompileIntConstVal(1));

            // true
            case (byte)OpCodes.True:
                return(DecompileBoolConstVal(true));

            // false
            case (byte)OpCodes.False:
                return(DecompileBoolConstVal(false));

            // None    (object literal)
            case (byte)OpCodes.NoObject:
            case (byte)OpCodes.EmptyDelegate:
                PopByte();
                StartPositions.Pop();
                return(new NoneLiteral());

            // (bool expression)
            case (byte)OpCodes.BoolVariable:
                return(DecompileBoolExprValue());

            // ClassName(Obj)
            case (byte)OpCodes.InterfaceCast:
            case (byte)OpCodes.DynamicCast:
                return(DecompileCast());

            // struct == struct
            case (byte)OpCodes.StructCmpEq:
                return(DecompileStructComparison(true));

            // struct != struct
            case (byte)OpCodes.StructCmpNe:
                return(DecompileStructComparison(false));

            // delegate == delegate
            case (byte)OpCodes.EqualEqual_DelDel:
                return(DecompileDelegateComparison(true));

            // delegate != delegate
            case (byte)OpCodes.NotEqual_DelDel:
                return(DecompileDelegateComparison(false));

            // delegate == Function
            case (byte)OpCodes.EqualEqual_DelFunc:
                return(DecompileDelegateComparison(true));

            // delegate != Function
            case (byte)OpCodes.NotEqual_DelFunc:
                return(DecompileDelegateComparison(false));

            // primitiveType(expr)
            case (byte)OpCodes.PrimitiveCast:
                return(DecompilePrimitiveCast());

            // (bool expr) ? expr : expr
            case (byte)OpCodes.Conditional:
                return(DecompileConditionalExpression());

            // end of script
            case (byte)OpCodes.EndOfScript:
                return(null);    // ERROR?

            // (empty function param)
            case (byte)OpCodes.EmptyParmValue:
                PopByte();
                StartPositions.Pop();
                return(new SymbolReference(null, ""));    // TODO: solve better

            // arrayName.Length
            case (byte)OpCodes.DynArrayLength:
                return(DecompileDynArrLength());

            // arrayName.Find(value)
            case (byte)OpCodes.DynArrayFind:
                return(DecompileDynArrayFind());

            // arrayName.Find(StructProperty, value)
            case (byte)OpCodes.DynArrayFindStruct:
                return(DecompileDynArrayFindStructMember());

            // arrayName.Insert(Index, Count)
            case (byte)OpCodes.DynArrayInsert:
                return(DecompileDynArrayInsert());

            // arrayName.Remove(Index, Count)
            case (byte)OpCodes.DynArrayRemove:
                return(DecompileDynArrayRemove());

            // arrayName.Add(value)
            case (byte)OpCodes.DynArrayAdd:
                return(DecompileDynArrayAdd());

            // arrayName.AddItem(value)
            case (byte)OpCodes.DynArrayAddItem:
                return(DecompileDynArrayAddItem());

            // arrayName.RemoveItem(value)
            case (byte)OpCodes.DynArrayRemoveItem:
                return(DecompileDynArrayRemoveItem());

            // arrayName.InsertItem(StructProperty, value)
            case (byte)OpCodes.DynArrayInsertItem:
                return(DecompileDynArrayInsertItem());

            // arrayName.Sort(value)
            case (byte)OpCodes.DynArraySort:
                return(DecompileDynArraySort());

            // TODO: temporary delegate handling, probably wrong:
            case (byte)OpCodes.DelegateFunction:
                return(DecompileDelegateFunction());

            case (byte)OpCodes.DelegateProperty:
                return(DecompileDelegateProperty());

            case (byte)OpCodes.NamedFunction:
                return(DecompileFunctionCall(byName: true, withFuncListIdx: true));

            case (byte)OpCodes.StringRefConst:
                return(DecompileStringRefConst());



                /*****
                 * TODO: all of these needs changes, see functions below.
                 * */
                #region Unsupported

            case (byte)OpCodes.NativeParm:     // is this even present anywhere?
                return(DecompileNativeParm());

            case (byte)OpCodes.GoW_DefaultValue:
                return(DecompileGoW_DefaultValue());

            case (byte)OpCodes.InstanceDelegate:
                return(DecompileInstanceDelegate());

                #endregion


            // TODO: 41, debugInfo

            // TODO: 0x3B - 0x3E native calls

            default:

                // ERROR!
                break;
            }

            return(null);
        }