xref: /freebsd/contrib/bearssl/T0/WordBuilder.cs (revision 2aaf9152a852aba9eb2036b95f4948ee77988826)
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