1*0957b409SSimon J. Gerraty /* 2*0957b409SSimon J. Gerraty * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 3*0957b409SSimon J. Gerraty * 4*0957b409SSimon J. Gerraty * Permission is hereby granted, free of charge, to any person obtaining 5*0957b409SSimon J. Gerraty * a copy of this software and associated documentation files (the 6*0957b409SSimon J. Gerraty * "Software"), to deal in the Software without restriction, including 7*0957b409SSimon J. Gerraty * without limitation the rights to use, copy, modify, merge, publish, 8*0957b409SSimon J. Gerraty * distribute, sublicense, and/or sell copies of the Software, and to 9*0957b409SSimon J. Gerraty * permit persons to whom the Software is furnished to do so, subject to 10*0957b409SSimon J. Gerraty * the following conditions: 11*0957b409SSimon J. Gerraty * 12*0957b409SSimon J. Gerraty * The above copyright notice and this permission notice shall be 13*0957b409SSimon J. Gerraty * included in all copies or substantial portions of the Software. 14*0957b409SSimon J. Gerraty * 15*0957b409SSimon J. Gerraty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16*0957b409SSimon J. Gerraty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17*0957b409SSimon J. Gerraty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18*0957b409SSimon J. Gerraty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19*0957b409SSimon J. Gerraty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20*0957b409SSimon J. Gerraty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21*0957b409SSimon J. Gerraty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22*0957b409SSimon J. Gerraty * SOFTWARE. 23*0957b409SSimon J. Gerraty */ 24*0957b409SSimon J. Gerraty 25*0957b409SSimon J. Gerraty using System; 26*0957b409SSimon J. Gerraty using System.Collections.Generic; 27*0957b409SSimon J. Gerraty 28*0957b409SSimon J. Gerraty /* 29*0957b409SSimon J. Gerraty * A WordBuilder instance organizes construction of a new interpreted word. 30*0957b409SSimon J. Gerraty * 31*0957b409SSimon J. Gerraty * Opcodes are accumulated with specific methods. A control-flow stack 32*0957b409SSimon J. Gerraty * is maintained to resolve jumps. 33*0957b409SSimon J. Gerraty * 34*0957b409SSimon J. Gerraty * Each instance shall be used for only one word. 35*0957b409SSimon J. Gerraty */ 36*0957b409SSimon J. Gerraty 37*0957b409SSimon J. Gerraty class WordBuilder { 38*0957b409SSimon J. Gerraty 39*0957b409SSimon J. Gerraty T0Comp TC; 40*0957b409SSimon J. Gerraty string name; 41*0957b409SSimon J. Gerraty int[] cfStack; 42*0957b409SSimon J. Gerraty int cfPtr; 43*0957b409SSimon J. Gerraty List<Opcode> code; 44*0957b409SSimon J. Gerraty List<string> toResolve; 45*0957b409SSimon J. Gerraty Dictionary<string, int> locals; 46*0957b409SSimon J. Gerraty bool jumpToLast; 47*0957b409SSimon J. Gerraty 48*0957b409SSimon J. Gerraty internal SType StackEffect { 49*0957b409SSimon J. Gerraty get; set; 50*0957b409SSimon J. Gerraty } 51*0957b409SSimon J. Gerraty 52*0957b409SSimon J. Gerraty /* 53*0957b409SSimon J. Gerraty * Create a new instance, with the specified word name. 54*0957b409SSimon J. Gerraty */ WordBuilder(T0Comp TC, string name)55*0957b409SSimon J. Gerraty internal WordBuilder(T0Comp TC, string name) 56*0957b409SSimon J. Gerraty { 57*0957b409SSimon J. Gerraty this.TC = TC; 58*0957b409SSimon J. Gerraty this.name = name; 59*0957b409SSimon J. Gerraty cfStack = new int[16]; 60*0957b409SSimon J. Gerraty cfPtr = -1; 61*0957b409SSimon J. Gerraty code = new List<Opcode>(); 62*0957b409SSimon J. Gerraty toResolve = new List<string>(); 63*0957b409SSimon J. Gerraty locals = new Dictionary<string, int>(); 64*0957b409SSimon J. Gerraty jumpToLast = true; 65*0957b409SSimon J. Gerraty StackEffect = SType.UNKNOWN; 66*0957b409SSimon J. Gerraty } 67*0957b409SSimon J. Gerraty 68*0957b409SSimon J. Gerraty /* 69*0957b409SSimon J. Gerraty * Build the word. The control-flow stack must be empty. A 'ret' 70*0957b409SSimon J. Gerraty * opcode is automatically appended if required. 71*0957b409SSimon J. Gerraty */ Build()72*0957b409SSimon J. Gerraty internal Word Build() 73*0957b409SSimon J. Gerraty { 74*0957b409SSimon J. Gerraty if (cfPtr != -1) { 75*0957b409SSimon J. Gerraty throw new Exception("control-flow stack is not empty"); 76*0957b409SSimon J. Gerraty } 77*0957b409SSimon J. Gerraty if (jumpToLast || code[code.Count - 1].MayFallThrough) { 78*0957b409SSimon J. Gerraty Ret(); 79*0957b409SSimon J. Gerraty } 80*0957b409SSimon J. Gerraty Word w = new WordInterpreted(TC, name, locals.Count, 81*0957b409SSimon J. Gerraty code.ToArray(), toResolve.ToArray()); 82*0957b409SSimon J. Gerraty w.StackEffect = StackEffect; 83*0957b409SSimon J. Gerraty return w; 84*0957b409SSimon J. Gerraty } 85*0957b409SSimon J. Gerraty Add(Opcode op)86*0957b409SSimon J. Gerraty void Add(Opcode op) 87*0957b409SSimon J. Gerraty { 88*0957b409SSimon J. Gerraty Add(op, null); 89*0957b409SSimon J. Gerraty } 90*0957b409SSimon J. Gerraty Add(Opcode op, string refName)91*0957b409SSimon J. Gerraty void Add(Opcode op, string refName) 92*0957b409SSimon J. Gerraty { 93*0957b409SSimon J. Gerraty code.Add(op); 94*0957b409SSimon J. Gerraty toResolve.Add(refName); 95*0957b409SSimon J. Gerraty jumpToLast = false; 96*0957b409SSimon J. Gerraty } 97*0957b409SSimon J. Gerraty 98*0957b409SSimon J. Gerraty /* 99*0957b409SSimon J. Gerraty * Rotate the control-flow stack at depth 'depth'. 100*0957b409SSimon J. Gerraty */ CSRoll(int depth)101*0957b409SSimon J. Gerraty internal void CSRoll(int depth) 102*0957b409SSimon J. Gerraty { 103*0957b409SSimon J. Gerraty int x = cfStack[cfPtr - depth]; 104*0957b409SSimon J. Gerraty Array.Copy(cfStack, cfPtr - (depth - 1), 105*0957b409SSimon J. Gerraty cfStack, cfPtr - depth, depth); 106*0957b409SSimon J. Gerraty cfStack[cfPtr] = x; 107*0957b409SSimon J. Gerraty } 108*0957b409SSimon J. Gerraty 109*0957b409SSimon J. Gerraty /* 110*0957b409SSimon J. Gerraty * Make a copy of the control-flow element at depth 'depth', and 111*0957b409SSimon J. Gerraty * push it on top of the control-flow stack. 112*0957b409SSimon J. Gerraty */ CSPick(int depth)113*0957b409SSimon J. Gerraty internal void CSPick(int depth) 114*0957b409SSimon J. Gerraty { 115*0957b409SSimon J. Gerraty int x = cfStack[cfPtr - depth]; 116*0957b409SSimon J. Gerraty CSPush(x); 117*0957b409SSimon J. Gerraty } 118*0957b409SSimon J. Gerraty CSPush(int x)119*0957b409SSimon J. Gerraty void CSPush(int x) 120*0957b409SSimon J. Gerraty { 121*0957b409SSimon J. Gerraty int len = cfStack.Length; 122*0957b409SSimon J. Gerraty if (++ cfPtr == len) { 123*0957b409SSimon J. Gerraty int[] ncf = new int[len << 1]; 124*0957b409SSimon J. Gerraty Array.Copy(cfStack, 0, ncf, 0, len); 125*0957b409SSimon J. Gerraty cfStack = ncf; 126*0957b409SSimon J. Gerraty } 127*0957b409SSimon J. Gerraty cfStack[cfPtr] = x; 128*0957b409SSimon J. Gerraty } 129*0957b409SSimon J. Gerraty CSPop()130*0957b409SSimon J. Gerraty int CSPop() 131*0957b409SSimon J. Gerraty { 132*0957b409SSimon J. Gerraty return cfStack[cfPtr --]; 133*0957b409SSimon J. Gerraty } 134*0957b409SSimon J. Gerraty 135*0957b409SSimon J. Gerraty /* 136*0957b409SSimon J. Gerraty * Push an origin on the control-flow stack, corresponding to the 137*0957b409SSimon J. Gerraty * next opcode to add. 138*0957b409SSimon J. Gerraty */ CSPushOrig()139*0957b409SSimon J. Gerraty internal void CSPushOrig() 140*0957b409SSimon J. Gerraty { 141*0957b409SSimon J. Gerraty CSPush(code.Count); 142*0957b409SSimon J. Gerraty } 143*0957b409SSimon J. Gerraty 144*0957b409SSimon J. Gerraty /* 145*0957b409SSimon J. Gerraty * Push a destination on the control-flow stack, corresponding to 146*0957b409SSimon J. Gerraty * the next opcode to add. 147*0957b409SSimon J. Gerraty */ CSPushDest()148*0957b409SSimon J. Gerraty internal void CSPushDest() 149*0957b409SSimon J. Gerraty { 150*0957b409SSimon J. Gerraty CSPush(-code.Count - 1); 151*0957b409SSimon J. Gerraty } 152*0957b409SSimon J. Gerraty 153*0957b409SSimon J. Gerraty /* 154*0957b409SSimon J. Gerraty * Pop an origin from the control-flow stack. An exception is 155*0957b409SSimon J. Gerraty * thrown if the value is not an origin. 156*0957b409SSimon J. Gerraty */ CSPopOrig()157*0957b409SSimon J. Gerraty internal int CSPopOrig() 158*0957b409SSimon J. Gerraty { 159*0957b409SSimon J. Gerraty int x = CSPop(); 160*0957b409SSimon J. Gerraty if (x < 0) { 161*0957b409SSimon J. Gerraty throw new Exception("not an origin"); 162*0957b409SSimon J. Gerraty } 163*0957b409SSimon J. Gerraty return x; 164*0957b409SSimon J. Gerraty } 165*0957b409SSimon J. Gerraty 166*0957b409SSimon J. Gerraty /* 167*0957b409SSimon J. Gerraty * Pop a destination from the control-flow stack. An exception is 168*0957b409SSimon J. Gerraty * thrown if the value is not a destination. 169*0957b409SSimon J. Gerraty */ CSPopDest()170*0957b409SSimon J. Gerraty internal int CSPopDest() 171*0957b409SSimon J. Gerraty { 172*0957b409SSimon J. Gerraty int x = CSPop(); 173*0957b409SSimon J. Gerraty if (x >= 0) { 174*0957b409SSimon J. Gerraty throw new Exception("not a destination"); 175*0957b409SSimon J. Gerraty } 176*0957b409SSimon J. Gerraty return -x - 1; 177*0957b409SSimon J. Gerraty } 178*0957b409SSimon J. Gerraty 179*0957b409SSimon J. Gerraty /* 180*0957b409SSimon J. Gerraty * Add a "push literal" opcode. 181*0957b409SSimon J. Gerraty */ Literal(TValue v)182*0957b409SSimon J. Gerraty internal void Literal(TValue v) 183*0957b409SSimon J. Gerraty { 184*0957b409SSimon J. Gerraty Add(new OpcodeConst(v)); 185*0957b409SSimon J. Gerraty } 186*0957b409SSimon J. Gerraty 187*0957b409SSimon J. Gerraty /* 188*0957b409SSimon J. Gerraty * Compile a "call" by name. This method implements the support 189*0957b409SSimon J. Gerraty * for local variables: 190*0957b409SSimon J. Gerraty * 191*0957b409SSimon J. Gerraty * - If the target is '>' followed by a local variable name, then 192*0957b409SSimon J. Gerraty * a "put local" opcode is added. 193*0957b409SSimon J. Gerraty * 194*0957b409SSimon J. Gerraty * - Otherwise, if the target is a local variable name, then a 195*0957b409SSimon J. Gerraty * "get local" opcode is added. 196*0957b409SSimon J. Gerraty * 197*0957b409SSimon J. Gerraty * - Otherwise, a call to the named word is added. The target name 198*0957b409SSimon J. Gerraty * will be resolved later on (typically, when the word containing 199*0957b409SSimon J. Gerraty * the call opcode is first invoked, or when C code is generated). 200*0957b409SSimon J. Gerraty */ Call(string target)201*0957b409SSimon J. Gerraty internal void Call(string target) 202*0957b409SSimon J. Gerraty { 203*0957b409SSimon J. Gerraty string lname; 204*0957b409SSimon J. Gerraty bool write; 205*0957b409SSimon J. Gerraty if (target.StartsWith(">")) { 206*0957b409SSimon J. Gerraty lname = target.Substring(1); 207*0957b409SSimon J. Gerraty write = true; 208*0957b409SSimon J. Gerraty } else { 209*0957b409SSimon J. Gerraty lname = target; 210*0957b409SSimon J. Gerraty write = false; 211*0957b409SSimon J. Gerraty } 212*0957b409SSimon J. Gerraty int lnum; 213*0957b409SSimon J. Gerraty if (locals.TryGetValue(lname, out lnum)) { 214*0957b409SSimon J. Gerraty if (write) { 215*0957b409SSimon J. Gerraty Add(new OpcodePutLocal(lnum)); 216*0957b409SSimon J. Gerraty } else { 217*0957b409SSimon J. Gerraty Add(new OpcodeGetLocal(lnum)); 218*0957b409SSimon J. Gerraty } 219*0957b409SSimon J. Gerraty } else { 220*0957b409SSimon J. Gerraty Add(new OpcodeCall(), target); 221*0957b409SSimon J. Gerraty } 222*0957b409SSimon J. Gerraty } 223*0957b409SSimon J. Gerraty 224*0957b409SSimon J. Gerraty /* 225*0957b409SSimon J. Gerraty * Add a "call" opcode to the designated word. 226*0957b409SSimon J. Gerraty */ CallExt(Word wtarget)227*0957b409SSimon J. Gerraty internal void CallExt(Word wtarget) 228*0957b409SSimon J. Gerraty { 229*0957b409SSimon J. Gerraty Add(new OpcodeCall(wtarget), null); 230*0957b409SSimon J. Gerraty } 231*0957b409SSimon J. Gerraty 232*0957b409SSimon J. Gerraty /* 233*0957b409SSimon J. Gerraty * Add a "call" opcode to a word which is not currently resolved. 234*0957b409SSimon J. Gerraty * This method ignores local variables. 235*0957b409SSimon J. Gerraty */ CallExt(string target)236*0957b409SSimon J. Gerraty internal void CallExt(string target) 237*0957b409SSimon J. Gerraty { 238*0957b409SSimon J. Gerraty Add(new OpcodeCall(), target); 239*0957b409SSimon J. Gerraty } 240*0957b409SSimon J. Gerraty 241*0957b409SSimon J. Gerraty /* 242*0957b409SSimon J. Gerraty * Add a "get local" opcode; the provided local name must already 243*0957b409SSimon J. Gerraty * be defined. 244*0957b409SSimon J. Gerraty */ GetLocal(string name)245*0957b409SSimon J. Gerraty internal void GetLocal(string name) 246*0957b409SSimon J. Gerraty { 247*0957b409SSimon J. Gerraty int lnum; 248*0957b409SSimon J. Gerraty if (locals.TryGetValue(name, out lnum)) { 249*0957b409SSimon J. Gerraty Add(new OpcodeGetLocal(lnum)); 250*0957b409SSimon J. Gerraty } else { 251*0957b409SSimon J. Gerraty throw new Exception("no such local: " + name); 252*0957b409SSimon J. Gerraty } 253*0957b409SSimon J. Gerraty } 254*0957b409SSimon J. Gerraty 255*0957b409SSimon J. Gerraty /* 256*0957b409SSimon J. Gerraty * Add a "put local" opcode; the provided local name must already 257*0957b409SSimon J. Gerraty * be defined. 258*0957b409SSimon J. Gerraty */ PutLocal(string name)259*0957b409SSimon J. Gerraty internal void PutLocal(string name) 260*0957b409SSimon J. Gerraty { 261*0957b409SSimon J. Gerraty int lnum; 262*0957b409SSimon J. Gerraty if (locals.TryGetValue(name, out lnum)) { 263*0957b409SSimon J. Gerraty Add(new OpcodePutLocal(lnum)); 264*0957b409SSimon J. Gerraty } else { 265*0957b409SSimon J. Gerraty throw new Exception("no such local: " + name); 266*0957b409SSimon J. Gerraty } 267*0957b409SSimon J. Gerraty } 268*0957b409SSimon J. Gerraty 269*0957b409SSimon J. Gerraty /* 270*0957b409SSimon J. Gerraty * Define a new local name. 271*0957b409SSimon J. Gerraty */ DefLocal(string lname)272*0957b409SSimon J. Gerraty internal void DefLocal(string lname) 273*0957b409SSimon J. Gerraty { 274*0957b409SSimon J. Gerraty if (locals.ContainsKey(lname)) { 275*0957b409SSimon J. Gerraty throw new Exception(String.Format( 276*0957b409SSimon J. Gerraty "local already defined: {0}", lname)); 277*0957b409SSimon J. Gerraty } 278*0957b409SSimon J. Gerraty locals[lname] = locals.Count; 279*0957b409SSimon J. Gerraty } 280*0957b409SSimon J. Gerraty 281*0957b409SSimon J. Gerraty /* 282*0957b409SSimon J. Gerraty * Add a "call" opcode whose target is an XT value (which may be 283*0957b409SSimon J. Gerraty * resolved or as yet unresolved). 284*0957b409SSimon J. Gerraty */ Call(TPointerXT xt)285*0957b409SSimon J. Gerraty internal void Call(TPointerXT xt) 286*0957b409SSimon J. Gerraty { 287*0957b409SSimon J. Gerraty if (xt.Target == null) { 288*0957b409SSimon J. Gerraty Add(new OpcodeCall(), xt.Name); 289*0957b409SSimon J. Gerraty } else { 290*0957b409SSimon J. Gerraty Add(new OpcodeCall(xt.Target)); 291*0957b409SSimon J. Gerraty } 292*0957b409SSimon J. Gerraty } 293*0957b409SSimon J. Gerraty 294*0957b409SSimon J. Gerraty /* 295*0957b409SSimon J. Gerraty * Add a "ret" opcode. 296*0957b409SSimon J. Gerraty */ Ret()297*0957b409SSimon J. Gerraty internal void Ret() 298*0957b409SSimon J. Gerraty { 299*0957b409SSimon J. Gerraty Add(new OpcodeRet()); 300*0957b409SSimon J. Gerraty } 301*0957b409SSimon J. Gerraty 302*0957b409SSimon J. Gerraty /* 303*0957b409SSimon J. Gerraty * Add a forward unconditional jump. The new opcode address is 304*0957b409SSimon J. Gerraty * pushed on the control-flow stack as an origin. 305*0957b409SSimon J. Gerraty */ Ahead()306*0957b409SSimon J. Gerraty internal void Ahead() 307*0957b409SSimon J. Gerraty { 308*0957b409SSimon J. Gerraty CSPushOrig(); 309*0957b409SSimon J. Gerraty Add(new OpcodeJumpUncond()); 310*0957b409SSimon J. Gerraty } 311*0957b409SSimon J. Gerraty 312*0957b409SSimon J. Gerraty /* 313*0957b409SSimon J. Gerraty * Add a forward conditional jump, which will be taken at runtime 314*0957b409SSimon J. Gerraty * if the top-of-stack value is 'true'. The new opcode address is 315*0957b409SSimon J. Gerraty * pushed on the control-flow stack as an origin. 316*0957b409SSimon J. Gerraty */ AheadIf()317*0957b409SSimon J. Gerraty internal void AheadIf() 318*0957b409SSimon J. Gerraty { 319*0957b409SSimon J. Gerraty CSPushOrig(); 320*0957b409SSimon J. Gerraty Add(new OpcodeJumpIf()); 321*0957b409SSimon J. Gerraty } 322*0957b409SSimon J. Gerraty 323*0957b409SSimon J. Gerraty /* 324*0957b409SSimon J. Gerraty * Add a forward conditional jump, which will be taken at runtime 325*0957b409SSimon J. Gerraty * if the top-of-stack value is 'false'. The new opcode address is 326*0957b409SSimon J. Gerraty * pushed on the control-flow stack as an origin. 327*0957b409SSimon J. Gerraty */ AheadIfNot()328*0957b409SSimon J. Gerraty internal void AheadIfNot() 329*0957b409SSimon J. Gerraty { 330*0957b409SSimon J. Gerraty CSPushOrig(); 331*0957b409SSimon J. Gerraty Add(new OpcodeJumpIfNot()); 332*0957b409SSimon J. Gerraty } 333*0957b409SSimon J. Gerraty 334*0957b409SSimon J. Gerraty /* 335*0957b409SSimon J. Gerraty * Resolve a previous forward jump to the current code address. 336*0957b409SSimon J. Gerraty * The top of control-flow stack is popped and must be an origin. 337*0957b409SSimon J. Gerraty */ Then()338*0957b409SSimon J. Gerraty internal void Then() 339*0957b409SSimon J. Gerraty { 340*0957b409SSimon J. Gerraty int x = CSPopOrig(); 341*0957b409SSimon J. Gerraty code[x].ResolveJump(code.Count - x - 1); 342*0957b409SSimon J. Gerraty jumpToLast = true; 343*0957b409SSimon J. Gerraty } 344*0957b409SSimon J. Gerraty 345*0957b409SSimon J. Gerraty /* 346*0957b409SSimon J. Gerraty * Push the current code address on the control-flow stack as a 347*0957b409SSimon J. Gerraty * destination, to be used by an ulterior backward jump. 348*0957b409SSimon J. Gerraty */ Begin()349*0957b409SSimon J. Gerraty internal void Begin() 350*0957b409SSimon J. Gerraty { 351*0957b409SSimon J. Gerraty CSPushDest(); 352*0957b409SSimon J. Gerraty } 353*0957b409SSimon J. Gerraty 354*0957b409SSimon J. Gerraty /* 355*0957b409SSimon J. Gerraty * Add a backward unconditional jump. The jump target is popped 356*0957b409SSimon J. Gerraty * from the control-flow stack as a destination. 357*0957b409SSimon J. Gerraty */ Again()358*0957b409SSimon J. Gerraty internal void Again() 359*0957b409SSimon J. Gerraty { 360*0957b409SSimon J. Gerraty int x = CSPopDest(); 361*0957b409SSimon J. Gerraty Add(new OpcodeJumpUncond(x - code.Count - 1)); 362*0957b409SSimon J. Gerraty } 363*0957b409SSimon J. Gerraty 364*0957b409SSimon J. Gerraty /* 365*0957b409SSimon J. Gerraty * Add a backward conditional jump, which will be taken at runtime 366*0957b409SSimon J. Gerraty * if the top-of-stack value is 'true'. The jump target is popped 367*0957b409SSimon J. Gerraty * from the control-flow stack as a destination. 368*0957b409SSimon J. Gerraty */ AgainIf()369*0957b409SSimon J. Gerraty internal void AgainIf() 370*0957b409SSimon J. Gerraty { 371*0957b409SSimon J. Gerraty int x = CSPopDest(); 372*0957b409SSimon J. Gerraty Add(new OpcodeJumpIf(x - code.Count - 1)); 373*0957b409SSimon J. Gerraty } 374*0957b409SSimon J. Gerraty 375*0957b409SSimon J. Gerraty /* 376*0957b409SSimon J. Gerraty * Add a backward conditional jump, which will be taken at runtime 377*0957b409SSimon J. Gerraty * if the top-of-stack value is 'false'. The jump target is popped 378*0957b409SSimon J. Gerraty * from the control-flow stack as a destination. 379*0957b409SSimon J. Gerraty */ AgainIfNot()380*0957b409SSimon J. Gerraty internal void AgainIfNot() 381*0957b409SSimon J. Gerraty { 382*0957b409SSimon J. Gerraty int x = CSPopDest(); 383*0957b409SSimon J. Gerraty Add(new OpcodeJumpIfNot(x - code.Count - 1)); 384*0957b409SSimon J. Gerraty } 385*0957b409SSimon J. Gerraty } 386