Пример #1
0
        public bool VisitNode(ExpressionOnlyStatement node)
        {
            // expression;
            Write("");
            node.Value.AcceptVisitor(this);

            return(true);
        }
Пример #2
0
        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));
        }
Пример #3
0
        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);
                    }
                }
            }
        }
Пример #4
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);
        }
Пример #5
0
        public CodeBody Decompile()
        {
            // Skip native funcs
            if (DataContainer is UFunction Func && Func.FunctionFlags.HasFlag(FunctionFlags.Native))
            {
                var comment = new ExpressionOnlyStatement(new SymbolReference(null, "// Native function"));
                return(new CodeBody(new List <Statement> {
                    comment
                }));
            }

            if (ContainingClass.Export.ObjectName == "SFXGalaxyMapObject")
            {
                //these functions are broken and cannot be decompiled. instead of trying, we construct a simpler, functionally identical version
                if (DataContainer.Export.ObjectName == "GetEditorLabel")
                {
                    return(new CodeBody(new List <Statement> {
                        new ReturnStatement(new SymbolReference(null, "sLabel"))
                    }));
                }
                if (DataContainer.Export.ObjectName == "InitializeAppearance")
                {
                    return(new CodeBody(new List <Statement> {
                        new ReturnStatement()
                    }));
                }
            }

            Position      = 0;
            _totalPadding = 0;
            CurrentScope  = new Stack <int>();
            var statements = new List <Statement>();

            StatementLocations = new Dictionary <ushort, Statement>();
            StartPositions     = new Stack <ushort>();
            Scopes             = new List <List <Statement> >();
            LabelTable         = new List <LabelTableEntry>();
            ForEachScopes      = new Stack <ushort>();

            DecompileDefaultParameterValues(statements);

            Scopes.Add(statements);
            CurrentScope.Push(Scopes.Count - 1);
            while (Position < Size && !CurrentIs(OpCodes.EndOfScript))
            {
                var current = DecompileStatement();
                if (current == null && PeekByte == (byte)OpCodes.EndOfScript)
                {
                    break; // Natural end after label table, no error
                }
                if (current == null)
                {
                    //as well as being eye-catching in generated code, this is totally invalid unrealscript and will cause compilation errors!
                    statements.Clear();
                    statements.Add(new ExpressionOnlyStatement(new SymbolReference(null, "**************************")));
                    statements.Add(new ExpressionOnlyStatement(new SymbolReference(null, "*                        *")));
                    statements.Add(new ExpressionOnlyStatement(new SymbolReference(null, "*  DECOMPILATION ERROR!  *")));
                    statements.Add(new ExpressionOnlyStatement(new SymbolReference(null, "*                        *")));
                    statements.Add(new ExpressionOnlyStatement(new SymbolReference(null, "**************************")));
                    return(new CodeBody(statements));
                }

                statements.Add(current);
            }
            CurrentScope.Pop();
            AddStateLabels();

            Dictionary <Statement, ushort> LocationStatements = StatementLocations.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);

            DecompileLoopsAndIfs(statements, LocationStatements);

            //a void return at the end of a function is a bytecode implementation detail, get rid of it.
            //This will also get rid of returnnothings, so loop to make sure we get both
            while (statements.Count > 0 && statements.Last() is ReturnStatement ret && ret.Value is null)
            {
                statements.RemoveAt(statements.Count - 1);
            }

            return(new CodeBody(statements));
        }
Пример #6
0
 public bool VisitNode(ExpressionOnlyStatement node)
 {
     throw new NotImplementedException();
 }
Пример #7
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);
            }
        }