private void ParseVariableDeclaration() { while (file.Match(new byte[] { 0x00, 0x02 })) { if (file.IsMatch(new byte[] { 0x00 }) || file.IsMatch(new byte[] { 0x01 }) || file.IsMatch(new byte[] { 0x02 }) || file.IsMatch(new byte[] { 0x03 }) || file.IsMatch(new byte[] { 0x04 }) || file.IsMatch(new byte[] { 0x05 }) || file.IsMatch(new byte[] { 0x06 }) || file.IsMatch(new byte[] { 0x07 }) || file.IsMatch(new byte[] { 0x08 })) { CotophaAST.CotophaVariable obj = new CotophaAST.CotophaVariable(); byte typeId = file.ReadByte(); obj.context = 0; obj.type = typeId; if (typeId == 0) { obj.objectName = GetConstString(); //Console.WriteLine("PUSHCONST {0} {1:x2} {2} {3:x8}", variableTypes[typeId], objectNameLen, FindConstString(curOffset, imageOffset), unk3); } obj.name = file.ReadString(); functions.Last().stack.Add(obj); } else { Console.WriteLine("Inspect code located at 0x{0:x8}", (int)file.GetPosition() - 1); Environment.Exit(1); } ParseExpression(); } }
private void ParseExpression() { ParseVariableDeclaration(); if (showDebug) { Console.WriteLine("pos[{0:x8}] op[{1:x2}]", file.GetPosition(), file.PeekByte()); } if (file.Match(new byte[] { 0x02, 0x02, 0x01 })) // push "this" { CotophaAST.CotophaVariable obj = new CotophaAST.CotophaVariable(); obj.name = "this"; functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x02, 0x03, 0x04 })) // push global variable { functions.Last().stack.Add(GetGlobalVariable()); } else if (file.Match(new byte[] { 0x02, 0x02, 0x06 })) { // variable initialization string variableName = file.ReadString(); bool hasParent = false; bool hasThis = false; if (variableName == "parent") { hasParent = true; } foreach (var cmd in functions.Last().arguments) { if (cmd.argumentName == "this") { hasThis = true; break; } } CotophaAST.CotophaVariable obj = new CotophaAST.CotophaVariable(); byte typeId = 0; bool hasType = true; obj.hasValue = true; if (hasParent) { obj.objectName = "parent"; } else { obj.objectName = "this"; } obj.name = variableName; obj.type = typeId; if (obj.objectName == "parent") { obj.type = 0; obj.showType = false; } if (file.Match(new byte[] { 0x02, 0x00 })) { typeId = file.ReadByte(); //functions.Last().stack.Last().Print(); //obj.Print(); if (typeId == 0) // object { obj.stringValue = GetConstString(); } else if (typeId == 4) // integer { obj.intValue = file.ReadInt32(); } else if (typeId == 5) // real { obj.realValue = file.ReadDouble(); } else if (typeId == 6) // string { obj.stringValue = file.ReadString(); } else { functions.Last().stack.Last().Print(); Console.WriteLine("Unhandled variable assignment: stringValue type id {0} at 0x{1:x8}", typeId, (int)file.GetPosition()); Environment.Exit(1); } } else { obj.hasValue = false; obj.showType = false; } functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x0b })) // subscript index { if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaVariable)) { var obj = (CotophaAST.CotophaVariable)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var idxObj = new CotophaAST.CotophaInteger(); idxObj.intValue = obj.intValue; obj.SetIndex(idxObj); obj.hasValue = false; //obj.showType = false; functions.Last().stack.Add(obj); } else if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaInteger)) { var obj1 = (CotophaAST.CotophaInteger)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var obj2 = (CotophaAST.CotophaVariable)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var obj3 = new CotophaAST.CotophaVariable(); var idxObj = new CotophaAST.CotophaInteger(); idxObj.intValue = obj1.intValue; obj3.SetIndex(idxObj); obj3.name = obj2.name; obj3.type = 4; obj3.showType = false; obj3.hasValue = false; functions.Last().stack.Add(obj3); } else if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaString)) { var obj3 = new CotophaAST.CotophaVariable(); var obj1 = (CotophaAST.CotophaString)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj3.type = 4; obj3.showType = false; obj3.hasValue = false; obj3.SetIndex(obj1); if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaString)) { var obj2 = (CotophaAST.CotophaString)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj3.name = obj2.stringValue; } else if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaVariable)) { var obj2 = (CotophaAST.CotophaVariable)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj3.name = obj2.name; } functions.Last().stack.Add(obj3); } else { Console.WriteLine("Don't know how to handle type {0}", functions.Last().stack.Last().objType); Environment.Exit(1); } } else if (file.Match(new byte[] { 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00 })) // EndFunc { functions.Last().isStruct = false; //functions.Last().Print(); } else if (file.Match(new byte[] { 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01 })) // EndStruct { functions.Last().isStruct = true; //functions.Last().Print(); } else if (file.Match(new byte[] { 0x09, 0x00 })) // return { CotophaAST.CotophaReturn obj = new CotophaAST.CotophaReturn(); var lastObject = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj.returnObject = lastObject; //obj.returnObject.Print(); functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x09, 0x01 })) // end of file { endOfFile = true; } else if (file.Match(new byte[] { 0x02, 0x00, 0x00 })) // object { string value = GetConstString(); ; CotophaAST.CotophaObject obj = new CotophaAST.CotophaObject(); obj.stringValue = value; functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x02, 0x00, 0x04 })) // integer { int value = file.ReadInt32(); CotophaAST.CotophaInteger obj = new CotophaAST.CotophaInteger(); obj.intValue = value; functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x02, 0x00, 0x05 })) // real { double value = file.ReadDouble(); CotophaAST.CotophaReal obj = new CotophaAST.CotophaReal(); obj.realValue = value; functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x02, 0x00, 0x06 })) // string { string value = file.ReadString(); CotophaAST.CotophaString obj = new CotophaAST.CotophaString(); obj.stringValue = value; functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x02, 0x01, 0x04 })) // variable reference { int idx = file.ReadInt32(); int variableCount = 0; CotophaAST.CotophaVariable variableName = new CotophaAST.CotophaVariable(); bool found = false; foreach (var cmd in functions.Last().variables) { if (idx == variableCount) { variableName.name = cmd.name; found = true; break; } variableCount++; } if (!found) { functions.Last().Print(); Console.WriteLine("Could not find variable"); Environment.Exit(1); } functions.Last().stack.Add(variableName); } else if (file.Match(new byte[] { 0x0a, 0x06 })) // member variable { if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaString)) { var obj2 = (CotophaAST.CotophaString)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); string name = GetConstString(); //functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj2.stringValue += "." + name; obj2.Print(); functions.Last().stack.Add(obj2); } else if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaVariable)) { var obj2 = (CotophaAST.CotophaVariable)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); string name = GetConstString(); //functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var nameObject = new CotophaAST.CotophaString(); nameObject.stringValue = name; obj2.leftObject = nameObject; functions.Last().stack.Add(obj2); } else { Console.WriteLine("Unexpected left name type: {0}", functions.Last().stack.Last().objType); Environment.Exit(1); } } else if (file.Match(new byte[] { 0x03, 0xff })) { //Console.WriteLine("Reached 0x03 0xff {0:x2}", file.PeekByte()); bool showType = !file.Match(new byte[] { 0x01 }); var obj = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaVariable)) { var obj2 = (CotophaAST.CotophaVariable)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj2.hasValue = true; obj2.showType = showType; obj2.rightObject = obj; functions.Last().stack.Add(obj2); //obj2.Print(); } else if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaString)) { var obj2 = (CotophaAST.CotophaString)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var obj3 = new CotophaAST.CotophaVariable(); obj3.name = obj2.stringValue; obj3.hasValue = true; obj3.showType = showType; obj3.rightObject = obj; functions.Last().stack.Add(obj3); //obj3.Print(); } else if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaReal)) { var obj2 = (CotophaAST.CotophaReal)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var obj3 = new CotophaAST.CotophaCall(); obj3.left = "Real"; obj3.args.Add(obj); functions.Last().stack.Add(obj3); } else { Console.WriteLine("Unexpected left hand type: {0}", functions.Last().stack.Last().objType); Environment.Exit(1); } if (file.Match(new byte[] { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })) // repeat { functions.Last().stack.Add(new CotophaAST.CotophaRepeatStatement()); ParseVariableDeclaration(); } } else if (file.Match(new byte[] { 0x00, 0x01 })) // local variable { if (file.IsMatch(new byte[] { 0x00 }) || file.IsMatch(new byte[] { 0x01 }) || file.IsMatch(new byte[] { 0x02 }) || file.IsMatch(new byte[] { 0x03 }) || file.IsMatch(new byte[] { 0x04 }) || file.IsMatch(new byte[] { 0x05 }) || file.IsMatch(new byte[] { 0x06 }) || file.IsMatch(new byte[] { 0x07 }) || file.IsMatch(new byte[] { 0x08 })) { CotophaAST.CotophaVariable obj = new CotophaAST.CotophaVariable(); byte typeId = file.ReadByte(); obj.context = 0; obj.type = typeId; if (typeId == 0) { obj.objectName = GetConstString(); } obj.name = file.ReadString(); functions.Last().stack.Add(obj); } else { Console.WriteLine("Handle non-0x02 0x00 case in 0x00 0x01 @ 0x{0:x8}", (int)file.GetPosition() - 1); Environment.Exit(1); } } else if (file.Match(new byte[] { 0x03 })) // assignment operation { CotophaAST.CotophaAssignment assignment = new CotophaAST.CotophaAssignment(); int op = file.ReadByte(); var obj1 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var obj2 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); //Console.Write("0x03 obj1: "); //obj1.Print(); //Console.Write("0x03 obj2: "); //obj2.Print(); assignment.op = op; assignment.leftObject = obj2; assignment.rightObject = obj1; functions.Last().stack.Add(assignment); //assignment.Print(); } else if (file.Match(new byte[] { 0x0c })) // math operation { CotophaAST.CotophaMathOp mathop = new CotophaAST.CotophaMathOp(); int op = file.ReadByte(); var obj1 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var obj2 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); //Console.Write("0x0c obj1: "); //obj1.Print(); //Console.Write("0x0c obj2: "); //obj2.Print(); mathop.op = op; mathop.leftObject = obj2; mathop.rightObject = obj1; functions.Last().stack.Add(mathop); //mathop.Print(); } else if (file.Match(new byte[] { 0x0e })) // comparison operation { CotophaAST.CotophaComparison comparison = new CotophaAST.CotophaComparison(); int op = file.ReadByte(); var obj1 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); var obj2 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); comparison.op = op; comparison.leftObject = obj2; comparison.rightObject = obj1; functions.Last().stack.Add(comparison); } else if (file.Match(new byte[] { 0x07, 0x00 })) { int blockSize = file.ReadInt32(); long currentPosition = file.GetPosition(); var comparisonObj = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); if (functions.Last().stack.Count > 0 && functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaElseIfStatement)) { CotophaAST.CotophaElseIfStatement obj = (CotophaAST.CotophaElseIfStatement)functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj.leftObject = comparisonObj; functions.Last().stack.Add(obj); } else { //Console.WriteLine("If statement {0:x8} ({0} bytes) in length", blockSize); CotophaAST.CotophaIfStatement obj = new CotophaAST.CotophaIfStatement(); obj.leftObject = comparisonObj; functions.Last().stack.Add(obj); } if (blockSize < 0) { return; } do { ParseExpression(); } while (file.GetPosition() - currentPosition < blockSize); if (file.GetPosition() - currentPosition == blockSize) { functions.Last().stack.Add(new CotophaAST.CotophaEndIfStatement()); } else { Console.WriteLine("If block wrong size: {2:x8} {0:x8} {1:x8}", file.GetPosition() - currentPosition, blockSize, file.GetPosition()); Environment.Exit(1); } } else if (file.Match(new byte[] { 0x06 })) { int blockSize = file.ReadInt32(); long currentPosition = file.GetPosition(); if (functions.Last().stack.Last().objType == typeof(CotophaAST.CotophaEndIfStatement)) { functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); functions.Last().stack.Add(new CotophaAST.CotophaElseIfStatement()); } //Console.WriteLine("ElseIf statement {0:x8} ({0} bytes) in length", blockSize); return; /* * Console.WriteLine("{0:x8} {1:x2}", file.GetPosition(), file.PeekByte()); * functions.Last().Print(); * * Environment.Exit(1); */ } else if (file.Match(new byte[] { 0x08, 0x02 })) // member function { int arguments = file.ReadInt32(); string name = GetConstString(); CotophaAST.CotophaCall obj = new CotophaAST.CotophaCall(); obj.left = name; for (int i = 0; i < arguments; i++) { var obj2 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); if (i + 1 < arguments) { obj.args.Add(obj2); } else { obj.leftObject = obj2; } } obj.args.Reverse(); functions.Last().stack.Add(obj); //file.Match(new byte[] {0x03, 0xff, 0x01}); } else if (file.Match(new byte[] { 0x08 })) { byte type = file.ReadByte(); int arguments = file.ReadInt32(); string name = GetConstString(); CotophaAST.CotophaCall obj = new CotophaAST.CotophaCall(); obj.left = name; obj.right = ""; CotophaAST.CotophaAssignment assignment = new CotophaAST.CotophaAssignment(); assignment.op = 8; /* * if (functions.Last().stack.Count != 1) * { * assignment.leftObject = functions.Last().stack.Last(); * functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); * } */ for (int i = 0; i < arguments; i++) { var obj2 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); if (assignment.leftObject != null) { if (i + 1 < arguments) { obj.args.Add(obj2); } else { obj.leftObject = obj2; } } else { obj.args.Add(obj2); } } if (assignment.leftObject != null) { assignment.rightObject = obj; functions.Last().stack.Add(assignment); //assignment.Print(); } else { functions.Last().stack.Add(obj); //obj.Print(); } //file.Match(new byte[] {0x03, 0xff, 0x01}); } else if (file.Match(new byte[] { 0x05 })) // until { var obj = new CotophaAST.CotophaUntilStatement(); do { ParseExpression(); } while (!file.IsMatch(new byte[] { 0x07, 0x00 })); ParseExpression(); // if statement if (functions.Last().stack.Last().objType != typeof(CotophaAST.CotophaIfStatement)) { Console.WriteLine("Unexpected type on right of Until. Found {0}", functions.Last().stack.Last().objType); Environment.Exit(1); } var obj2 = functions.Last().stack.Last(); functions.Last().stack.RemoveAt(functions.Last().stack.Count - 1); obj.rightObject = obj2.leftObject; functions.Last().stack.Add(obj); } else if (file.Match(new byte[] { 0x01 })) // ? { //Console.WriteLine("0x01, ignoring..."); } else { /* * Console.WriteLine("{0:x8} {1:x2}", file.GetPosition(), file.PeekByte()); * Console.WriteLine("Don't know where to go from here"); * Environment.Exit(1); */ return; } //ParseExpression(); if (showDebug) { if (functions.Last().stack.Count > 0) { Console.Write("{0} -> ", functions.Last().stack.Last().objType); functions.Last().stack.Last().Print(); } functions.Last().Print(); } }