public AssignStatement(SymbolReference target, Expression value, SourcePosition start, SourcePosition end) : base(ASTNodeType.AssignStatement, start, end) { Target = target; Value = value; }
public Expression DecompileNativeFunction(UInt16 index) { var parameters = new List<Expression>(); while (!CurrentIs(StandardByteCodes.EndFunctionParms)) { var param = DecompileExpression(); if (param == null) return null; // ERROR parameters.Add(param); } PopByte(); var entry = NativeTable[index]; Expression call = null; switch (entry.Type) { case NativeType.Function: var func = new SymbolReference(null, null, null, entry.Name); call = new FunctionCall(func, parameters, null, null); break; case NativeType.Operator: // TODO: table should hold precedence, currently all have 0 and it'll be a mess. var op = new InOpDeclaration(entry.Name, entry.Precedence, false, null, null, null, null, null, null, null); call = new InOpReference(op, parameters[0], parameters[1], null, null); break; case NativeType.PreOperator: // TODO: table should hold precedence, currently all have 0 and it'll be a mess. var preOp = new PreOpDeclaration(entry.Name, false, null, null, null, null, null, null); call = new PreOpReference(preOp, parameters[0], null, null); break; case NativeType.PostOperator: // TODO: table should hold precedence, currently all have 0 and it'll be a mess. var postOp = new PostOpDeclaration(entry.Name, false, null, null, null, null, null, null); call = new PostOpReference(postOp, parameters[0], null, null); break; } StartPositions.Pop(); return call; }
public Expression DecompileGoW_DefaultValue() { PopByte(); var unkn = ReadByte(); var expr = DecompileExpression(); StartPositions.Pop(); var op = new InOpDeclaration("", 0, true, null, null, null, null, null, null, null); var objRef = new SymbolReference(null, null, null, "UNSUPPORTED: GoW_DefaultValue: Byte:" + unkn + " - "); return new InOpReference(op, objRef, expr, null, null); }
public Expression DecompileFunctionCall(bool byName = false, bool withUnknShort = false, bool global = false) { PopByte(); String funcName; if (byName) { funcName = PCC.GetName(ReadNameRef()); } else { var funcObj = ReadObject(); funcName = funcObj.ObjectName; if (funcName == DataContainer.Name && !isInClassContext) // If we're calling ourself, it's a super call { var str = "super"; var currentClass = DataContainer.ExportEntry.GetOuterOfType("Class").Object as ME3Class; var funcOuterClass = funcObj.GetOuterOfType("Class").ObjectName; if (currentClass != null && currentClass.SuperField != null && currentClass.SuperField.Name == funcOuterClass) funcName = str + "." + funcName; else funcName = str + "(" + funcOuterClass + ")." + funcName; } } if (global) funcName = "global." + funcName; if (withUnknShort) ReadInt16(); // TODO: related to unkn65, split out? Possibly jump? var parameters = new List<Expression>(); while (!CurrentIs(StandardByteCodes.EndFunctionParms)) { if (CurrentIs(StandardByteCodes.Nothing)) { PopByte(); // TODO: is this reasonable? what does it mean? parameters.Add(new SymbolReference(null, null, null, "None")); continue; } var param = DecompileExpression(); if (param == null) return null; // ERROR parameters.Add(param); } PopByte(); StartPositions.Pop(); var func = new SymbolReference(null, null, null, funcName); return new FunctionCall(func, parameters, null, null); }
// TODO: only skips one object? see code. public Expression DecompileEatReturn() { PopByte(); var obj = ReadObject(); var expr = DecompileExpression(); StartPositions.Pop(); var op = new InOpDeclaration("", 0, true, null, null, null, null, null, null, null); var objRef = new SymbolReference(null, null, null, "UNSUPPORTED: EatReturnValue: " + obj.ObjectName + "|" + obj.ClassName + " -"); return new InOpReference(op, objRef, expr, null, null); }
public Expression DecompileContext(bool isClass = false) { PopByte(); var left = DecompileExpression(); if (left == null) return null; // ERROR ReadInt16(); // discard MemSize value. (size of expr-right in half-bytes) ReadObject(); // discard RetValRef. ReadByte(); // discard unknown byte. isInClassContext = isClass; var right = DecompileExpression(); if (right == null) return null; // ERROR isInClassContext = false; if (isClass) { var builder = new CodeBuilderVisitor(); // what a wonderful hack, TODO. left.AcceptVisitor(builder); var str = builder.GetCodeString() + ".static"; left = new SymbolReference(null, null, null, str); } StartPositions.Pop(); return new CompositeSymbolRef(left, right, null, null); }
public FunctionCall(SymbolReference func, List <Expression> arguments, SourcePosition start, SourcePosition end) : base(ASTNodeType.FunctionCall, start, end) { Function = func; Arguments = arguments; }
public FunctionCall(SymbolReference func, List<Expression> parameters, SourcePosition start, SourcePosition end) : base(ASTNodeType.FunctionCall, start, end) { Function = func; Parameters = parameters; }
public bool VisitNode(SymbolReference node) { // symbolname Append("{0}", node.Name); return true; }
// TODO: guess for loop, probably requires a large restructure public Statement DecompileConditionalJump(bool isOpt = false) { 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() { 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; }
public ReturnStatement DecompileReturn() { PopByte(); Expression expr = null; if (CurrentIs(StandardByteCodes.ReturnNullValue)) { // TODO: research this a bit, seems to be the zero-equivalent value for the return type. PopByte(); var retVal = ReadObject(); expr = new SymbolReference(null, null, null, "null"); // TODO: faulty obv, kind of illustrates the thing though. } else if(CurrentIs(StandardByteCodes.Nothing)) { PopByte(); } else { expr = DecompileExpression(); if (expr == null && PopByte() != (byte)StandardByteCodes.Nothing) return null; //ERROR ? } var statement = new ReturnStatement(null, null, expr); StatementLocations.Add(StartPositions.Pop(), statement); return statement; }
// TODO: guess for loop, probably requires a large restructure public Statement DecompileForEach(bool isDynArray = false) { 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; }
public DelegateCall(SymbolReference del, List <Expression> arguments, SourcePosition start = null, SourcePosition end = null) : base(ASTNodeType.FunctionCall, start, end) { DelegateReference = del; Arguments = arguments; }
public DefaultPropertiesBlock ConvertDefaultProperties(List<ME3DefaultProperty> properties) { var defaults = new List<Statement>(); foreach (var prop in properties) { var name = new SymbolReference(null, null, null, prop.Name); var value = ConvertPropertyValue(prop); defaults.Add(new AssignStatement(name, value, null, null)); } return new DefaultPropertiesBlock(defaults, null, null); }
// TODO: replace this ugly-ass hack with proper AST support. public Expression DecompileNew() { PopByte(); var parameters = new List<Expression>(); for (int n = 0; n < 5; n++) { if (CurrentIs(StandardByteCodes.Nothing)) { parameters.Add(null); continue; } var param = DecompileExpression(); if (param == null) return null; // ERROR parameters.Add(param); } Expression first = null; if ((parameters[0] ?? parameters[1] ?? parameters[2]) != null) { var innerParms = new List<Expression>(); if (parameters[0] != null) innerParms.Add(parameters[0]); if (parameters[1] != null) innerParms.Add(parameters[1]); if (parameters[2] != null) innerParms.Add(parameters[2]); first = new FunctionCall(new SymbolReference(null, null, null, "new"), innerParms, null, null); } else { first = new SymbolReference(null, null, null, "new"); } var second = parameters[3] ?? new SymbolReference(null, null, null, "NoClass??"); var op = new InOpDeclaration("", 0, true, null, null, null, null, null, null, null); var firstHalf = new InOpReference(op, first, second, null, null); StartPositions.Pop(); if (parameters[4] != null) return new InOpReference(op, firstHalf, parameters[4], null, null); else return firstHalf; }
public Expression DecompileStructMember() { PopByte(); var MemberRef = ReadObject(); var StructRef = ReadObject(); ReadByte(); // discard unknown bytes ReadByte(); var expr = DecompileExpression(); // get the expression for struct instance if (expr == null) return null; // ERROR StartPositions.Pop(); var member = new SymbolReference(null, null, null, MemberRef.ObjectName); return new CompositeSymbolRef(expr, member, null, null); }
public bool VisitNode(SymbolReference node) { throw new NotImplementedException(); }
public FunctionCall(SymbolReference func, List <Expression> parameters, SourcePosition start, SourcePosition end) : base(ASTNodeType.FunctionCall, start, end) { Function = func; Parameters = parameters; }
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); } } } }