public LuaFile Compile(Ast.Chunk c, string name) { file = new LuaFile(); block = new Block(); block.Chunk.Name = name; block.Chunk.ArgumentCount = 0; block.Chunk.Vararg = 2; DoChunk(c); file.Main = block.Chunk; file.Main.ArgumentCount = 0; file.Main.Vararg = 2; file.Main.UpvalueCount = file.Main.Upvalues.Count; bool addRet = file.Main.Instructions.Count == 0; if (addRet == false) addRet = file.Main.Instructions[file.Main.Instructions.Count - 1].Opcode != Instruction.LuaOpcode.RETURN; if (addRet) { Instruction ret = new Instruction("RETURN"); ret.A = 0; ret.B = 1; ret.C = 0; file.Main.Instructions.Add(ret); } return file; }
public static Instruction From(uint binary) { int opcode = (int)Lua.GET_OPCODE(binary); //(int)Bit.Get(op, 1, 6); Instruction instr = new Instruction(opcode, 0); if (instr.OpcodeType == OpcodeType.ABC) { instr.A = Lua.GETARG_A(binary); instr.B = Lua.GETARG_B(binary); instr.C = Lua.GETARG_C(binary); //instr.A = Bit.Get(op, 7, 14); //instr.B = Bit.Get(op, 24, 32); //instr.C = Bit.Get(op, 15, 23); } else if (instr.OpcodeType == OpcodeType.ABx) { instr.A = Lua.GETARG_A(binary); instr.Bx = Lua.GETARG_Bx(binary); //instr.A = Bit.Get(op, 7, 14); //instr.Bx = Bit.Get(op, 15, 32); } else if (instr.OpcodeType == OpcodeType.AsBx) { instr.A = Lua.GETARG_A(binary); instr.sBx = Lua.GETARG_sBx(binary); //instr.A = Bit.Get(op, 7, 14); //instr.sBx = Bit.Get(op, 15, 32) - 131071; } return instr; }
void unOp(string opname, Expression expr) { // this and the variable reg2 are saved so that we can use the locations in // args B and C to the opcode int reg1 = block.regnum; DoExpr(expr); Instruction i = new Instruction(opname); // We no longer need reg1 through the top, so we can overwrite them block.regnum = reg1; i.A = block.getreg(); // >256 is const i.B = reg1; emit(i); }
void emit(Instruction i) { block.Chunk.Instructions.Add(i); }
void binOp(string opname, Expression left, Expression right) { // this and the variable reg2 are saved so that we can use the locations in // args B and C to the opcode int reg1, reg2; double result; if (constfolding(left, right, opname, out result) == false) { if (left is NumberExpr == false) { reg1 = block.regnum; DoExpr(left); } else reg1 = 256 + block.K[number(((NumberExpr)left).Value)]; if (right is NumberExpr == false) { reg2 = block.regnum; DoExpr(right); } else reg2 = 256 + block.K[number(((NumberExpr)right).Value)]; } else { DoExpr(new NumberExpr() { Value = result.ToString() }); return; } Instruction i = new Instruction(opname); // We no longer need reg1 through the top, so we can overwrite them block.regnum = reg1; i.A = block.getreg(); // >256 is const i.B = reg1; i.C = reg2; emit(i); }
void DoStatement(Statement s) { line = s.LineNumber; if (s is AssignmentStatement && !(s is AugmentedAssignmentStatement)) { AssignmentStatement a = s as AssignmentStatement; if (a.IsLocal == false) { for (int i = a.Rhs.Count; i > 0; i--) DoExpr(a.Rhs[i - 1], false, a.Lhs.Count); for (int i = a.Lhs.Count; i > 0; i--) DoExpr(a.Lhs[i - 1], true); return; } else { for (int i = a.Rhs.Count; i > 0; i--) DoExpr(a.Rhs[i - 1], false, a.Lhs.Count); for (int i = a.Lhs.Count; i > 0; i--) DoExpr(a.Lhs[i - 1], true); return; } } else if (s is AugmentedAssignmentStatement) { AugmentedAssignmentStatement aas = s as AugmentedAssignmentStatement; StringBuilder sb = new StringBuilder(); //sb.Append(DoExpr(a.Lhs[0])); if (aas.IsLocal) throw new LuaSourceException(s.LineNumber, 0, "Local assignment cannot have augmented operators"); DoExpr(aas.Rhs[0], true, 1); DoExpr(aas.Lhs[0], true, 1); return; } else if (s is BreakStatement) { bool hadLoop = false; while (block != null) { if (block.IsLoop) { hadLoop = true; break; } block = block.PreviousBlock; } if (!hadLoop) throw new LuaSourceException(s.LineNumber, 0, "No loop to break"); Instruction i = new Instruction("JMP"); i.A = 0; i.sBx = -1; // Infinite loop ;) emit(i); patchSbx.Push(i); return; } else if (s is ContinueStatement) { } else if (s is CallStatement) { CallStatement cs = s as CallStatement; DoExpr(cs.Expression); return; } else if (s is DoStatement) { } else if (s is GenericForStatement) { } else if (s is NumericForStatement) { } else if (s is FunctionStatement) { } else if (s is GotoStatement) ; else if (s is IfStmt) { } else if (s is LabelStatement) ; else if (s is RepeatStatement) { } else if (s is ReturnStatement) { } else if (s is UsingStatement) { } else if (s is WhileStatement) { WhileStatement ws = s as WhileStatement; int start = block.Chunk.Instructions.Count; DoExpr(ws.Condition); Instruction t = new Instruction("TEST"); t.A = block.regnum; t.C = 0; emit(t); DoChunk(ws.Body, true); Instruction i = new Instruction("JMP"); i.A = 0; i.sBx = -(block.Chunk.Instructions.Count - start) - 1; emit(i); while (patchSbx.Count > 0) patchSbx.Pop().sBx = Math.Abs(block.Chunk.Instructions.Count + i.sBx - 1); //return; } throw new NotImplementedException(s.GetType().Name + " is not implemented"); }
void DoExpr(Expression e, bool setVar = false, int setVarLhsCount = -1, bool onlyCheckConsts = false) { if (e is AnonymousFunctionExpr) // function() ... end { } else if (e is BinOpExpr) { BinOpExpr boe = e as BinOpExpr; switch (boe.GetOperator()) { case BinaryOperator.Add: binOp("ADD", boe.Lhs, boe.Rhs); return; case BinaryOperator.Subtract: binOp("SUB", boe.Lhs, boe.Rhs); return; case BinaryOperator.Multiply: binOp("MUL", boe.Lhs, boe.Rhs); return; case BinaryOperator.Divide: binOp("DIV", boe.Lhs, boe.Rhs); return; case BinaryOperator.Power: binOp("POW", boe.Lhs, boe.Rhs); return; case BinaryOperator.Modulus: binOp("MOD", boe.Lhs, boe.Rhs); return; case BinaryOperator.Concat: binOp("CONCAT", boe.Lhs, boe.Rhs); return; case BinaryOperator.And: break; case BinaryOperator.Or: break; case BinaryOperator.LessThan: break; case BinaryOperator.LessThanOrEqualTo: break; case BinaryOperator.GreaterThan: break; case BinaryOperator.GreaterThanOrEqualTo: break; case BinaryOperator.NotEqual: break; case BinaryOperator.ShiftRight: CallExpr ce = new CallExpr(); ce.Arguments.Add(boe.Lhs); ce.Arguments.Add(boe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } }, Ident = "rshift", Indexer = ".", }; DoExpr(ce); return; case BinaryOperator.ShiftLeft: ce = new CallExpr(); ce.Arguments.Add(boe.Lhs); ce.Arguments.Add(boe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } }, Ident = "lshift", Indexer = ".", }; DoExpr(ce); return; case BinaryOperator.Xor: ce = new CallExpr(); ce.Arguments.Add(boe.Lhs); ce.Arguments.Add(boe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } }, Ident = "bxor", Indexer = ".", }; DoExpr(ce); return; case BinaryOperator.BitAnd: ce = new CallExpr(); ce.Arguments.Add(boe.Lhs); ce.Arguments.Add(boe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } }, Ident = "band", Indexer = ".", }; DoExpr(ce); return; case BinaryOperator.BitOr: ce = new CallExpr(); ce.Arguments.Add(boe.Lhs); ce.Arguments.Add(boe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } }, Ident = "bor", Indexer = ".", }; DoExpr(ce); return; case BinaryOperator.BitNot: ce = new CallExpr(); ce.Arguments.Add(boe.Lhs); ce.Arguments.Add(boe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } }, Ident = "bnot", Indexer = ".", }; DoExpr(ce); return; case BinaryOperator.NONE: default: throw new Exception("Unknown binary operator '" + boe.Op + "'"); } } else if (e is BoolExpr) { bool v = ((BoolExpr)e).Value; Instruction i = new Instruction("LOADBOOL"); i.A = block.getreg(); i.B = v ? 1 : 0; i.C = 0; emit(i); return; } else if (e is CallExpr)//&& (!(e is StringCallExpr) && !(e is TableCallExpr))) { CallExpr ce = e as CallExpr; int breg = ++block.regnum; DoExpr(ce.Base); bool isZero = false; bool isMethod = false; Expression ex = ce.Base; while (ex != null) { if (ex is IndexExpr) ex = ((IndexExpr)ex).Index; else if (ex is MemberExpr) { MemberExpr me = ex as MemberExpr; if (me.Indexer == ":") { isMethod = true; break; } else break; //ex = me.Ident; } else break; } foreach (Expression e2 in ce.Arguments) { DoExpr(e2); if (e2 is CallExpr || block.Chunk.Instructions[block.Chunk.Instructions.Count - 1].Opcode == Instruction.LuaOpcode.CALL) { isZero = true; Instruction i_ = block.Chunk.Instructions[block.Chunk.Instructions.Count - 1]; Debug.Assert(i_.Opcode == Instruction.LuaOpcode.CALL); i_.C = 0; } } Instruction i = new Instruction("CALL"); i.A = breg; if (isMethod) //i.B++; i.B = isZero ? 2 : (ce.Arguments.Count > 0 ? 2 + ce.Arguments.Count : 2); else i.B = isZero ? 0 : (ce.Arguments.Count > 0 ? 1 + ce.Arguments.Count : 1); i.C = setVarLhsCount == 0 || setVarLhsCount == -1 ? 1 : //(isZero ? 0 : 1) : 1 + setVarLhsCount; // (isZero ? 0 : 1 + setVarLhsCount); //i.C = setVarLhsCount == 0 || setVarLhsCount == -1 ? 1 : 1 + setVarLhsCount; emit(i); return; } else if (e is StringCallExpr) { throw new Exception(); } else if (e is TableCallExpr) { throw new Exception(); } else if (e is IndexExpr) { IndexExpr ie = e as IndexExpr; int regnum = block.regnum; DoExpr(ie.Base); DoExpr(ie.Index); Instruction i = new Instruction("GETTABLE"); i.A = regnum; i.B = regnum; i.C = block.regnum - 1;// block.getreg(); emit(i); block.regnum = regnum + 1; return; } else if (e is InlineFunctionExpression) // |<args>| -> <exprs> { InlineFunctionExpression i = e as InlineFunctionExpression; AnonymousFunctionExpr af = new AnonymousFunctionExpr(); af.Arguments = i.Arguments; af.IsVararg = i.IsVararg; af.Body = new List<Statement>() { new ReturnStatement { Arguments = i.Expressions } }; DoExpr(af); } else if (e is MemberExpr) { MemberExpr me = e as MemberExpr; if (me.Indexer == ".") { int regnum = block.regnum; DoExpr(me.Base); DoExpr(new StringExpr(me.Ident), false, -1, true); Instruction i = new Instruction("GETTABLE"); i.A = regnum; i.B = regnum; i.C = 256 + block.K[me.Ident]; //i.C = block.regnum - 1;// block.getreg(); emit(i); block.regnum = regnum + 1; return; } else if (me.Indexer == ":") { int regnum = block.regnum; DoExpr(me.Base); DoExpr(new StringExpr(me.Ident), false, -1, true); Instruction i = new Instruction("SELF"); i.A = regnum; i.B = regnum; i.C = 256 + block.K[me.Ident]; //i.C = block.regnum - 1;// block.getreg(); emit(i); block.regnum = regnum + 1; return; } else throw new Exception("Unknown member indexer '" + me.Indexer + "'"); } else if (e is NilExpr) { Instruction i = new Instruction("LOADNIL"); i.A = block.getreg(); i.B = setVarLhsCount == -1 ? i.A : setVarLhsCount - 1; i.C = 0; emit(i); return; } else if (e is NumberExpr) { NumberExpr ne = e as NumberExpr; // TODO: this can optimized into a Dictionary to avoid re-parsing numbers each time double r; int x = Lua.luaO_str2d(ne.Value.Replace("_", ""), out r); if (x == 0) throw new LuaSourceException(line, 0, "Invalid number"); if (onlyCheckConsts == false) { Instruction i = new Instruction("loadk"); i.A = block.getreg(); i.Bx = block.K[r]; emit(i); } else block.K.Check(r); return; } else if (e is StringExpr) { StringExpr se = e as StringExpr; string s = se.Value; if (se.StringType != TokenType.LongString) s = Unescaper.Unescape(s); else { int i = 1; while (s[i] != '[') i++; i++; s = s.Substring(i, s.Length - i - 2); } if (onlyCheckConsts == false) { Instruction i2 = new Instruction("loadk"); i2.A = block.getreg(); i2.Bx = block.K[s]; emit(i2); } else block.K.Check(s); return; } else if (e is TableConstructorExpr) { Instruction i = new Instruction("NEWTABLE"); int tblA = block.regnum; i.A = block.getreg(); i.B = 0; i.C = 0; emit(i); TableConstructorExpr tce = e as TableConstructorExpr; if (tce.EntryList.Count == 0) return; int b = 0; bool wasLastCall = false; foreach (Expression e2 in tce.EntryList) { if (e2 is TableConstructorKeyExpr) { TableConstructorKeyExpr tcke = e2 as TableConstructorKeyExpr; DoExpr(tcke.Key); DoExpr(tcke.Value); } else if (e2 is TableConstructorNamedFunctionExpr) { TableConstructorNamedFunctionExpr tcnfe = e2 as TableConstructorNamedFunctionExpr; } else if (e2 is TableConstructorStringKeyExpr) { TableConstructorStringKeyExpr tcske = e2 as TableConstructorStringKeyExpr; DoExpr(new StringExpr(tcske.Key)); DoExpr(tcske.Value); } else if (e2 is TableConstructorValueExpr) { TableConstructorValueExpr tcve = e2 as TableConstructorValueExpr; DoExpr(tcve.Value); if (tcve.Value is VarargExpr || tcve.Value is CallExpr) wasLastCall = true; else wasLastCall = false; } b++; } i.B = b; i = new Instruction("SETLIST"); i.A = tblA; if (wasLastCall) i.B = 0; else i.B = block.regnum - 1; i.C = tblA + 1; emit(i); block.regnum = tblA; return; } else if (e is UnOpExpr) { UnOpExpr uoe = e as UnOpExpr; switch (uoe.GetOperator()) { case UnaryOperator.Not: unOp("NOT", uoe.Rhs); return; case UnaryOperator.Length: unOp("LEN", uoe.Rhs); return; case UnaryOperator.BitNot: CallExpr ce = new CallExpr(); ce.Arguments.Add(uoe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "bit", IsGlobal = true } }, Ident = "bnot", Indexer = ".", }; DoExpr(ce); return; case UnaryOperator.Negate: unOp("UNM", uoe.Rhs); return; case UnaryOperator.UnNegate: ce = new CallExpr(); ce.Arguments.Add(uoe.Rhs); ce.Base = new MemberExpr() { Base = new VariableExpression() { Var = new Variable() { Name = "math", IsGlobal = true } }, Ident = "abs", Indexer = ".", }; DoExpr(ce); return; case UnaryOperator.NONE: default: throw new Exception("Unknown unary operator '" + uoe.Op + "'"); } } else if (e is VarargExpr) { if (block.Chunk.Vararg == 0) throw new LuaSourceException(0, 0, "Cannot use varargs (...) outside of a vararg function"); Instruction i = new Instruction("VARARG"); i.A = block.getreg(); if (setVar) { i.B = setVarLhsCount == -1 ? 0 : 1 + setVarLhsCount; } else { i.B = 0; } emit(i); return; } else if (e is VariableExpression) { VariableExpression ve = e as VariableExpression; if (ve.Var.IsGlobal == false) { // local if (setVar) { //Instruction i = new Instruction("move"); //i.B = block.V[ve.Var.Name]; // moved into here //i.A = block.getreg(); // from here //emit(i); int _TMP_001_ = block.V[ve.Var.Name]; // Should probably just add a Check method in Var2Reg block.CheckLocalName(ve.Var.Name); } else { Instruction i = new Instruction("move"); i.B = block.V[ve.Var.Name]; // moved into here i.A = block.getreg(); // from here emit(i); } } else { // global Instruction i = null; if (setVar) { i = new Instruction("setglobal"); i.A = block.regnum - 1; // ret } else { i = new Instruction("getglobal"); i.A = block.getreg(); // ret } i.Bx = block.K[ve.Var.Name]; // const emit(i); } return; } throw new NotImplementedException(e.GetType().Name + " is not implemented"); }
bool constfolding(Expression a, Expression b, string opcode1, out double ret) { ret = 0; if (a is NumberExpr == false || b is NumberExpr == false) return false; double l = number(((NumberExpr)a).Value); double r = number(((NumberExpr)b).Value); Instruction opcode = new Instruction(opcode1); switch (opcode.Opcode) { case Instruction.LuaOpcode.ADD: ret = l + r; return true; case Instruction.LuaOpcode.SUB: ret = l - r; return true; break; case Instruction.LuaOpcode.MUL: ret = l * r; return true; case Instruction.LuaOpcode.DIV: if (l == 0 || r == 0) return false; ret = l / r; return true; case Instruction.LuaOpcode.MOD: if (l == 0 || r == 0) return false; ret = l % r; return true; case Instruction.LuaOpcode.POW: if (l == 0 || r == 0) return false; ret = System.Math.Pow(l, r); return true; case Instruction.LuaOpcode.CONCAT: break; case Instruction.LuaOpcode.EQ: break; case Instruction.LuaOpcode.LT: break; case Instruction.LuaOpcode.LE: break; default: break; } return false; }
public LuaFile Parse(string t) { this.text = t; file = new LuaFile(); index = 0; lineNumber = 1; func = file.Main; file.Main.Vararg = 2; file.Main.Name = "LASM Chunk"; funcStack = new Stack<Chunk>(); readWhitespace(); while (text.Length > index) { readWhitespace(); string line = ""; while (true) { if (text.Length <= index) break; char c = text[index]; if (c == '\r') { index++; if (text[index] == '\n') index++; break; } else if (c == '\n') { index++; break; } else line += c; index++; } line = line.Trim(); if (string.IsNullOrEmpty(line) || line[0] == ';') { } // do nothing. else if (line[0] == '.') parseControl(line); else { Instruction op = parseOpcode(line); op.LineNumber = lineNumber; func.Instructions.Add(op); } lineNumber++; } Instruction instr1 = func.Instructions.Count > 0 ? func.Instructions[func.Instructions.Count - 1] : null; Instruction instr2 = new Instruction("RETURN"); instr2.A = 0; instr2.B = 1; instr2.C = 0; //getmetatable(func.Instructions).__newindex(func.Instructions, func.Instructions.Count, op) if (instr1 == null || instr1.Opcode != Instruction.LuaOpcode.RETURN) func.Instructions.Add(instr2); return file; }
void parseControl(string line) { string ll = line.ToLower(); if (ll.Substring(0, 6) == ".const") { string l = line.Substring(6); l = l.Trim(); object value = readValue(l); if (value == null) func.Constants.Add(new Constant(ConstantType.Nil, null)); else if (value is bool) func.Constants.Add(new Constant(ConstantType.Bool, (bool)value)); else if (value is double) func.Constants.Add(new Constant(ConstantType.Number, (double)value)); else if (value is string) func.Constants.Add(new Constant(ConstantType.String, (string)value)); } else if (ll.Substring(0, 5) == ".name") { /// Im lazy :P string l = line.Substring(5); l = l.Trim(); if (l[0] == '"') func.Name = (string)readValue(l); else func.Name = l; } else if (ll.Substring(0, 8) == ".options") { string l = line.Substring(8); l = l.Trim(); List<int> nums = new List<int>(); // Pattern matching time! Regex r = new Regex("\\d+"); foreach (Match m in r.Matches(l)) nums.Add(int.Parse(m.Value)); func.UpvalueCount = nums.Count > 0 ? nums[0] : func.UpvalueCount; func.ArgumentCount = nums.Count > 1 ? nums[1] : func.ArgumentCount; func.Vararg = nums.Count > 2 ? nums[2] : func.Vararg; func.MaxStackSize = nums.Count > 3 ? (uint)nums[3] : func.MaxStackSize; } else if (ll.Substring(0, 6) == ".local") { string l = line.Substring(6).Trim(); if (l[0] == '"') func.Locals.Add(new Local((string)readValue(l), 0, 0)); else func.Locals.Add(new Local(l, 0, 0)); } else if (ll.Substring(0, 6) == ".upval") { string l = line.Substring(6).Trim(); if (l[0] == '"') func.Upvalues.Add(new Upvalue((string)readValue(l))); else func.Upvalues.Add(new Upvalue(l)); } else if (ll.Substring(0, 8) == ".upvalue") { string l = line.Substring(8).Trim(); if (l[0] == '"') func.Upvalues.Add(new Upvalue((string)readValue(l))); else func.Upvalues.Add(new Upvalue(l)); } else if (ll.Substring(0, 10) == ".stacksize") { string l = line.Substring(10).Trim(); uint n = uint.Parse(l); func.MaxStackSize = n; } else if (ll.Substring(0, 13) == ".maxstacksize") { string l = line.Substring(13).Trim(); uint n = uint.Parse(l); func.MaxStackSize = n; } else if (ll.Substring(0, 7) == ".vararg") { string l = line.Substring(7).Trim(); int n = int.Parse(l); func.Vararg = n; } else if (ll.Substring(0, 9) == ".function") { string l = line.Substring(9).Trim(); Chunk n = new Chunk(); n.FirstLine = (uint)lineNumber; if (l.Length > 0) if (l[0] == '"') n.Name = (string)readValue(l); else n.Name = l; func.Protos.Add(n); funcStack.Push(func); func = n; } else if (ll.Substring(0, 5) == ".func") { string l = line.Substring(5).Trim(); Chunk n = new Chunk(); n.FirstLine = (uint)lineNumber; if (l.Length > 0) if (l[0] == '"') n.Name = (string)readValue(l); else n.Name = l; func.Protos.Add(n); funcStack.Push(func); func = n; } else if (ll.Substring(0, 4) == ".end") { Chunk f = funcStack.Pop(); func.LastLine = (ulong)lineNumber; Instruction instr1 = func.Instructions.Count > 0 ? func.Instructions[func.Instructions.Count - 1] : null; Instruction instr2 = new Instruction("RETURN"); instr2.A = 0; instr2.B = 1; instr2.C = 0; if (instr1 != null && instr1.Opcode == Instruction.LuaOpcode.RETURN) { } //func.Instructions.Add(instr2); else func.Instructions.Add(instr2); func = f; } else throw new Exception("Invalid Control Label"); }
Instruction parseOpcode(string line) { string op = ""; int i = 0; string l = line.ToLower(); while (true) { if (i >= l.Length) break; if (!char.IsLetter(l[i])) break; else op += l[i++]; } Instruction instr = new Instruction(op, 0); line = line.Substring(i).Trim(); i = 0; switch (instr.OpcodeType) { case OpcodeType.ABC: string a = "", b = "", c = ""; bool inA = true, inB = false; while (true) { if (line.Length <= i) break; char ch = line[i]; if (ch == '\t' || ch == ' ') if (inA) { inB = true; inA = false; } else if (inB) inB = false; else break; else if (inA) a = a + ch; else if (inB) b = b + ch; else c = c + ch; i++; } c = c == "" ? "0" : c; instr.A = tonumber(a); instr.B = tonumber(b); instr.C = tonumber(c); break; case OpcodeType.ABx: string bx = ""; a = ""; inA = true; while (true) { if (line.Length <= i) break; char ch = line[i]; if (ch == '\t' || ch == ' ') if (inA) inA = false; else break; else if (inA) a = a + ch; else bx = bx + ch; i++; } instr.A = tonumber(a); instr.Bx = tonumber(bx); break; case OpcodeType.AsBx: string sbx = ""; a = ""; inA = true; while (true) { if (line.Length <= i) break; char ch = line[i]; if (ch == '\t' || ch == ' ') if (inA) inA = false; else break; else if (inA) a = a + ch; else sbx = sbx + ch; i++; } instr.A = tonumber(a); instr.sBx = tonumber(sbx); break; default: break; } return instr; }
public static string Opcode(Instruction op) { long c0, c1, c2, c3; if (op.OpcodeType == OpcodeType.AsBx) { long Bx = op.sBx + 131071; long C = Bit.keep(Bx, 9); long B = Bit.srb(Bx, 9); c0 = op.OpcodeNumber + Bit.slb(Bit.keep(op.A, 2), 6); c1 = Bit.srb(op.A, 2) + Bit.slb(Bit.keep(C, 2), 6); c2 = Bit.srb(C, 2) + Bit.slb(Bit.keep(B, 1), 7); c3 = Bit.srb(B, 1); } else if (op.OpcodeType == OpcodeType.ABx) { long C = Bit.keep(op.Bx, 9); long B = Bit.srb(op.Bx, 9); c0 = op.OpcodeNumber + Bit.slb(Bit.keep(op.A, 2), 6); c1 = Bit.srb(op.A, 2) + Bit.slb(Bit.keep(C, 2), 6); c2 = Bit.srb(C, 2) + Bit.slb(Bit.keep(B, 1), 7); c3 = Bit.srb(B, 1); } else { c0 = op.OpcodeNumber + Bit.slb(Bit.keep(op.A, 2), 6); c1 = Bit.srb(op.A, 2) + Bit.slb(Bit.keep(op.C, 2), 6); c2 = Bit.srb(op.C, 2) + Bit.slb(Bit.keep(op.B, 1), 7); c3 = Bit.srb(op.B, 1); } StringBuilder sb = new StringBuilder(); sb.Append((char)c0); sb.Append((char)c1); sb.Append((char)c2); sb.Append((char)c3); return sb.ToString(); }