xref: /freebsd/contrib/bearssl/T0/T0Comp.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 using System.IO;
28*0957b409SSimon J. Gerraty using System.Reflection;
29*0957b409SSimon J. Gerraty using System.Text;
30*0957b409SSimon J. Gerraty 
31*0957b409SSimon J. Gerraty /*
32*0957b409SSimon J. Gerraty  * This is the main compiler class.
33*0957b409SSimon J. Gerraty  */
34*0957b409SSimon J. Gerraty 
35*0957b409SSimon J. Gerraty public class T0Comp {
36*0957b409SSimon J. Gerraty 
37*0957b409SSimon J. Gerraty 	/*
38*0957b409SSimon J. Gerraty 	 * Command-line entry point.
39*0957b409SSimon J. Gerraty 	 */
Main(string[] args)40*0957b409SSimon J. Gerraty 	public static void Main(string[] args)
41*0957b409SSimon J. Gerraty 	{
42*0957b409SSimon J. Gerraty 		try {
43*0957b409SSimon J. Gerraty 			List<string> r = new List<string>();
44*0957b409SSimon J. Gerraty 			string outBase = null;
45*0957b409SSimon J. Gerraty 			List<string> entryPoints = new List<string>();
46*0957b409SSimon J. Gerraty 			string coreRun = null;
47*0957b409SSimon J. Gerraty 			bool flow = true;
48*0957b409SSimon J. Gerraty 			int dsLim = 32;
49*0957b409SSimon J. Gerraty 			int rsLim = 32;
50*0957b409SSimon J. Gerraty 			for (int i = 0; i < args.Length; i ++) {
51*0957b409SSimon J. Gerraty 				string a = args[i];
52*0957b409SSimon J. Gerraty 				if (!a.StartsWith("-")) {
53*0957b409SSimon J. Gerraty 					r.Add(a);
54*0957b409SSimon J. Gerraty 					continue;
55*0957b409SSimon J. Gerraty 				}
56*0957b409SSimon J. Gerraty 				if (a == "--") {
57*0957b409SSimon J. Gerraty 					for (;;) {
58*0957b409SSimon J. Gerraty 						if (++ i >= args.Length) {
59*0957b409SSimon J. Gerraty 							break;
60*0957b409SSimon J. Gerraty 						}
61*0957b409SSimon J. Gerraty 						r.Add(args[i]);
62*0957b409SSimon J. Gerraty 					}
63*0957b409SSimon J. Gerraty 					break;
64*0957b409SSimon J. Gerraty 				}
65*0957b409SSimon J. Gerraty 				while (a.StartsWith("-")) {
66*0957b409SSimon J. Gerraty 					a = a.Substring(1);
67*0957b409SSimon J. Gerraty 				}
68*0957b409SSimon J. Gerraty 				int j = a.IndexOf('=');
69*0957b409SSimon J. Gerraty 				string pname;
70*0957b409SSimon J. Gerraty 				string pval, pval2;
71*0957b409SSimon J. Gerraty 				if (j < 0) {
72*0957b409SSimon J. Gerraty 					pname = a.ToLowerInvariant();
73*0957b409SSimon J. Gerraty 					pval = null;
74*0957b409SSimon J. Gerraty 					pval2 = (i + 1) < args.Length
75*0957b409SSimon J. Gerraty 						? args[i + 1] : null;
76*0957b409SSimon J. Gerraty 				} else {
77*0957b409SSimon J. Gerraty 					pname = a.Substring(0, j).Trim()
78*0957b409SSimon J. Gerraty 						.ToLowerInvariant();
79*0957b409SSimon J. Gerraty 					pval = a.Substring(j + 1);
80*0957b409SSimon J. Gerraty 					pval2 = null;
81*0957b409SSimon J. Gerraty 				}
82*0957b409SSimon J. Gerraty 				switch (pname) {
83*0957b409SSimon J. Gerraty 				case "o":
84*0957b409SSimon J. Gerraty 				case "out":
85*0957b409SSimon J. Gerraty 					if (pval == null) {
86*0957b409SSimon J. Gerraty 						if (pval2 == null) {
87*0957b409SSimon J. Gerraty 							Usage();
88*0957b409SSimon J. Gerraty 						}
89*0957b409SSimon J. Gerraty 						i ++;
90*0957b409SSimon J. Gerraty 						pval = pval2;
91*0957b409SSimon J. Gerraty 					}
92*0957b409SSimon J. Gerraty 					if (outBase != null) {
93*0957b409SSimon J. Gerraty 						Usage();
94*0957b409SSimon J. Gerraty 					}
95*0957b409SSimon J. Gerraty 					outBase = pval;
96*0957b409SSimon J. Gerraty 					break;
97*0957b409SSimon J. Gerraty 				case "r":
98*0957b409SSimon J. Gerraty 				case "run":
99*0957b409SSimon J. Gerraty 					if (pval == null) {
100*0957b409SSimon J. Gerraty 						if (pval2 == null) {
101*0957b409SSimon J. Gerraty 							Usage();
102*0957b409SSimon J. Gerraty 						}
103*0957b409SSimon J. Gerraty 						i ++;
104*0957b409SSimon J. Gerraty 						pval = pval2;
105*0957b409SSimon J. Gerraty 					}
106*0957b409SSimon J. Gerraty 					coreRun = pval;
107*0957b409SSimon J. Gerraty 					break;
108*0957b409SSimon J. Gerraty 				case "m":
109*0957b409SSimon J. Gerraty 				case "main":
110*0957b409SSimon J. Gerraty 					if (pval == null) {
111*0957b409SSimon J. Gerraty 						if (pval2 == null) {
112*0957b409SSimon J. Gerraty 							Usage();
113*0957b409SSimon J. Gerraty 						}
114*0957b409SSimon J. Gerraty 						i ++;
115*0957b409SSimon J. Gerraty 						pval = pval2;
116*0957b409SSimon J. Gerraty 					}
117*0957b409SSimon J. Gerraty 					foreach (string ep in pval.Split(',')) {
118*0957b409SSimon J. Gerraty 						string epz = ep.Trim();
119*0957b409SSimon J. Gerraty 						if (epz.Length > 0) {
120*0957b409SSimon J. Gerraty 							entryPoints.Add(epz);
121*0957b409SSimon J. Gerraty 						}
122*0957b409SSimon J. Gerraty 					}
123*0957b409SSimon J. Gerraty 					break;
124*0957b409SSimon J. Gerraty 				case "nf":
125*0957b409SSimon J. Gerraty 				case "noflow":
126*0957b409SSimon J. Gerraty 					flow = false;
127*0957b409SSimon J. Gerraty 					break;
128*0957b409SSimon J. Gerraty 				default:
129*0957b409SSimon J. Gerraty 					Usage();
130*0957b409SSimon J. Gerraty 					break;
131*0957b409SSimon J. Gerraty 				}
132*0957b409SSimon J. Gerraty 			}
133*0957b409SSimon J. Gerraty 			if (r.Count == 0) {
134*0957b409SSimon J. Gerraty 				Usage();
135*0957b409SSimon J. Gerraty 			}
136*0957b409SSimon J. Gerraty 			if (outBase == null) {
137*0957b409SSimon J. Gerraty 				outBase = "t0out";
138*0957b409SSimon J. Gerraty 			}
139*0957b409SSimon J. Gerraty 			if (entryPoints.Count == 0) {
140*0957b409SSimon J. Gerraty 				entryPoints.Add("main");
141*0957b409SSimon J. Gerraty 			}
142*0957b409SSimon J. Gerraty 			if (coreRun == null) {
143*0957b409SSimon J. Gerraty 				coreRun = outBase;
144*0957b409SSimon J. Gerraty 			}
145*0957b409SSimon J. Gerraty 			T0Comp tc = new T0Comp();
146*0957b409SSimon J. Gerraty 			tc.enableFlowAnalysis = flow;
147*0957b409SSimon J. Gerraty 			tc.dsLimit = dsLim;
148*0957b409SSimon J. Gerraty 			tc.rsLimit = rsLim;
149*0957b409SSimon J. Gerraty 			using (TextReader tr = new StreamReader(
150*0957b409SSimon J. Gerraty 				Assembly.GetExecutingAssembly()
151*0957b409SSimon J. Gerraty 				.GetManifestResourceStream("t0-kernel")))
152*0957b409SSimon J. Gerraty 			{
153*0957b409SSimon J. Gerraty 				tc.ProcessInput(tr);
154*0957b409SSimon J. Gerraty 			}
155*0957b409SSimon J. Gerraty 			foreach (string a in r) {
156*0957b409SSimon J. Gerraty 				Console.WriteLine("[{0}]", a);
157*0957b409SSimon J. Gerraty 				using (TextReader tr = File.OpenText(a)) {
158*0957b409SSimon J. Gerraty 					tc.ProcessInput(tr);
159*0957b409SSimon J. Gerraty 				}
160*0957b409SSimon J. Gerraty 			}
161*0957b409SSimon J. Gerraty 			tc.Generate(outBase, coreRun, entryPoints.ToArray());
162*0957b409SSimon J. Gerraty 		} catch (Exception e) {
163*0957b409SSimon J. Gerraty 			Console.WriteLine(e.ToString());
164*0957b409SSimon J. Gerraty 			Environment.Exit(1);
165*0957b409SSimon J. Gerraty 		}
166*0957b409SSimon J. Gerraty 	}
167*0957b409SSimon J. Gerraty 
Usage()168*0957b409SSimon J. Gerraty 	static void Usage()
169*0957b409SSimon J. Gerraty 	{
170*0957b409SSimon J. Gerraty 		Console.WriteLine(
171*0957b409SSimon J. Gerraty "usage: T0Comp.exe [ options... ] file...");
172*0957b409SSimon J. Gerraty 		Console.WriteLine(
173*0957b409SSimon J. Gerraty "options:");
174*0957b409SSimon J. Gerraty 		Console.WriteLine(
175*0957b409SSimon J. Gerraty "   -o file    use 'file' as base for output file name (default: 't0out')");
176*0957b409SSimon J. Gerraty 		Console.WriteLine(
177*0957b409SSimon J. Gerraty "   -r name    use 'name' as base for run function (default: same as output)");
178*0957b409SSimon J. Gerraty 		Console.WriteLine(
179*0957b409SSimon J. Gerraty "   -m name[,name...]");
180*0957b409SSimon J. Gerraty 		Console.WriteLine(
181*0957b409SSimon J. Gerraty "              define entry point(s)");
182*0957b409SSimon J. Gerraty 		Console.WriteLine(
183*0957b409SSimon J. Gerraty "   -nf        disable flow analysis");
184*0957b409SSimon J. Gerraty 		Environment.Exit(1);
185*0957b409SSimon J. Gerraty 	}
186*0957b409SSimon J. Gerraty 
187*0957b409SSimon J. Gerraty 	/*
188*0957b409SSimon J. Gerraty 	 * If 'delayedChar' is Int32.MinValue then there is no delayed
189*0957b409SSimon J. Gerraty 	 * character.
190*0957b409SSimon J. Gerraty 	 * If 'delayedChar' equals x >= 0 then there is one delayed
191*0957b409SSimon J. Gerraty 	 * character of value x.
192*0957b409SSimon J. Gerraty 	 * If 'delayedChar' equals y < 0 then there are two delayed
193*0957b409SSimon J. Gerraty 	 * characters, a newline (U+000A) followed by character of
194*0957b409SSimon J. Gerraty 	 * value -(y+1).
195*0957b409SSimon J. Gerraty 	 */
196*0957b409SSimon J. Gerraty 	TextReader currentInput;
197*0957b409SSimon J. Gerraty 	int delayedChar;
198*0957b409SSimon J. Gerraty 
199*0957b409SSimon J. Gerraty 	/*
200*0957b409SSimon J. Gerraty 	 * Common StringBuilder used to parse tokens; it is reused for
201*0957b409SSimon J. Gerraty 	 * each new token.
202*0957b409SSimon J. Gerraty 	 */
203*0957b409SSimon J. Gerraty 	StringBuilder tokenBuilder;
204*0957b409SSimon J. Gerraty 
205*0957b409SSimon J. Gerraty 	/*
206*0957b409SSimon J. Gerraty 	 * There may be a delayed token in some cases.
207*0957b409SSimon J. Gerraty 	 */
208*0957b409SSimon J. Gerraty 	String delayedToken;
209*0957b409SSimon J. Gerraty 
210*0957b409SSimon J. Gerraty 	/*
211*0957b409SSimon J. Gerraty 	 * Defined words are referenced by name in this map. Names are
212*0957b409SSimon J. Gerraty 	 * string-sensitive; for better reproducibility, the map is sorted
213*0957b409SSimon J. Gerraty 	 * (ordinal order).
214*0957b409SSimon J. Gerraty 	 */
215*0957b409SSimon J. Gerraty 	IDictionary<string, Word> words;
216*0957b409SSimon J. Gerraty 
217*0957b409SSimon J. Gerraty 	/*
218*0957b409SSimon J. Gerraty 	 * Last defined word is also referenced in 'lastWord'. This is
219*0957b409SSimon J. Gerraty 	 * used by 'immediate'.
220*0957b409SSimon J. Gerraty 	 */
221*0957b409SSimon J. Gerraty 	Word lastWord;
222*0957b409SSimon J. Gerraty 
223*0957b409SSimon J. Gerraty 	/*
224*0957b409SSimon J. Gerraty 	 * When compiling, this builder is used. A stack saves other
225*0957b409SSimon J. Gerraty 	 * builders in case of nested definition.
226*0957b409SSimon J. Gerraty 	 */
227*0957b409SSimon J. Gerraty 	WordBuilder wordBuilder;
228*0957b409SSimon J. Gerraty 	Stack<WordBuilder> savedWordBuilders;
229*0957b409SSimon J. Gerraty 
230*0957b409SSimon J. Gerraty 	/*
231*0957b409SSimon J. Gerraty 	 * C code defined for words is kept in this map, by word name.
232*0957b409SSimon J. Gerraty 	 */
233*0957b409SSimon J. Gerraty 	IDictionary<string, string> allCCode;
234*0957b409SSimon J. Gerraty 
235*0957b409SSimon J. Gerraty 	/*
236*0957b409SSimon J. Gerraty 	 * 'compiling' is true when compiling tokens to a word, false
237*0957b409SSimon J. Gerraty 	 * when interpreting them.
238*0957b409SSimon J. Gerraty 	 */
239*0957b409SSimon J. Gerraty 	bool compiling;
240*0957b409SSimon J. Gerraty 
241*0957b409SSimon J. Gerraty 	/*
242*0957b409SSimon J. Gerraty 	 * 'quitRunLoop' is set to true to trigger exit of the
243*0957b409SSimon J. Gerraty 	 * interpretation loop when the end of the current input file
244*0957b409SSimon J. Gerraty 	 * is reached.
245*0957b409SSimon J. Gerraty 	 */
246*0957b409SSimon J. Gerraty 	bool quitRunLoop;
247*0957b409SSimon J. Gerraty 
248*0957b409SSimon J. Gerraty 	/*
249*0957b409SSimon J. Gerraty 	 * 'extraCode' is for C code that is to be added as preamble to
250*0957b409SSimon J. Gerraty 	 * the C output.
251*0957b409SSimon J. Gerraty 	 */
252*0957b409SSimon J. Gerraty 	List<string> extraCode;
253*0957b409SSimon J. Gerraty 
254*0957b409SSimon J. Gerraty 	/*
255*0957b409SSimon J. Gerraty 	 * 'extraCodeDefer' is for C code that is to be added in the C
256*0957b409SSimon J. Gerraty 	 * output _after_ the data and code blocks.
257*0957b409SSimon J. Gerraty 	 */
258*0957b409SSimon J. Gerraty 	List<string> extraCodeDefer;
259*0957b409SSimon J. Gerraty 
260*0957b409SSimon J. Gerraty 	/*
261*0957b409SSimon J. Gerraty 	 * 'dataBlock' is the data block in which constant data bytes
262*0957b409SSimon J. Gerraty 	 * are accumulated.
263*0957b409SSimon J. Gerraty 	 */
264*0957b409SSimon J. Gerraty 	ConstData dataBlock;
265*0957b409SSimon J. Gerraty 
266*0957b409SSimon J. Gerraty 	/*
267*0957b409SSimon J. Gerraty 	 * Counter for blocks of constant data.
268*0957b409SSimon J. Gerraty 	 */
269*0957b409SSimon J. Gerraty 	long currentBlobID;
270*0957b409SSimon J. Gerraty 
271*0957b409SSimon J. Gerraty 	/*
272*0957b409SSimon J. Gerraty 	 * Flow analysis enable flag.
273*0957b409SSimon J. Gerraty 	 */
274*0957b409SSimon J. Gerraty 	bool enableFlowAnalysis;
275*0957b409SSimon J. Gerraty 
276*0957b409SSimon J. Gerraty 	/*
277*0957b409SSimon J. Gerraty 	 * Data stack size limit.
278*0957b409SSimon J. Gerraty 	 */
279*0957b409SSimon J. Gerraty 	int dsLimit;
280*0957b409SSimon J. Gerraty 
281*0957b409SSimon J. Gerraty 	/*
282*0957b409SSimon J. Gerraty 	 * Return stack size limit.
283*0957b409SSimon J. Gerraty 	 */
284*0957b409SSimon J. Gerraty 	int rsLimit;
285*0957b409SSimon J. Gerraty 
T0Comp()286*0957b409SSimon J. Gerraty 	T0Comp()
287*0957b409SSimon J. Gerraty 	{
288*0957b409SSimon J. Gerraty 		tokenBuilder = new StringBuilder();
289*0957b409SSimon J. Gerraty 		words = new SortedDictionary<string, Word>(
290*0957b409SSimon J. Gerraty 			StringComparer.Ordinal);
291*0957b409SSimon J. Gerraty 		savedWordBuilders = new Stack<WordBuilder>();
292*0957b409SSimon J. Gerraty 		allCCode = new SortedDictionary<string, string>(
293*0957b409SSimon J. Gerraty 			StringComparer.Ordinal);
294*0957b409SSimon J. Gerraty 		compiling = false;
295*0957b409SSimon J. Gerraty 		extraCode = new List<string>();
296*0957b409SSimon J. Gerraty 		extraCodeDefer = new List<string>();
297*0957b409SSimon J. Gerraty 		enableFlowAnalysis = true;
298*0957b409SSimon J. Gerraty 
299*0957b409SSimon J. Gerraty 		/*
300*0957b409SSimon J. Gerraty 		 * Native words are predefined and implemented only with
301*0957b409SSimon J. Gerraty 		 * native code. Some may be part of the generated output,
302*0957b409SSimon J. Gerraty 		 * if C code is set for them.
303*0957b409SSimon J. Gerraty 		 */
304*0957b409SSimon J. Gerraty 
305*0957b409SSimon J. Gerraty 		/*
306*0957b409SSimon J. Gerraty 		 * add-cc:
307*0957b409SSimon J. Gerraty 		 * Parses next token as a word name, then a C code snippet.
308*0957b409SSimon J. Gerraty 		 * Sets the C code for that word.
309*0957b409SSimon J. Gerraty 		 */
310*0957b409SSimon J. Gerraty 		AddNative("add-cc:", false, SType.BLANK, cpu => {
311*0957b409SSimon J. Gerraty 			string tt = Next();
312*0957b409SSimon J. Gerraty 			if (tt == null) {
313*0957b409SSimon J. Gerraty 				throw new Exception(
314*0957b409SSimon J. Gerraty 					"EOF reached (missing name)");
315*0957b409SSimon J. Gerraty 			}
316*0957b409SSimon J. Gerraty 			if (allCCode.ContainsKey(tt)) {
317*0957b409SSimon J. Gerraty 				throw new Exception(
318*0957b409SSimon J. Gerraty 					"C code already set for: " + tt);
319*0957b409SSimon J. Gerraty 			}
320*0957b409SSimon J. Gerraty 			allCCode[tt] = ParseCCode();
321*0957b409SSimon J. Gerraty 		});
322*0957b409SSimon J. Gerraty 
323*0957b409SSimon J. Gerraty 		/*
324*0957b409SSimon J. Gerraty 		 * cc:
325*0957b409SSimon J. Gerraty 		 * Parses next token as a word name, then a C code snippet.
326*0957b409SSimon J. Gerraty 		 * A new word is defined, that throws an exception when
327*0957b409SSimon J. Gerraty 		 * invoked during compilation. The C code is set for that
328*0957b409SSimon J. Gerraty 		 * new word.
329*0957b409SSimon J. Gerraty 		 */
330*0957b409SSimon J. Gerraty 		AddNative("cc:", false, SType.BLANK, cpu => {
331*0957b409SSimon J. Gerraty 			string tt = Next();
332*0957b409SSimon J. Gerraty 			if (tt == null) {
333*0957b409SSimon J. Gerraty 				throw new Exception(
334*0957b409SSimon J. Gerraty 					"EOF reached (missing name)");
335*0957b409SSimon J. Gerraty 			}
336*0957b409SSimon J. Gerraty 			Word w = AddNative(tt, false, cpu2 => {
337*0957b409SSimon J. Gerraty 				throw new Exception(
338*0957b409SSimon J. Gerraty 					"C-only word: " + tt);
339*0957b409SSimon J. Gerraty 			});
340*0957b409SSimon J. Gerraty 			if (allCCode.ContainsKey(tt)) {
341*0957b409SSimon J. Gerraty 				throw new Exception(
342*0957b409SSimon J. Gerraty 					"C code already set for: " + tt);
343*0957b409SSimon J. Gerraty 			}
344*0957b409SSimon J. Gerraty 			SType stackEffect;
345*0957b409SSimon J. Gerraty 			allCCode[tt] = ParseCCode(out stackEffect);
346*0957b409SSimon J. Gerraty 			w.StackEffect = stackEffect;
347*0957b409SSimon J. Gerraty 		});
348*0957b409SSimon J. Gerraty 
349*0957b409SSimon J. Gerraty 		/*
350*0957b409SSimon J. Gerraty 		 * preamble
351*0957b409SSimon J. Gerraty 		 * Parses a C code snippet, then adds it to the generated
352*0957b409SSimon J. Gerraty 		 * output preamble.
353*0957b409SSimon J. Gerraty 		 */
354*0957b409SSimon J. Gerraty 		AddNative("preamble", false, SType.BLANK, cpu => {
355*0957b409SSimon J. Gerraty 			extraCode.Add(ParseCCode());
356*0957b409SSimon J. Gerraty 		});
357*0957b409SSimon J. Gerraty 
358*0957b409SSimon J. Gerraty 		/*
359*0957b409SSimon J. Gerraty 		 * postamble
360*0957b409SSimon J. Gerraty 		 * Parses a C code snippet, then adds it to the generated
361*0957b409SSimon J. Gerraty 		 * output after the data and code blocks.
362*0957b409SSimon J. Gerraty 		 */
363*0957b409SSimon J. Gerraty 		AddNative("postamble", false, SType.BLANK, cpu => {
364*0957b409SSimon J. Gerraty 			extraCodeDefer.Add(ParseCCode());
365*0957b409SSimon J. Gerraty 		});
366*0957b409SSimon J. Gerraty 
367*0957b409SSimon J. Gerraty 		/*
368*0957b409SSimon J. Gerraty 		 * make-CX
369*0957b409SSimon J. Gerraty 		 * Expects two integers and a string, and makes a
370*0957b409SSimon J. Gerraty 		 * constant that stands for the string as a C constant
371*0957b409SSimon J. Gerraty 		 * expression. The two integers are the expected range
372*0957b409SSimon J. Gerraty 		 * (min-max, inclusive).
373*0957b409SSimon J. Gerraty 		 */
374*0957b409SSimon J. Gerraty 		AddNative("make-CX", false, new SType(3, 1), cpu => {
375*0957b409SSimon J. Gerraty 			TValue c = cpu.Pop();
376*0957b409SSimon J. Gerraty 			if (!(c.ptr is TPointerBlob)) {
377*0957b409SSimon J. Gerraty 				throw new Exception(string.Format(
378*0957b409SSimon J. Gerraty 					"'{0}' is not a string", c));
379*0957b409SSimon J. Gerraty 			}
380*0957b409SSimon J. Gerraty 			int max = cpu.Pop();
381*0957b409SSimon J. Gerraty 			int min = cpu.Pop();
382*0957b409SSimon J. Gerraty 			TValue tv = new TValue(0, new TPointerExpr(
383*0957b409SSimon J. Gerraty 				c.ToString(), min, max));
384*0957b409SSimon J. Gerraty 			cpu.Push(tv);
385*0957b409SSimon J. Gerraty 		});
386*0957b409SSimon J. Gerraty 
387*0957b409SSimon J. Gerraty 		/*
388*0957b409SSimon J. Gerraty 		 * CX  (immediate)
389*0957b409SSimon J. Gerraty 		 * Parses two integer constants, then a C code snippet.
390*0957b409SSimon J. Gerraty 		 * It then pushes on the stack, or compiles to the
391*0957b409SSimon J. Gerraty 		 * current word, a value consisting of the given C
392*0957b409SSimon J. Gerraty 		 * expression; the two integers indicate the expected
393*0957b409SSimon J. Gerraty 		 * range (min-max, inclusive) of the C expression when
394*0957b409SSimon J. Gerraty 		 * evaluated.
395*0957b409SSimon J. Gerraty 		 */
396*0957b409SSimon J. Gerraty 		AddNative("CX", true, cpu => {
397*0957b409SSimon J. Gerraty 			string tt = Next();
398*0957b409SSimon J. Gerraty 			if (tt == null) {
399*0957b409SSimon J. Gerraty 				throw new Exception(
400*0957b409SSimon J. Gerraty 					"EOF reached (missing min value)");
401*0957b409SSimon J. Gerraty 			}
402*0957b409SSimon J. Gerraty 			int min = ParseInteger(tt);
403*0957b409SSimon J. Gerraty 			tt = Next();
404*0957b409SSimon J. Gerraty 			if (tt == null) {
405*0957b409SSimon J. Gerraty 				throw new Exception(
406*0957b409SSimon J. Gerraty 					"EOF reached (missing max value)");
407*0957b409SSimon J. Gerraty 			}
408*0957b409SSimon J. Gerraty 			int max = ParseInteger(tt);
409*0957b409SSimon J. Gerraty 			if (max < min) {
410*0957b409SSimon J. Gerraty 				throw new Exception("min/max in wrong order");
411*0957b409SSimon J. Gerraty 			}
412*0957b409SSimon J. Gerraty 			TValue tv = new TValue(0, new TPointerExpr(
413*0957b409SSimon J. Gerraty 				ParseCCode().Trim(), min, max));
414*0957b409SSimon J. Gerraty 			if (compiling) {
415*0957b409SSimon J. Gerraty 				wordBuilder.Literal(tv);
416*0957b409SSimon J. Gerraty 			} else {
417*0957b409SSimon J. Gerraty 				cpu.Push(tv);
418*0957b409SSimon J. Gerraty 			}
419*0957b409SSimon J. Gerraty 		});
420*0957b409SSimon J. Gerraty 
421*0957b409SSimon J. Gerraty 		/*
422*0957b409SSimon J. Gerraty 		 * co
423*0957b409SSimon J. Gerraty 		 * Interrupt the current execution. This implements
424*0957b409SSimon J. Gerraty 		 * coroutines. It cannot be invoked during compilation.
425*0957b409SSimon J. Gerraty 		 */
426*0957b409SSimon J. Gerraty 		AddNative("co", false, SType.BLANK, cpu => {
427*0957b409SSimon J. Gerraty 			throw new Exception("No coroutine in compile mode");
428*0957b409SSimon J. Gerraty 		});
429*0957b409SSimon J. Gerraty 
430*0957b409SSimon J. Gerraty 		/*
431*0957b409SSimon J. Gerraty 		 * :
432*0957b409SSimon J. Gerraty 		 * Parses next token as word name. It begins definition
433*0957b409SSimon J. Gerraty 		 * of that word, setting it as current target for
434*0957b409SSimon J. Gerraty 		 * word building. Any previously opened word is saved
435*0957b409SSimon J. Gerraty 		 * and will become available again as a target when that
436*0957b409SSimon J. Gerraty 		 * new word is finished building.
437*0957b409SSimon J. Gerraty 		 */
438*0957b409SSimon J. Gerraty 		AddNative(":", false, cpu => {
439*0957b409SSimon J. Gerraty 			string tt = Next();
440*0957b409SSimon J. Gerraty 			if (tt == null) {
441*0957b409SSimon J. Gerraty 				throw new Exception(
442*0957b409SSimon J. Gerraty 					"EOF reached (missing name)");
443*0957b409SSimon J. Gerraty 			}
444*0957b409SSimon J. Gerraty 			if (compiling) {
445*0957b409SSimon J. Gerraty 				savedWordBuilders.Push(wordBuilder);
446*0957b409SSimon J. Gerraty 			} else {
447*0957b409SSimon J. Gerraty 				compiling = true;
448*0957b409SSimon J. Gerraty 			}
449*0957b409SSimon J. Gerraty 			wordBuilder = new WordBuilder(this, tt);
450*0957b409SSimon J. Gerraty 			tt = Next();
451*0957b409SSimon J. Gerraty 			if (tt == null) {
452*0957b409SSimon J. Gerraty 				throw new Exception(
453*0957b409SSimon J. Gerraty 					"EOF reached (while compiling)");
454*0957b409SSimon J. Gerraty 			}
455*0957b409SSimon J. Gerraty 			if (tt == "(") {
456*0957b409SSimon J. Gerraty 				SType stackEffect = ParseStackEffectNF();
457*0957b409SSimon J. Gerraty 				if (!stackEffect.IsKnown) {
458*0957b409SSimon J. Gerraty 					throw new Exception(
459*0957b409SSimon J. Gerraty 						"Invalid stack effect syntax");
460*0957b409SSimon J. Gerraty 				}
461*0957b409SSimon J. Gerraty 				wordBuilder.StackEffect = stackEffect;
462*0957b409SSimon J. Gerraty 			} else {
463*0957b409SSimon J. Gerraty 				delayedToken = tt;
464*0957b409SSimon J. Gerraty 			}
465*0957b409SSimon J. Gerraty 		});
466*0957b409SSimon J. Gerraty 
467*0957b409SSimon J. Gerraty 		/*
468*0957b409SSimon J. Gerraty 		 * Pops a string as word name, and two integers as stack
469*0957b409SSimon J. Gerraty 		 * effect. It begins definition of that word, setting it
470*0957b409SSimon J. Gerraty 		 * as current target for word building. Any previously
471*0957b409SSimon J. Gerraty 		 * opened word is saved and will become available again as
472*0957b409SSimon J. Gerraty 		 * a target when that new word is finished building.
473*0957b409SSimon J. Gerraty 		 *
474*0957b409SSimon J. Gerraty 		 * Stack effect is the pair 'din dout'. If din is negative,
475*0957b409SSimon J. Gerraty 		 * then the stack effect is "unknown". If din is nonnegative
476*0957b409SSimon J. Gerraty 		 * but dout is negative, then the word is reputed never to
477*0957b409SSimon J. Gerraty 		 * return.
478*0957b409SSimon J. Gerraty 		 */
479*0957b409SSimon J. Gerraty 		AddNative("define-word", false, cpu => {
480*0957b409SSimon J. Gerraty 			int dout = cpu.Pop();
481*0957b409SSimon J. Gerraty 			int din = cpu.Pop();
482*0957b409SSimon J. Gerraty 			TValue s = cpu.Pop();
483*0957b409SSimon J. Gerraty 			if (!(s.ptr is TPointerBlob)) {
484*0957b409SSimon J. Gerraty 				throw new Exception(string.Format(
485*0957b409SSimon J. Gerraty 					"Not a string: '{0}'", s));
486*0957b409SSimon J. Gerraty 			}
487*0957b409SSimon J. Gerraty 			string tt = s.ToString();
488*0957b409SSimon J. Gerraty 			if (compiling) {
489*0957b409SSimon J. Gerraty 				savedWordBuilders.Push(wordBuilder);
490*0957b409SSimon J. Gerraty 			} else {
491*0957b409SSimon J. Gerraty 				compiling = true;
492*0957b409SSimon J. Gerraty 			}
493*0957b409SSimon J. Gerraty 			wordBuilder = new WordBuilder(this, tt);
494*0957b409SSimon J. Gerraty 			wordBuilder.StackEffect = new SType(din, dout);
495*0957b409SSimon J. Gerraty 		});
496*0957b409SSimon J. Gerraty 
497*0957b409SSimon J. Gerraty 		/*
498*0957b409SSimon J. Gerraty 		 * ;  (immediate)
499*0957b409SSimon J. Gerraty 		 * Ends current word. The current word is registered under
500*0957b409SSimon J. Gerraty 		 * its name, and the previously opened word (if any) becomes
501*0957b409SSimon J. Gerraty 		 * again the building target.
502*0957b409SSimon J. Gerraty 		 */
503*0957b409SSimon J. Gerraty 		AddNative(";", true, cpu => {
504*0957b409SSimon J. Gerraty 			if (!compiling) {
505*0957b409SSimon J. Gerraty 				throw new Exception("Not compiling");
506*0957b409SSimon J. Gerraty 			}
507*0957b409SSimon J. Gerraty 			Word w = wordBuilder.Build();
508*0957b409SSimon J. Gerraty 			string name = w.Name;
509*0957b409SSimon J. Gerraty 			if (words.ContainsKey(name)) {
510*0957b409SSimon J. Gerraty 				throw new Exception(
511*0957b409SSimon J. Gerraty 					"Word already defined: " + name);
512*0957b409SSimon J. Gerraty 			}
513*0957b409SSimon J. Gerraty 			words[name] = w;
514*0957b409SSimon J. Gerraty 			lastWord = w;
515*0957b409SSimon J. Gerraty 			if (savedWordBuilders.Count > 0) {
516*0957b409SSimon J. Gerraty 				wordBuilder = savedWordBuilders.Pop();
517*0957b409SSimon J. Gerraty 			} else {
518*0957b409SSimon J. Gerraty 				wordBuilder = null;
519*0957b409SSimon J. Gerraty 				compiling = false;
520*0957b409SSimon J. Gerraty 			}
521*0957b409SSimon J. Gerraty 		});
522*0957b409SSimon J. Gerraty 
523*0957b409SSimon J. Gerraty 		/*
524*0957b409SSimon J. Gerraty 		 * immediate
525*0957b409SSimon J. Gerraty 		 * Sets the last defined word as immediate.
526*0957b409SSimon J. Gerraty 		 */
527*0957b409SSimon J. Gerraty 		AddNative("immediate", false, cpu => {
528*0957b409SSimon J. Gerraty 			if (lastWord == null) {
529*0957b409SSimon J. Gerraty 				throw new Exception("No word defined yet");
530*0957b409SSimon J. Gerraty 			}
531*0957b409SSimon J. Gerraty 			lastWord.Immediate = true;
532*0957b409SSimon J. Gerraty 		});
533*0957b409SSimon J. Gerraty 
534*0957b409SSimon J. Gerraty 		/*
535*0957b409SSimon J. Gerraty 		 * literal  (immediate)
536*0957b409SSimon J. Gerraty 		 * Pops the current TOS value, and add in the current word
537*0957b409SSimon J. Gerraty 		 * the action of pushing that value. This cannot be used
538*0957b409SSimon J. Gerraty 		 * when no word is being built.
539*0957b409SSimon J. Gerraty 		 */
540*0957b409SSimon J. Gerraty 		WordNative wliteral = AddNative("literal", true, cpu => {
541*0957b409SSimon J. Gerraty 			CheckCompiling();
542*0957b409SSimon J. Gerraty 			wordBuilder.Literal(cpu.Pop());
543*0957b409SSimon J. Gerraty 		});
544*0957b409SSimon J. Gerraty 
545*0957b409SSimon J. Gerraty 		/*
546*0957b409SSimon J. Gerraty 		 * compile
547*0957b409SSimon J. Gerraty 		 * Pops the current TOS value, which must be an XT (pointer
548*0957b409SSimon J. Gerraty 		 * to a word); the action of calling that word is compiled
549*0957b409SSimon J. Gerraty 		 * in the current word.
550*0957b409SSimon J. Gerraty 		 */
551*0957b409SSimon J. Gerraty 		WordNative wcompile = AddNative("compile", false, cpu => {
552*0957b409SSimon J. Gerraty 			CheckCompiling();
553*0957b409SSimon J. Gerraty 			wordBuilder.Call(cpu.Pop().ToXT());
554*0957b409SSimon J. Gerraty 		});
555*0957b409SSimon J. Gerraty 
556*0957b409SSimon J. Gerraty 		/*
557*0957b409SSimon J. Gerraty 		 * postpone  (immediate)
558*0957b409SSimon J. Gerraty 		 * Parses the next token as a word name, and add to the
559*0957b409SSimon J. Gerraty 		 * current word the action of calling that word. This
560*0957b409SSimon J. Gerraty 		 * basically removes immediatety from the next word.
561*0957b409SSimon J. Gerraty 		 */
562*0957b409SSimon J. Gerraty 		AddNative("postpone", true, cpu => {
563*0957b409SSimon J. Gerraty 			CheckCompiling();
564*0957b409SSimon J. Gerraty 			string tt = Next();
565*0957b409SSimon J. Gerraty 			if (tt == null) {
566*0957b409SSimon J. Gerraty 				throw new Exception(
567*0957b409SSimon J. Gerraty 					"EOF reached (missing name)");
568*0957b409SSimon J. Gerraty 			}
569*0957b409SSimon J. Gerraty 			TValue v;
570*0957b409SSimon J. Gerraty 			bool isVal = TryParseLiteral(tt, out v);
571*0957b409SSimon J. Gerraty 			Word w = LookupNF(tt);
572*0957b409SSimon J. Gerraty 			if (isVal && w != null) {
573*0957b409SSimon J. Gerraty 				throw new Exception(String.Format(
574*0957b409SSimon J. Gerraty 					"Ambiguous: both defined word and"
575*0957b409SSimon J. Gerraty 					+ " literal: {0}", tt));
576*0957b409SSimon J. Gerraty 			}
577*0957b409SSimon J. Gerraty 			if (isVal) {
578*0957b409SSimon J. Gerraty 				wordBuilder.Literal(v);
579*0957b409SSimon J. Gerraty 				wordBuilder.CallExt(wliteral);
580*0957b409SSimon J. Gerraty 			} else if (w != null) {
581*0957b409SSimon J. Gerraty 				if (w.Immediate) {
582*0957b409SSimon J. Gerraty 					wordBuilder.CallExt(w);
583*0957b409SSimon J. Gerraty 				} else {
584*0957b409SSimon J. Gerraty 					wordBuilder.Literal(new TValue(0,
585*0957b409SSimon J. Gerraty 						new TPointerXT(w)));
586*0957b409SSimon J. Gerraty 					wordBuilder.CallExt(wcompile);
587*0957b409SSimon J. Gerraty 				}
588*0957b409SSimon J. Gerraty 			} else {
589*0957b409SSimon J. Gerraty 				wordBuilder.Literal(new TValue(0,
590*0957b409SSimon J. Gerraty 					new TPointerXT(tt)));
591*0957b409SSimon J. Gerraty 				wordBuilder.CallExt(wcompile);
592*0957b409SSimon J. Gerraty 			}
593*0957b409SSimon J. Gerraty 		});
594*0957b409SSimon J. Gerraty 
595*0957b409SSimon J. Gerraty 		/*
596*0957b409SSimon J. Gerraty 		 * Interrupt compilation with an error.
597*0957b409SSimon J. Gerraty 		 */
598*0957b409SSimon J. Gerraty 		AddNative("exitvm", false, cpu => {
599*0957b409SSimon J. Gerraty 			throw new Exception();
600*0957b409SSimon J. Gerraty 		});
601*0957b409SSimon J. Gerraty 
602*0957b409SSimon J. Gerraty 		/*
603*0957b409SSimon J. Gerraty 		 * Open a new data block. Its symbolic address is pushed
604*0957b409SSimon J. Gerraty 		 * on the stack.
605*0957b409SSimon J. Gerraty 		 */
606*0957b409SSimon J. Gerraty 		AddNative("new-data-block", false, cpu => {
607*0957b409SSimon J. Gerraty 			dataBlock = new ConstData(this);
608*0957b409SSimon J. Gerraty 			cpu.Push(new TValue(0, new TPointerBlob(dataBlock)));
609*0957b409SSimon J. Gerraty 		});
610*0957b409SSimon J. Gerraty 
611*0957b409SSimon J. Gerraty 		/*
612*0957b409SSimon J. Gerraty 		 * Define a new data word. The data address and name are
613*0957b409SSimon J. Gerraty 		 * popped from the stack.
614*0957b409SSimon J. Gerraty 		 */
615*0957b409SSimon J. Gerraty 		AddNative("define-data-word", false, cpu => {
616*0957b409SSimon J. Gerraty 			string name = cpu.Pop().ToString();
617*0957b409SSimon J. Gerraty 			TValue va = cpu.Pop();
618*0957b409SSimon J. Gerraty 			TPointerBlob tb = va.ptr as TPointerBlob;
619*0957b409SSimon J. Gerraty 			if (tb == null) {
620*0957b409SSimon J. Gerraty 				throw new Exception(
621*0957b409SSimon J. Gerraty 					"Address is not a data area");
622*0957b409SSimon J. Gerraty 			}
623*0957b409SSimon J. Gerraty 			Word w = new WordData(this, name, tb.Blob, va.x);
624*0957b409SSimon J. Gerraty 			if (words.ContainsKey(name)) {
625*0957b409SSimon J. Gerraty 				throw new Exception(
626*0957b409SSimon J. Gerraty 					"Word already defined: " + name);
627*0957b409SSimon J. Gerraty 			}
628*0957b409SSimon J. Gerraty 			words[name] = w;
629*0957b409SSimon J. Gerraty 			lastWord = w;
630*0957b409SSimon J. Gerraty 		});
631*0957b409SSimon J. Gerraty 
632*0957b409SSimon J. Gerraty 		/*
633*0957b409SSimon J. Gerraty 		 * Get an address pointing at the end of the current
634*0957b409SSimon J. Gerraty 		 * data block. This is the address of the next byte that
635*0957b409SSimon J. Gerraty 		 * will be added.
636*0957b409SSimon J. Gerraty 		 */
637*0957b409SSimon J. Gerraty 		AddNative("current-data", false, cpu => {
638*0957b409SSimon J. Gerraty 			if (dataBlock == null) {
639*0957b409SSimon J. Gerraty 				throw new Exception(
640*0957b409SSimon J. Gerraty 					"No current data block");
641*0957b409SSimon J. Gerraty 			}
642*0957b409SSimon J. Gerraty 			cpu.Push(new TValue(dataBlock.Length,
643*0957b409SSimon J. Gerraty 				new TPointerBlob(dataBlock)));
644*0957b409SSimon J. Gerraty 		});
645*0957b409SSimon J. Gerraty 
646*0957b409SSimon J. Gerraty 		/*
647*0957b409SSimon J. Gerraty 		 * Add a byte value to the data block.
648*0957b409SSimon J. Gerraty 		 */
649*0957b409SSimon J. Gerraty 		AddNative("data-add8", false, cpu => {
650*0957b409SSimon J. Gerraty 			if (dataBlock == null) {
651*0957b409SSimon J. Gerraty 				throw new Exception(
652*0957b409SSimon J. Gerraty 					"No current data block");
653*0957b409SSimon J. Gerraty 			}
654*0957b409SSimon J. Gerraty 			int v = cpu.Pop();
655*0957b409SSimon J. Gerraty 			if (v < 0 || v > 0xFF) {
656*0957b409SSimon J. Gerraty 				throw new Exception(
657*0957b409SSimon J. Gerraty 					"Byte value out of range: " + v);
658*0957b409SSimon J. Gerraty 			}
659*0957b409SSimon J. Gerraty 			dataBlock.Add8((byte)v);
660*0957b409SSimon J. Gerraty 		});
661*0957b409SSimon J. Gerraty 
662*0957b409SSimon J. Gerraty 		/*
663*0957b409SSimon J. Gerraty 		 * Set a byte value in the data block.
664*0957b409SSimon J. Gerraty 		 */
665*0957b409SSimon J. Gerraty 		AddNative("data-set8", false, cpu => {
666*0957b409SSimon J. Gerraty 			TValue va = cpu.Pop();
667*0957b409SSimon J. Gerraty 			TPointerBlob tb = va.ptr as TPointerBlob;
668*0957b409SSimon J. Gerraty 			if (tb == null) {
669*0957b409SSimon J. Gerraty 				throw new Exception(
670*0957b409SSimon J. Gerraty 					"Address is not a data area");
671*0957b409SSimon J. Gerraty 			}
672*0957b409SSimon J. Gerraty 			int v = cpu.Pop();
673*0957b409SSimon J. Gerraty 			if (v < 0 || v > 0xFF) {
674*0957b409SSimon J. Gerraty 				throw new Exception(
675*0957b409SSimon J. Gerraty 					"Byte value out of range: " + v);
676*0957b409SSimon J. Gerraty 			}
677*0957b409SSimon J. Gerraty 			tb.Blob.Set8(va.x, (byte)v);
678*0957b409SSimon J. Gerraty 		});
679*0957b409SSimon J. Gerraty 
680*0957b409SSimon J. Gerraty 		/*
681*0957b409SSimon J. Gerraty 		 * Get a byte value from a data block.
682*0957b409SSimon J. Gerraty 		 */
683*0957b409SSimon J. Gerraty 		AddNative("data-get8", false, new SType(1, 1), cpu => {
684*0957b409SSimon J. Gerraty 			TValue va = cpu.Pop();
685*0957b409SSimon J. Gerraty 			TPointerBlob tb = va.ptr as TPointerBlob;
686*0957b409SSimon J. Gerraty 			if (tb == null) {
687*0957b409SSimon J. Gerraty 				throw new Exception(
688*0957b409SSimon J. Gerraty 					"Address is not a data area");
689*0957b409SSimon J. Gerraty 			}
690*0957b409SSimon J. Gerraty 			int v = tb.Blob.Read8(va.x);
691*0957b409SSimon J. Gerraty 			cpu.Push(v);
692*0957b409SSimon J. Gerraty 		});
693*0957b409SSimon J. Gerraty 
694*0957b409SSimon J. Gerraty 		/*
695*0957b409SSimon J. Gerraty 		 *
696*0957b409SSimon J. Gerraty 		 */
697*0957b409SSimon J. Gerraty 		AddNative("compile-local-read", false, cpu => {
698*0957b409SSimon J. Gerraty 			CheckCompiling();
699*0957b409SSimon J. Gerraty 			wordBuilder.GetLocal(cpu.Pop().ToString());
700*0957b409SSimon J. Gerraty 		});
701*0957b409SSimon J. Gerraty 		AddNative("compile-local-write", false, cpu => {
702*0957b409SSimon J. Gerraty 			CheckCompiling();
703*0957b409SSimon J. Gerraty 			wordBuilder.PutLocal(cpu.Pop().ToString());
704*0957b409SSimon J. Gerraty 		});
705*0957b409SSimon J. Gerraty 
706*0957b409SSimon J. Gerraty 		AddNative("ahead", true, cpu => {
707*0957b409SSimon J. Gerraty 			CheckCompiling();
708*0957b409SSimon J. Gerraty 			wordBuilder.Ahead();
709*0957b409SSimon J. Gerraty 		});
710*0957b409SSimon J. Gerraty 		AddNative("begin", true, cpu => {
711*0957b409SSimon J. Gerraty 			CheckCompiling();
712*0957b409SSimon J. Gerraty 			wordBuilder.Begin();
713*0957b409SSimon J. Gerraty 		});
714*0957b409SSimon J. Gerraty 		AddNative("again", true, cpu => {
715*0957b409SSimon J. Gerraty 			CheckCompiling();
716*0957b409SSimon J. Gerraty 			wordBuilder.Again();
717*0957b409SSimon J. Gerraty 		});
718*0957b409SSimon J. Gerraty 		AddNative("until", true, cpu => {
719*0957b409SSimon J. Gerraty 			CheckCompiling();
720*0957b409SSimon J. Gerraty 			wordBuilder.AgainIfNot();
721*0957b409SSimon J. Gerraty 		});
722*0957b409SSimon J. Gerraty 		AddNative("untilnot", true, cpu => {
723*0957b409SSimon J. Gerraty 			CheckCompiling();
724*0957b409SSimon J. Gerraty 			wordBuilder.AgainIf();
725*0957b409SSimon J. Gerraty 		});
726*0957b409SSimon J. Gerraty 		AddNative("if", true, cpu => {
727*0957b409SSimon J. Gerraty 			CheckCompiling();
728*0957b409SSimon J. Gerraty 			wordBuilder.AheadIfNot();
729*0957b409SSimon J. Gerraty 		});
730*0957b409SSimon J. Gerraty 		AddNative("ifnot", true, cpu => {
731*0957b409SSimon J. Gerraty 			CheckCompiling();
732*0957b409SSimon J. Gerraty 			wordBuilder.AheadIf();
733*0957b409SSimon J. Gerraty 		});
734*0957b409SSimon J. Gerraty 		AddNative("then", true, cpu => {
735*0957b409SSimon J. Gerraty 			CheckCompiling();
736*0957b409SSimon J. Gerraty 			wordBuilder.Then();
737*0957b409SSimon J. Gerraty 		});
738*0957b409SSimon J. Gerraty 		AddNative("cs-pick", false, cpu => {
739*0957b409SSimon J. Gerraty 			CheckCompiling();
740*0957b409SSimon J. Gerraty 			wordBuilder.CSPick(cpu.Pop());
741*0957b409SSimon J. Gerraty 		});
742*0957b409SSimon J. Gerraty 		AddNative("cs-roll", false, cpu => {
743*0957b409SSimon J. Gerraty 			CheckCompiling();
744*0957b409SSimon J. Gerraty 			wordBuilder.CSRoll(cpu.Pop());
745*0957b409SSimon J. Gerraty 		});
746*0957b409SSimon J. Gerraty 		AddNative("next-word", false, cpu => {
747*0957b409SSimon J. Gerraty 			string s = Next();
748*0957b409SSimon J. Gerraty 			if (s == null) {
749*0957b409SSimon J. Gerraty 				throw new Exception("No next word (EOF)");
750*0957b409SSimon J. Gerraty 			}
751*0957b409SSimon J. Gerraty 			cpu.Push(StringToBlob(s));
752*0957b409SSimon J. Gerraty 		});
753*0957b409SSimon J. Gerraty 		AddNative("parse", false, cpu => {
754*0957b409SSimon J. Gerraty 			int d = cpu.Pop();
755*0957b409SSimon J. Gerraty 			string s = ReadTerm(d);
756*0957b409SSimon J. Gerraty 			cpu.Push(StringToBlob(s));
757*0957b409SSimon J. Gerraty 		});
758*0957b409SSimon J. Gerraty 		AddNative("char", false, cpu => {
759*0957b409SSimon J. Gerraty 			int c = NextChar();
760*0957b409SSimon J. Gerraty 			if (c < 0) {
761*0957b409SSimon J. Gerraty 				throw new Exception("No next character (EOF)");
762*0957b409SSimon J. Gerraty 			}
763*0957b409SSimon J. Gerraty 			cpu.Push(c);
764*0957b409SSimon J. Gerraty 		});
765*0957b409SSimon J. Gerraty 		AddNative("'", false, cpu => {
766*0957b409SSimon J. Gerraty 			string name = Next();
767*0957b409SSimon J. Gerraty 			cpu.Push(new TValue(0, new TPointerXT(name)));
768*0957b409SSimon J. Gerraty 		});
769*0957b409SSimon J. Gerraty 
770*0957b409SSimon J. Gerraty 		/*
771*0957b409SSimon J. Gerraty 		 * The "execute" word is valid in generated C code, but
772*0957b409SSimon J. Gerraty 		 * since it jumps to a runtime pointer, its actual stack
773*0957b409SSimon J. Gerraty 		 * effect cannot be computed in advance.
774*0957b409SSimon J. Gerraty 		 */
775*0957b409SSimon J. Gerraty 		AddNative("execute", false, cpu => {
776*0957b409SSimon J. Gerraty 			cpu.Pop().Execute(this, cpu);
777*0957b409SSimon J. Gerraty 		});
778*0957b409SSimon J. Gerraty 
779*0957b409SSimon J. Gerraty 		AddNative("[", true, cpu => {
780*0957b409SSimon J. Gerraty 			CheckCompiling();
781*0957b409SSimon J. Gerraty 			compiling = false;
782*0957b409SSimon J. Gerraty 		});
783*0957b409SSimon J. Gerraty 		AddNative("]", false, cpu => {
784*0957b409SSimon J. Gerraty 			compiling = true;
785*0957b409SSimon J. Gerraty 		});
786*0957b409SSimon J. Gerraty 		AddNative("(local)", false, cpu => {
787*0957b409SSimon J. Gerraty 			CheckCompiling();
788*0957b409SSimon J. Gerraty 			wordBuilder.DefLocal(cpu.Pop().ToString());
789*0957b409SSimon J. Gerraty 		});
790*0957b409SSimon J. Gerraty 		AddNative("ret", true, cpu => {
791*0957b409SSimon J. Gerraty 			CheckCompiling();
792*0957b409SSimon J. Gerraty 			wordBuilder.Ret();
793*0957b409SSimon J. Gerraty 		});
794*0957b409SSimon J. Gerraty 
795*0957b409SSimon J. Gerraty 		AddNative("drop", false, new SType(1, 0), cpu => {
796*0957b409SSimon J. Gerraty 			cpu.Pop();
797*0957b409SSimon J. Gerraty 		});
798*0957b409SSimon J. Gerraty 		AddNative("dup", false, new SType(1, 2), cpu => {
799*0957b409SSimon J. Gerraty 			cpu.Push(cpu.Peek(0));
800*0957b409SSimon J. Gerraty 		});
801*0957b409SSimon J. Gerraty 		AddNative("swap", false, new SType(2, 2), cpu => {
802*0957b409SSimon J. Gerraty 			cpu.Rot(1);
803*0957b409SSimon J. Gerraty 		});
804*0957b409SSimon J. Gerraty 		AddNative("over", false, new SType(2, 3), cpu => {
805*0957b409SSimon J. Gerraty 			cpu.Push(cpu.Peek(1));
806*0957b409SSimon J. Gerraty 		});
807*0957b409SSimon J. Gerraty 		AddNative("rot", false, new SType(3, 3), cpu => {
808*0957b409SSimon J. Gerraty 			cpu.Rot(2);
809*0957b409SSimon J. Gerraty 		});
810*0957b409SSimon J. Gerraty 		AddNative("-rot", false, new SType(3, 3), cpu => {
811*0957b409SSimon J. Gerraty 			cpu.NRot(2);
812*0957b409SSimon J. Gerraty 		});
813*0957b409SSimon J. Gerraty 
814*0957b409SSimon J. Gerraty 		/*
815*0957b409SSimon J. Gerraty 		 * "roll" and "pick" are special in that the stack slot
816*0957b409SSimon J. Gerraty 		 * they inspect might be known only at runtime, so an
817*0957b409SSimon J. Gerraty 		 * absolute stack effect cannot be attributed. Instead,
818*0957b409SSimon J. Gerraty 		 * we simply hope that the caller knows what it is doing,
819*0957b409SSimon J. Gerraty 		 * and we use a simple stack effect for just the count
820*0957b409SSimon J. Gerraty 		 * value and picked value.
821*0957b409SSimon J. Gerraty 		 */
822*0957b409SSimon J. Gerraty 		AddNative("roll", false, new SType(1, 0), cpu => {
823*0957b409SSimon J. Gerraty 			cpu.Rot(cpu.Pop());
824*0957b409SSimon J. Gerraty 		});
825*0957b409SSimon J. Gerraty 		AddNative("pick", false, new SType(1, 1), cpu => {
826*0957b409SSimon J. Gerraty 			cpu.Push(cpu.Peek(cpu.Pop()));
827*0957b409SSimon J. Gerraty 		});
828*0957b409SSimon J. Gerraty 
829*0957b409SSimon J. Gerraty 		AddNative("+", false, new SType(2, 1), cpu => {
830*0957b409SSimon J. Gerraty 			TValue b = cpu.Pop();
831*0957b409SSimon J. Gerraty 			TValue a = cpu.Pop();
832*0957b409SSimon J. Gerraty 			if (b.ptr == null) {
833*0957b409SSimon J. Gerraty 				a.x += (int)b;
834*0957b409SSimon J. Gerraty 				cpu.Push(a);
835*0957b409SSimon J. Gerraty 			} else if (a.ptr is TPointerBlob
836*0957b409SSimon J. Gerraty 				&& b.ptr is TPointerBlob)
837*0957b409SSimon J. Gerraty 			{
838*0957b409SSimon J. Gerraty 				cpu.Push(StringToBlob(
839*0957b409SSimon J. Gerraty 					a.ToString() + b.ToString()));
840*0957b409SSimon J. Gerraty 			} else {
841*0957b409SSimon J. Gerraty 				throw new Exception(string.Format(
842*0957b409SSimon J. Gerraty 					"Cannot add '{0}' to '{1}'", b, a));
843*0957b409SSimon J. Gerraty 			}
844*0957b409SSimon J. Gerraty 		});
845*0957b409SSimon J. Gerraty 		AddNative("-", false, new SType(2, 1), cpu => {
846*0957b409SSimon J. Gerraty 			/*
847*0957b409SSimon J. Gerraty 			 * We can subtract two pointers, provided that
848*0957b409SSimon J. Gerraty 			 * they point to the same blob. Otherwise,
849*0957b409SSimon J. Gerraty 			 * the subtraction second operand must be an
850*0957b409SSimon J. Gerraty 			 * integer.
851*0957b409SSimon J. Gerraty 			 */
852*0957b409SSimon J. Gerraty 			TValue b = cpu.Pop();
853*0957b409SSimon J. Gerraty 			TValue a = cpu.Pop();
854*0957b409SSimon J. Gerraty 			TPointerBlob ap = a.ptr as TPointerBlob;
855*0957b409SSimon J. Gerraty 			TPointerBlob bp = b.ptr as TPointerBlob;
856*0957b409SSimon J. Gerraty 			if (ap != null && bp != null && ap.Blob == bp.Blob) {
857*0957b409SSimon J. Gerraty 				cpu.Push(new TValue(a.x - b.x));
858*0957b409SSimon J. Gerraty 				return;
859*0957b409SSimon J. Gerraty 			}
860*0957b409SSimon J. Gerraty 			int bx = b;
861*0957b409SSimon J. Gerraty 			a.x -= bx;
862*0957b409SSimon J. Gerraty 			cpu.Push(a);
863*0957b409SSimon J. Gerraty 		});
864*0957b409SSimon J. Gerraty 		AddNative("neg", false, new SType(1, 1), cpu => {
865*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
866*0957b409SSimon J. Gerraty 			cpu.Push(-ax);
867*0957b409SSimon J. Gerraty 		});
868*0957b409SSimon J. Gerraty 		AddNative("*", false, new SType(2, 1), cpu => {
869*0957b409SSimon J. Gerraty 			int bx = cpu.Pop();
870*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
871*0957b409SSimon J. Gerraty 			cpu.Push(ax * bx);
872*0957b409SSimon J. Gerraty 		});
873*0957b409SSimon J. Gerraty 		AddNative("/", false, new SType(2, 1), cpu => {
874*0957b409SSimon J. Gerraty 			int bx = cpu.Pop();
875*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
876*0957b409SSimon J. Gerraty 			cpu.Push(ax / bx);
877*0957b409SSimon J. Gerraty 		});
878*0957b409SSimon J. Gerraty 		AddNative("u/", false, new SType(2, 1), cpu => {
879*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop();
880*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
881*0957b409SSimon J. Gerraty 			cpu.Push(ax / bx);
882*0957b409SSimon J. Gerraty 		});
883*0957b409SSimon J. Gerraty 		AddNative("%", false, new SType(2, 1), cpu => {
884*0957b409SSimon J. Gerraty 			int bx = cpu.Pop();
885*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
886*0957b409SSimon J. Gerraty 			cpu.Push(ax % bx);
887*0957b409SSimon J. Gerraty 		});
888*0957b409SSimon J. Gerraty 		AddNative("u%", false, new SType(2, 1), cpu => {
889*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop();
890*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
891*0957b409SSimon J. Gerraty 			cpu.Push(ax % bx);
892*0957b409SSimon J. Gerraty 		});
893*0957b409SSimon J. Gerraty 		AddNative("<", false, new SType(2, 1), cpu => {
894*0957b409SSimon J. Gerraty 			int bx = cpu.Pop();
895*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
896*0957b409SSimon J. Gerraty 			cpu.Push(ax < bx);
897*0957b409SSimon J. Gerraty 		});
898*0957b409SSimon J. Gerraty 		AddNative("<=", false, new SType(2, 1), cpu => {
899*0957b409SSimon J. Gerraty 			int bx = cpu.Pop();
900*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
901*0957b409SSimon J. Gerraty 			cpu.Push(ax <= bx);
902*0957b409SSimon J. Gerraty 		});
903*0957b409SSimon J. Gerraty 		AddNative(">", false, new SType(2, 1), cpu => {
904*0957b409SSimon J. Gerraty 			int bx = cpu.Pop();
905*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
906*0957b409SSimon J. Gerraty 			cpu.Push(ax > bx);
907*0957b409SSimon J. Gerraty 		});
908*0957b409SSimon J. Gerraty 		AddNative(">=", false, new SType(2, 1), cpu => {
909*0957b409SSimon J. Gerraty 			int bx = cpu.Pop();
910*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
911*0957b409SSimon J. Gerraty 			cpu.Push(ax >= bx);
912*0957b409SSimon J. Gerraty 		});
913*0957b409SSimon J. Gerraty 		AddNative("=", false, new SType(2, 1), cpu => {
914*0957b409SSimon J. Gerraty 			TValue b = cpu.Pop();
915*0957b409SSimon J. Gerraty 			TValue a = cpu.Pop();
916*0957b409SSimon J. Gerraty 			cpu.Push(a.Equals(b));
917*0957b409SSimon J. Gerraty 		});
918*0957b409SSimon J. Gerraty 		AddNative("<>", false, new SType(2, 1), cpu => {
919*0957b409SSimon J. Gerraty 			TValue b = cpu.Pop();
920*0957b409SSimon J. Gerraty 			TValue a = cpu.Pop();
921*0957b409SSimon J. Gerraty 			cpu.Push(!a.Equals(b));
922*0957b409SSimon J. Gerraty 		});
923*0957b409SSimon J. Gerraty 		AddNative("u<", false, new SType(2, 1), cpu => {
924*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop().UInt;
925*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop().UInt;
926*0957b409SSimon J. Gerraty 			cpu.Push(new TValue(ax < bx));
927*0957b409SSimon J. Gerraty 		});
928*0957b409SSimon J. Gerraty 		AddNative("u<=", false, new SType(2, 1), cpu => {
929*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop().UInt;
930*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop().UInt;
931*0957b409SSimon J. Gerraty 			cpu.Push(new TValue(ax <= bx));
932*0957b409SSimon J. Gerraty 		});
933*0957b409SSimon J. Gerraty 		AddNative("u>", false, new SType(2, 1), cpu => {
934*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop().UInt;
935*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop().UInt;
936*0957b409SSimon J. Gerraty 			cpu.Push(new TValue(ax > bx));
937*0957b409SSimon J. Gerraty 		});
938*0957b409SSimon J. Gerraty 		AddNative("u>=", false, new SType(2, 1), cpu => {
939*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop();
940*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
941*0957b409SSimon J. Gerraty 			cpu.Push(ax >= bx);
942*0957b409SSimon J. Gerraty 		});
943*0957b409SSimon J. Gerraty 		AddNative("and", false, new SType(2, 1), cpu => {
944*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop();
945*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
946*0957b409SSimon J. Gerraty 			cpu.Push(ax & bx);
947*0957b409SSimon J. Gerraty 		});
948*0957b409SSimon J. Gerraty 		AddNative("or", false, new SType(2, 1), cpu => {
949*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop();
950*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
951*0957b409SSimon J. Gerraty 			cpu.Push(ax | bx);
952*0957b409SSimon J. Gerraty 		});
953*0957b409SSimon J. Gerraty 		AddNative("xor", false, new SType(2, 1), cpu => {
954*0957b409SSimon J. Gerraty 			uint bx = cpu.Pop();
955*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
956*0957b409SSimon J. Gerraty 			cpu.Push(ax ^ bx);
957*0957b409SSimon J. Gerraty 		});
958*0957b409SSimon J. Gerraty 		AddNative("not", false, new SType(1, 1), cpu => {
959*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
960*0957b409SSimon J. Gerraty 			cpu.Push(~ax);
961*0957b409SSimon J. Gerraty 		});
962*0957b409SSimon J. Gerraty 		AddNative("<<", false, new SType(2, 1), cpu => {
963*0957b409SSimon J. Gerraty 			int count = cpu.Pop();
964*0957b409SSimon J. Gerraty 			if (count < 0 || count > 31) {
965*0957b409SSimon J. Gerraty 				throw new Exception("Invalid shift count");
966*0957b409SSimon J. Gerraty 			}
967*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
968*0957b409SSimon J. Gerraty 			cpu.Push(ax << count);
969*0957b409SSimon J. Gerraty 		});
970*0957b409SSimon J. Gerraty 		AddNative(">>", false, new SType(2, 1), cpu => {
971*0957b409SSimon J. Gerraty 			int count = cpu.Pop();
972*0957b409SSimon J. Gerraty 			if (count < 0 || count > 31) {
973*0957b409SSimon J. Gerraty 				throw new Exception("Invalid shift count");
974*0957b409SSimon J. Gerraty 			}
975*0957b409SSimon J. Gerraty 			int ax = cpu.Pop();
976*0957b409SSimon J. Gerraty 			cpu.Push(ax >> count);
977*0957b409SSimon J. Gerraty 		});
978*0957b409SSimon J. Gerraty 		AddNative("u>>", false, new SType(2, 1), cpu => {
979*0957b409SSimon J. Gerraty 			int count = cpu.Pop();
980*0957b409SSimon J. Gerraty 			if (count < 0 || count > 31) {
981*0957b409SSimon J. Gerraty 				throw new Exception("Invalid shift count");
982*0957b409SSimon J. Gerraty 			}
983*0957b409SSimon J. Gerraty 			uint ax = cpu.Pop();
984*0957b409SSimon J. Gerraty 			cpu.Push(ax >> count);
985*0957b409SSimon J. Gerraty 		});
986*0957b409SSimon J. Gerraty 
987*0957b409SSimon J. Gerraty 		AddNative(".", false, new SType(1, 0), cpu => {
988*0957b409SSimon J. Gerraty 			Console.Write(" {0}", cpu.Pop().ToString());
989*0957b409SSimon J. Gerraty 		});
990*0957b409SSimon J. Gerraty 		AddNative(".s", false, SType.BLANK, cpu => {
991*0957b409SSimon J. Gerraty 			int n = cpu.Depth;
992*0957b409SSimon J. Gerraty 			for (int i = n - 1; i >= 0; i --) {
993*0957b409SSimon J. Gerraty 				Console.Write(" {0}", cpu.Peek(i).ToString());
994*0957b409SSimon J. Gerraty 			}
995*0957b409SSimon J. Gerraty 		});
996*0957b409SSimon J. Gerraty 		AddNative("putc", false, new SType(1, 0), cpu => {
997*0957b409SSimon J. Gerraty 			Console.Write((char)cpu.Pop());
998*0957b409SSimon J. Gerraty 		});
999*0957b409SSimon J. Gerraty 		AddNative("puts", false, new SType(1, 0), cpu => {
1000*0957b409SSimon J. Gerraty 			Console.Write("{0}", cpu.Pop().ToString());
1001*0957b409SSimon J. Gerraty 		});
1002*0957b409SSimon J. Gerraty 		AddNative("cr", false, SType.BLANK, cpu => {
1003*0957b409SSimon J. Gerraty 			Console.WriteLine();
1004*0957b409SSimon J. Gerraty 		});
1005*0957b409SSimon J. Gerraty 		AddNative("eqstr", false, new SType(2, 1), cpu => {
1006*0957b409SSimon J. Gerraty 			string s2 = cpu.Pop().ToString();
1007*0957b409SSimon J. Gerraty 			string s1 = cpu.Pop().ToString();
1008*0957b409SSimon J. Gerraty 			cpu.Push(s1 == s2);
1009*0957b409SSimon J. Gerraty 		});
1010*0957b409SSimon J. Gerraty 	}
1011*0957b409SSimon J. Gerraty 
AddNative(string name, bool immediate, WordNative.NativeRun code)1012*0957b409SSimon J. Gerraty 	WordNative AddNative(string name, bool immediate,
1013*0957b409SSimon J. Gerraty 		WordNative.NativeRun code)
1014*0957b409SSimon J. Gerraty 	{
1015*0957b409SSimon J. Gerraty 		return AddNative(name, immediate, SType.UNKNOWN, code);
1016*0957b409SSimon J. Gerraty 	}
1017*0957b409SSimon J. Gerraty 
AddNative(string name, bool immediate, SType stackEffect, WordNative.NativeRun code)1018*0957b409SSimon J. Gerraty 	WordNative AddNative(string name, bool immediate, SType stackEffect,
1019*0957b409SSimon J. Gerraty 		WordNative.NativeRun code)
1020*0957b409SSimon J. Gerraty 	{
1021*0957b409SSimon J. Gerraty 		if (words.ContainsKey(name)) {
1022*0957b409SSimon J. Gerraty 			throw new Exception(
1023*0957b409SSimon J. Gerraty 				"Word already defined: " + name);
1024*0957b409SSimon J. Gerraty 		}
1025*0957b409SSimon J. Gerraty 		WordNative w = new WordNative(this, name, code);
1026*0957b409SSimon J. Gerraty 		w.Immediate = immediate;
1027*0957b409SSimon J. Gerraty 		w.StackEffect = stackEffect;
1028*0957b409SSimon J. Gerraty 		words[name] = w;
1029*0957b409SSimon J. Gerraty 		return w;
1030*0957b409SSimon J. Gerraty 	}
1031*0957b409SSimon J. Gerraty 
NextBlobID()1032*0957b409SSimon J. Gerraty 	internal long NextBlobID()
1033*0957b409SSimon J. Gerraty 	{
1034*0957b409SSimon J. Gerraty 		return currentBlobID ++;
1035*0957b409SSimon J. Gerraty 	}
1036*0957b409SSimon J. Gerraty 
NextChar()1037*0957b409SSimon J. Gerraty 	int NextChar()
1038*0957b409SSimon J. Gerraty 	{
1039*0957b409SSimon J. Gerraty 		int c = delayedChar;
1040*0957b409SSimon J. Gerraty 		if (c >= 0) {
1041*0957b409SSimon J. Gerraty 			delayedChar = Int32.MinValue;
1042*0957b409SSimon J. Gerraty 		} else if (c > Int32.MinValue) {
1043*0957b409SSimon J. Gerraty 			delayedChar = -(c + 1);
1044*0957b409SSimon J. Gerraty 			c = '\n';
1045*0957b409SSimon J. Gerraty 		} else {
1046*0957b409SSimon J. Gerraty 			c = currentInput.Read();
1047*0957b409SSimon J. Gerraty 		}
1048*0957b409SSimon J. Gerraty 		if (c == '\r') {
1049*0957b409SSimon J. Gerraty 			if (delayedChar >= 0) {
1050*0957b409SSimon J. Gerraty 				c = delayedChar;
1051*0957b409SSimon J. Gerraty 				delayedChar = Int32.MinValue;
1052*0957b409SSimon J. Gerraty 			} else {
1053*0957b409SSimon J. Gerraty 				c = currentInput.Read();
1054*0957b409SSimon J. Gerraty 			}
1055*0957b409SSimon J. Gerraty 			if (c != '\n') {
1056*0957b409SSimon J. Gerraty 				delayedChar = c;
1057*0957b409SSimon J. Gerraty 				c = '\n';
1058*0957b409SSimon J. Gerraty 			}
1059*0957b409SSimon J. Gerraty 		}
1060*0957b409SSimon J. Gerraty 		return c;
1061*0957b409SSimon J. Gerraty 	}
1062*0957b409SSimon J. Gerraty 
1063*0957b409SSimon J. Gerraty 	/*
1064*0957b409SSimon J. Gerraty 	 * Un-read the character value 'c'. That value MUST be the one
1065*0957b409SSimon J. Gerraty 	 * that was obtained from NextChar().
1066*0957b409SSimon J. Gerraty 	 */
Unread(int c)1067*0957b409SSimon J. Gerraty 	void Unread(int c)
1068*0957b409SSimon J. Gerraty 	{
1069*0957b409SSimon J. Gerraty 		if (c < 0) {
1070*0957b409SSimon J. Gerraty 			return;
1071*0957b409SSimon J. Gerraty 		}
1072*0957b409SSimon J. Gerraty 		if (delayedChar < 0) {
1073*0957b409SSimon J. Gerraty 			if (delayedChar != Int32.MinValue) {
1074*0957b409SSimon J. Gerraty 				throw new Exception(
1075*0957b409SSimon J. Gerraty 					"Already two delayed characters");
1076*0957b409SSimon J. Gerraty 			}
1077*0957b409SSimon J. Gerraty 			delayedChar = c;
1078*0957b409SSimon J. Gerraty 		} else if (c != '\n') {
1079*0957b409SSimon J. Gerraty 			throw new Exception("Cannot delay two characters");
1080*0957b409SSimon J. Gerraty 		} else {
1081*0957b409SSimon J. Gerraty 			delayedChar = -(delayedChar + 1);
1082*0957b409SSimon J. Gerraty 		}
1083*0957b409SSimon J. Gerraty 	}
1084*0957b409SSimon J. Gerraty 
Next()1085*0957b409SSimon J. Gerraty 	string Next()
1086*0957b409SSimon J. Gerraty 	{
1087*0957b409SSimon J. Gerraty 		string r = delayedToken;
1088*0957b409SSimon J. Gerraty 		if (r != null) {
1089*0957b409SSimon J. Gerraty 			delayedToken = null;
1090*0957b409SSimon J. Gerraty 			return r;
1091*0957b409SSimon J. Gerraty 		}
1092*0957b409SSimon J. Gerraty 		tokenBuilder.Length = 0;
1093*0957b409SSimon J. Gerraty 		int c;
1094*0957b409SSimon J. Gerraty 		for (;;) {
1095*0957b409SSimon J. Gerraty 			c = NextChar();
1096*0957b409SSimon J. Gerraty 			if (c < 0) {
1097*0957b409SSimon J. Gerraty 				return null;
1098*0957b409SSimon J. Gerraty 			}
1099*0957b409SSimon J. Gerraty 			if (!IsWS(c)) {
1100*0957b409SSimon J. Gerraty 				break;
1101*0957b409SSimon J. Gerraty 			}
1102*0957b409SSimon J. Gerraty 		}
1103*0957b409SSimon J. Gerraty 		if (c == '"') {
1104*0957b409SSimon J. Gerraty 			return ParseString();
1105*0957b409SSimon J. Gerraty 		}
1106*0957b409SSimon J. Gerraty 		for (;;) {
1107*0957b409SSimon J. Gerraty 			tokenBuilder.Append((char)c);
1108*0957b409SSimon J. Gerraty 			c = NextChar();
1109*0957b409SSimon J. Gerraty 			if (c < 0 || IsWS(c)) {
1110*0957b409SSimon J. Gerraty 				Unread(c);
1111*0957b409SSimon J. Gerraty 				return tokenBuilder.ToString();
1112*0957b409SSimon J. Gerraty 			}
1113*0957b409SSimon J. Gerraty 		}
1114*0957b409SSimon J. Gerraty 	}
1115*0957b409SSimon J. Gerraty 
ParseCCode()1116*0957b409SSimon J. Gerraty 	string ParseCCode()
1117*0957b409SSimon J. Gerraty 	{
1118*0957b409SSimon J. Gerraty 		SType stackEffect;
1119*0957b409SSimon J. Gerraty 		string r = ParseCCode(out stackEffect);
1120*0957b409SSimon J. Gerraty 		if (stackEffect.IsKnown) {
1121*0957b409SSimon J. Gerraty 			throw new Exception(
1122*0957b409SSimon J. Gerraty 				"Stack effect forbidden in this declaration");
1123*0957b409SSimon J. Gerraty 		}
1124*0957b409SSimon J. Gerraty 		return r;
1125*0957b409SSimon J. Gerraty 	}
1126*0957b409SSimon J. Gerraty 
ParseCCode(out SType stackEffect)1127*0957b409SSimon J. Gerraty 	string ParseCCode(out SType stackEffect)
1128*0957b409SSimon J. Gerraty 	{
1129*0957b409SSimon J. Gerraty 		string s = ParseCCodeNF(out stackEffect);
1130*0957b409SSimon J. Gerraty 		if (s == null) {
1131*0957b409SSimon J. Gerraty 			throw new Exception("Error while parsing C code");
1132*0957b409SSimon J. Gerraty 		}
1133*0957b409SSimon J. Gerraty 		return s;
1134*0957b409SSimon J. Gerraty 	}
1135*0957b409SSimon J. Gerraty 
ParseCCodeNF(out SType stackEffect)1136*0957b409SSimon J. Gerraty 	string ParseCCodeNF(out SType stackEffect)
1137*0957b409SSimon J. Gerraty 	{
1138*0957b409SSimon J. Gerraty 		stackEffect = SType.UNKNOWN;
1139*0957b409SSimon J. Gerraty 		for (;;) {
1140*0957b409SSimon J. Gerraty 			int c = NextChar();
1141*0957b409SSimon J. Gerraty 			if (c < 0) {
1142*0957b409SSimon J. Gerraty 				return null;
1143*0957b409SSimon J. Gerraty 			}
1144*0957b409SSimon J. Gerraty 			if (!IsWS(c)) {
1145*0957b409SSimon J. Gerraty 				if (c == '(') {
1146*0957b409SSimon J. Gerraty 					if (stackEffect.IsKnown) {
1147*0957b409SSimon J. Gerraty 						Unread(c);
1148*0957b409SSimon J. Gerraty 						return null;
1149*0957b409SSimon J. Gerraty 					}
1150*0957b409SSimon J. Gerraty 					stackEffect = ParseStackEffectNF();
1151*0957b409SSimon J. Gerraty 					if (!stackEffect.IsKnown) {
1152*0957b409SSimon J. Gerraty 						return null;
1153*0957b409SSimon J. Gerraty 					}
1154*0957b409SSimon J. Gerraty 					continue;
1155*0957b409SSimon J. Gerraty 				} else if (c != '{') {
1156*0957b409SSimon J. Gerraty 					Unread(c);
1157*0957b409SSimon J. Gerraty 					return null;
1158*0957b409SSimon J. Gerraty 				}
1159*0957b409SSimon J. Gerraty 				break;
1160*0957b409SSimon J. Gerraty 			}
1161*0957b409SSimon J. Gerraty 		}
1162*0957b409SSimon J. Gerraty 		StringBuilder sb = new StringBuilder();
1163*0957b409SSimon J. Gerraty 		int count = 1;
1164*0957b409SSimon J. Gerraty 		for (;;) {
1165*0957b409SSimon J. Gerraty 			int c = NextChar();
1166*0957b409SSimon J. Gerraty 			if (c < 0) {
1167*0957b409SSimon J. Gerraty 				return null;
1168*0957b409SSimon J. Gerraty 			}
1169*0957b409SSimon J. Gerraty 			switch (c) {
1170*0957b409SSimon J. Gerraty 			case '{':
1171*0957b409SSimon J. Gerraty 				count ++;
1172*0957b409SSimon J. Gerraty 				break;
1173*0957b409SSimon J. Gerraty 			case '}':
1174*0957b409SSimon J. Gerraty 				if (-- count == 0) {
1175*0957b409SSimon J. Gerraty 					return sb.ToString();
1176*0957b409SSimon J. Gerraty 				}
1177*0957b409SSimon J. Gerraty 				break;
1178*0957b409SSimon J. Gerraty 			}
1179*0957b409SSimon J. Gerraty 			sb.Append((char)c);
1180*0957b409SSimon J. Gerraty 		}
1181*0957b409SSimon J. Gerraty 	}
1182*0957b409SSimon J. Gerraty 
1183*0957b409SSimon J. Gerraty 	/*
1184*0957b409SSimon J. Gerraty 	 * Parse a stack effect declaration. This method assumes that the
1185*0957b409SSimon J. Gerraty 	 * opening parenthesis has just been read. If the parsing fails,
1186*0957b409SSimon J. Gerraty 	 * then this method returns SType.UNKNOWN.
1187*0957b409SSimon J. Gerraty 	 */
ParseStackEffectNF()1188*0957b409SSimon J. Gerraty 	SType ParseStackEffectNF()
1189*0957b409SSimon J. Gerraty 	{
1190*0957b409SSimon J. Gerraty 		bool seenSep = false;
1191*0957b409SSimon J. Gerraty 		bool seenBang = false;
1192*0957b409SSimon J. Gerraty 		int din = 0, dout = 0;
1193*0957b409SSimon J. Gerraty 		for (;;) {
1194*0957b409SSimon J. Gerraty 			string t = Next();
1195*0957b409SSimon J. Gerraty 			if (t == null) {
1196*0957b409SSimon J. Gerraty 				return SType.UNKNOWN;
1197*0957b409SSimon J. Gerraty 			}
1198*0957b409SSimon J. Gerraty 			if (t == "--") {
1199*0957b409SSimon J. Gerraty 				if (seenSep) {
1200*0957b409SSimon J. Gerraty 					return SType.UNKNOWN;
1201*0957b409SSimon J. Gerraty 				}
1202*0957b409SSimon J. Gerraty 				seenSep = true;
1203*0957b409SSimon J. Gerraty 			} else if (t == ")") {
1204*0957b409SSimon J. Gerraty 				if (seenSep) {
1205*0957b409SSimon J. Gerraty 					if (seenBang && dout == 1) {
1206*0957b409SSimon J. Gerraty 						dout = -1;
1207*0957b409SSimon J. Gerraty 					}
1208*0957b409SSimon J. Gerraty 					return new SType(din, dout);
1209*0957b409SSimon J. Gerraty 				} else {
1210*0957b409SSimon J. Gerraty 					return SType.UNKNOWN;
1211*0957b409SSimon J. Gerraty 				}
1212*0957b409SSimon J. Gerraty 			} else {
1213*0957b409SSimon J. Gerraty 				if (seenSep) {
1214*0957b409SSimon J. Gerraty 					if (dout == 0 && t == "!") {
1215*0957b409SSimon J. Gerraty 						seenBang = true;
1216*0957b409SSimon J. Gerraty 					}
1217*0957b409SSimon J. Gerraty 					dout ++;
1218*0957b409SSimon J. Gerraty 				} else {
1219*0957b409SSimon J. Gerraty 					din ++;
1220*0957b409SSimon J. Gerraty 				}
1221*0957b409SSimon J. Gerraty 			}
1222*0957b409SSimon J. Gerraty 		}
1223*0957b409SSimon J. Gerraty 	}
1224*0957b409SSimon J. Gerraty 
ParseString()1225*0957b409SSimon J. Gerraty 	string ParseString()
1226*0957b409SSimon J. Gerraty 	{
1227*0957b409SSimon J. Gerraty 		StringBuilder sb = new StringBuilder();
1228*0957b409SSimon J. Gerraty 		sb.Append('"');
1229*0957b409SSimon J. Gerraty 		bool lcwb = false;
1230*0957b409SSimon J. Gerraty 		int hexNum = 0;
1231*0957b409SSimon J. Gerraty 		int acc = 0;
1232*0957b409SSimon J. Gerraty 		for (;;) {
1233*0957b409SSimon J. Gerraty 			int c = NextChar();
1234*0957b409SSimon J. Gerraty 			if (c < 0) {
1235*0957b409SSimon J. Gerraty 				throw new Exception(
1236*0957b409SSimon J. Gerraty 					"Unfinished literal string");
1237*0957b409SSimon J. Gerraty 			}
1238*0957b409SSimon J. Gerraty 			if (hexNum > 0) {
1239*0957b409SSimon J. Gerraty 				int d = HexVal(c);
1240*0957b409SSimon J. Gerraty 				if (d < 0) {
1241*0957b409SSimon J. Gerraty 					throw new Exception(String.Format(
1242*0957b409SSimon J. Gerraty 						"not an hex digit: U+{0:X4}",
1243*0957b409SSimon J. Gerraty 						c));
1244*0957b409SSimon J. Gerraty 				}
1245*0957b409SSimon J. Gerraty 				acc = (acc << 4) + d;
1246*0957b409SSimon J. Gerraty 				if (-- hexNum == 0) {
1247*0957b409SSimon J. Gerraty 					sb.Append((char)acc);
1248*0957b409SSimon J. Gerraty 					acc = 0;
1249*0957b409SSimon J. Gerraty 				}
1250*0957b409SSimon J. Gerraty 			} else if (lcwb) {
1251*0957b409SSimon J. Gerraty 				lcwb = false;
1252*0957b409SSimon J. Gerraty 				switch (c) {
1253*0957b409SSimon J. Gerraty 				case '\n': SkipNL(); break;
1254*0957b409SSimon J. Gerraty 				case 'x':
1255*0957b409SSimon J. Gerraty 					hexNum = 2;
1256*0957b409SSimon J. Gerraty 					break;
1257*0957b409SSimon J. Gerraty 				case 'u':
1258*0957b409SSimon J. Gerraty 					hexNum = 4;
1259*0957b409SSimon J. Gerraty 					break;
1260*0957b409SSimon J. Gerraty 				default:
1261*0957b409SSimon J. Gerraty 					sb.Append(SingleCharEscape(c));
1262*0957b409SSimon J. Gerraty 					break;
1263*0957b409SSimon J. Gerraty 				}
1264*0957b409SSimon J. Gerraty 			} else {
1265*0957b409SSimon J. Gerraty 				switch (c) {
1266*0957b409SSimon J. Gerraty 				case '"':
1267*0957b409SSimon J. Gerraty 					return sb.ToString();
1268*0957b409SSimon J. Gerraty 				case '\\':
1269*0957b409SSimon J. Gerraty 					lcwb = true;
1270*0957b409SSimon J. Gerraty 					break;
1271*0957b409SSimon J. Gerraty 				default:
1272*0957b409SSimon J. Gerraty 					sb.Append((char)c);
1273*0957b409SSimon J. Gerraty 					break;
1274*0957b409SSimon J. Gerraty 				}
1275*0957b409SSimon J. Gerraty 			}
1276*0957b409SSimon J. Gerraty 		}
1277*0957b409SSimon J. Gerraty 	}
1278*0957b409SSimon J. Gerraty 
SingleCharEscape(int c)1279*0957b409SSimon J. Gerraty 	static char SingleCharEscape(int c)
1280*0957b409SSimon J. Gerraty 	{
1281*0957b409SSimon J. Gerraty 		switch (c) {
1282*0957b409SSimon J. Gerraty 		case 'n': return '\n';
1283*0957b409SSimon J. Gerraty 		case 'r': return '\r';
1284*0957b409SSimon J. Gerraty 		case 't': return '\t';
1285*0957b409SSimon J. Gerraty 		case 's': return ' ';
1286*0957b409SSimon J. Gerraty 		default:
1287*0957b409SSimon J. Gerraty 			return (char)c;
1288*0957b409SSimon J. Gerraty 		}
1289*0957b409SSimon J. Gerraty 	}
1290*0957b409SSimon J. Gerraty 
1291*0957b409SSimon J. Gerraty 	/*
1292*0957b409SSimon J. Gerraty 	 * A backslash+newline sequence occurred in a literal string; we
1293*0957b409SSimon J. Gerraty 	 * check and consume the newline escape sequence (whitespace at
1294*0957b409SSimon J. Gerraty 	 * start of next line, then a double-quote character).
1295*0957b409SSimon J. Gerraty 	 */
SkipNL()1296*0957b409SSimon J. Gerraty 	void SkipNL()
1297*0957b409SSimon J. Gerraty 	{
1298*0957b409SSimon J. Gerraty 		for (;;) {
1299*0957b409SSimon J. Gerraty 			int c = NextChar();
1300*0957b409SSimon J. Gerraty 			if (c < 0) {
1301*0957b409SSimon J. Gerraty 				throw new Exception("EOF in literal string");
1302*0957b409SSimon J. Gerraty 			}
1303*0957b409SSimon J. Gerraty 			if (c == '\n') {
1304*0957b409SSimon J. Gerraty 				throw new Exception(
1305*0957b409SSimon J. Gerraty 					"Unescaped newline in literal string");
1306*0957b409SSimon J. Gerraty 			}
1307*0957b409SSimon J. Gerraty 			if (IsWS(c)) {
1308*0957b409SSimon J. Gerraty 				continue;
1309*0957b409SSimon J. Gerraty 			}
1310*0957b409SSimon J. Gerraty 			if (c == '"') {
1311*0957b409SSimon J. Gerraty 				return;
1312*0957b409SSimon J. Gerraty 			}
1313*0957b409SSimon J. Gerraty 			throw new Exception(
1314*0957b409SSimon J. Gerraty 				"Invalid newline escape in literal string");
1315*0957b409SSimon J. Gerraty 		}
1316*0957b409SSimon J. Gerraty 	}
1317*0957b409SSimon J. Gerraty 
DecodeCharConst(string t)1318*0957b409SSimon J. Gerraty 	static char DecodeCharConst(string t)
1319*0957b409SSimon J. Gerraty 	{
1320*0957b409SSimon J. Gerraty 		if (t.Length == 1 && t[0] != '\\') {
1321*0957b409SSimon J. Gerraty 			return t[0];
1322*0957b409SSimon J. Gerraty 		}
1323*0957b409SSimon J. Gerraty 		if (t.Length >= 2 && t[0] == '\\') {
1324*0957b409SSimon J. Gerraty 			switch (t[1]) {
1325*0957b409SSimon J. Gerraty 			case 'x':
1326*0957b409SSimon J. Gerraty 				if (t.Length == 4) {
1327*0957b409SSimon J. Gerraty 					int x = DecHex(t.Substring(2));
1328*0957b409SSimon J. Gerraty 					if (x >= 0) {
1329*0957b409SSimon J. Gerraty 						return (char)x;
1330*0957b409SSimon J. Gerraty 					}
1331*0957b409SSimon J. Gerraty 				}
1332*0957b409SSimon J. Gerraty 				break;
1333*0957b409SSimon J. Gerraty 			case 'u':
1334*0957b409SSimon J. Gerraty 				if (t.Length == 6) {
1335*0957b409SSimon J. Gerraty 					int x = DecHex(t.Substring(2));
1336*0957b409SSimon J. Gerraty 					if (x >= 0) {
1337*0957b409SSimon J. Gerraty 						return (char)x;
1338*0957b409SSimon J. Gerraty 					}
1339*0957b409SSimon J. Gerraty 				}
1340*0957b409SSimon J. Gerraty 				break;
1341*0957b409SSimon J. Gerraty 			default:
1342*0957b409SSimon J. Gerraty 				if (t.Length == 2) {
1343*0957b409SSimon J. Gerraty 					return SingleCharEscape(t[1]);
1344*0957b409SSimon J. Gerraty 				}
1345*0957b409SSimon J. Gerraty 				break;
1346*0957b409SSimon J. Gerraty 			}
1347*0957b409SSimon J. Gerraty 		}
1348*0957b409SSimon J. Gerraty 		throw new Exception("Invalid literal char: `" + t);
1349*0957b409SSimon J. Gerraty 	}
1350*0957b409SSimon J. Gerraty 
DecHex(string s)1351*0957b409SSimon J. Gerraty 	static int DecHex(string s)
1352*0957b409SSimon J. Gerraty 	{
1353*0957b409SSimon J. Gerraty 		int acc = 0;
1354*0957b409SSimon J. Gerraty 		foreach (char c in s) {
1355*0957b409SSimon J. Gerraty 			int d = HexVal(c);
1356*0957b409SSimon J. Gerraty 			if (d < 0) {
1357*0957b409SSimon J. Gerraty 				return -1;
1358*0957b409SSimon J. Gerraty 			}
1359*0957b409SSimon J. Gerraty 			acc = (acc << 4) + d;
1360*0957b409SSimon J. Gerraty 		}
1361*0957b409SSimon J. Gerraty 		return acc;
1362*0957b409SSimon J. Gerraty 	}
1363*0957b409SSimon J. Gerraty 
HexVal(int c)1364*0957b409SSimon J. Gerraty 	static int HexVal(int c)
1365*0957b409SSimon J. Gerraty 	{
1366*0957b409SSimon J. Gerraty 		if (c >= '0' && c <= '9') {
1367*0957b409SSimon J. Gerraty 			return c - '0';
1368*0957b409SSimon J. Gerraty 		} else if (c >= 'A' && c <= 'F') {
1369*0957b409SSimon J. Gerraty 			return c - ('A' - 10);
1370*0957b409SSimon J. Gerraty 		} else if (c >= 'a' && c <= 'f') {
1371*0957b409SSimon J. Gerraty 			return c - ('a' - 10);
1372*0957b409SSimon J. Gerraty 		} else {
1373*0957b409SSimon J. Gerraty 			return -1;
1374*0957b409SSimon J. Gerraty 		}
1375*0957b409SSimon J. Gerraty 	}
1376*0957b409SSimon J. Gerraty 
ReadTerm(int ct)1377*0957b409SSimon J. Gerraty 	string ReadTerm(int ct)
1378*0957b409SSimon J. Gerraty 	{
1379*0957b409SSimon J. Gerraty 		StringBuilder sb = new StringBuilder();
1380*0957b409SSimon J. Gerraty 		for (;;) {
1381*0957b409SSimon J. Gerraty 			int c = NextChar();
1382*0957b409SSimon J. Gerraty 			if (c < 0) {
1383*0957b409SSimon J. Gerraty 				throw new Exception(String.Format(
1384*0957b409SSimon J. Gerraty 					"EOF reached before U+{0:X4}", ct));
1385*0957b409SSimon J. Gerraty 			}
1386*0957b409SSimon J. Gerraty 			if (c == ct) {
1387*0957b409SSimon J. Gerraty 				return sb.ToString();
1388*0957b409SSimon J. Gerraty 			}
1389*0957b409SSimon J. Gerraty 			sb.Append((char)c);
1390*0957b409SSimon J. Gerraty 		}
1391*0957b409SSimon J. Gerraty 	}
1392*0957b409SSimon J. Gerraty 
IsWS(int c)1393*0957b409SSimon J. Gerraty 	static bool IsWS(int c)
1394*0957b409SSimon J. Gerraty 	{
1395*0957b409SSimon J. Gerraty 		return c <= 32;
1396*0957b409SSimon J. Gerraty 	}
1397*0957b409SSimon J. Gerraty 
ProcessInput(TextReader tr)1398*0957b409SSimon J. Gerraty 	void ProcessInput(TextReader tr)
1399*0957b409SSimon J. Gerraty 	{
1400*0957b409SSimon J. Gerraty 		this.currentInput = tr;
1401*0957b409SSimon J. Gerraty 		delayedChar = -1;
1402*0957b409SSimon J. Gerraty 		Word w = new WordNative(this, "toplevel",
1403*0957b409SSimon J. Gerraty 			xcpu => { CompileStep(xcpu); });
1404*0957b409SSimon J. Gerraty 		CPU cpu = new CPU();
1405*0957b409SSimon J. Gerraty 		Opcode[] code = new Opcode[] {
1406*0957b409SSimon J. Gerraty 			new OpcodeCall(w),
1407*0957b409SSimon J. Gerraty 			new OpcodeJumpUncond(-2)
1408*0957b409SSimon J. Gerraty 		};
1409*0957b409SSimon J. Gerraty 		quitRunLoop = false;
1410*0957b409SSimon J. Gerraty 		cpu.Enter(code, 0);
1411*0957b409SSimon J. Gerraty 		for (;;) {
1412*0957b409SSimon J. Gerraty 			if (quitRunLoop) {
1413*0957b409SSimon J. Gerraty 				break;
1414*0957b409SSimon J. Gerraty 			}
1415*0957b409SSimon J. Gerraty 			Opcode op = cpu.ipBuf[cpu.ipOff ++];
1416*0957b409SSimon J. Gerraty 			op.Run(cpu);
1417*0957b409SSimon J. Gerraty 		}
1418*0957b409SSimon J. Gerraty 	}
1419*0957b409SSimon J. Gerraty 
CompileStep(CPU cpu)1420*0957b409SSimon J. Gerraty 	void CompileStep(CPU cpu)
1421*0957b409SSimon J. Gerraty 	{
1422*0957b409SSimon J. Gerraty 		string tt = Next();
1423*0957b409SSimon J. Gerraty 		if (tt == null) {
1424*0957b409SSimon J. Gerraty 			if (compiling) {
1425*0957b409SSimon J. Gerraty 				throw new Exception("EOF while compiling");
1426*0957b409SSimon J. Gerraty 			}
1427*0957b409SSimon J. Gerraty 			quitRunLoop = true;
1428*0957b409SSimon J. Gerraty 			return;
1429*0957b409SSimon J. Gerraty 		}
1430*0957b409SSimon J. Gerraty 		TValue v;
1431*0957b409SSimon J. Gerraty 		bool isVal = TryParseLiteral(tt, out v);
1432*0957b409SSimon J. Gerraty 		Word w = LookupNF(tt);
1433*0957b409SSimon J. Gerraty 		if (isVal && w != null) {
1434*0957b409SSimon J. Gerraty 			throw new Exception(String.Format(
1435*0957b409SSimon J. Gerraty 				"Ambiguous: both defined word and literal: {0}",
1436*0957b409SSimon J. Gerraty 				tt));
1437*0957b409SSimon J. Gerraty 		}
1438*0957b409SSimon J. Gerraty 		if (compiling) {
1439*0957b409SSimon J. Gerraty 			if (isVal) {
1440*0957b409SSimon J. Gerraty 				wordBuilder.Literal(v);
1441*0957b409SSimon J. Gerraty 			} else if (w != null) {
1442*0957b409SSimon J. Gerraty 				if (w.Immediate) {
1443*0957b409SSimon J. Gerraty 					w.Run(cpu);
1444*0957b409SSimon J. Gerraty 				} else {
1445*0957b409SSimon J. Gerraty 					wordBuilder.CallExt(w);
1446*0957b409SSimon J. Gerraty 				}
1447*0957b409SSimon J. Gerraty 			} else {
1448*0957b409SSimon J. Gerraty 				wordBuilder.Call(tt);
1449*0957b409SSimon J. Gerraty 			}
1450*0957b409SSimon J. Gerraty 		} else {
1451*0957b409SSimon J. Gerraty 			if (isVal) {
1452*0957b409SSimon J. Gerraty 				cpu.Push(v);
1453*0957b409SSimon J. Gerraty 			} else if (w != null) {
1454*0957b409SSimon J. Gerraty 				w.Run(cpu);
1455*0957b409SSimon J. Gerraty 			} else {
1456*0957b409SSimon J. Gerraty 				throw new Exception(String.Format(
1457*0957b409SSimon J. Gerraty 					"Unknown word: '{0}'", tt));
1458*0957b409SSimon J. Gerraty 			}
1459*0957b409SSimon J. Gerraty 		}
1460*0957b409SSimon J. Gerraty 	}
1461*0957b409SSimon J. Gerraty 
GetCCode(string name)1462*0957b409SSimon J. Gerraty 	string GetCCode(string name)
1463*0957b409SSimon J. Gerraty 	{
1464*0957b409SSimon J. Gerraty 		string ccode;
1465*0957b409SSimon J. Gerraty 		allCCode.TryGetValue(name, out ccode);
1466*0957b409SSimon J. Gerraty 		return ccode;
1467*0957b409SSimon J. Gerraty 	}
1468*0957b409SSimon J. Gerraty 
Generate(string outBase, string coreRun, params string[] entryPoints)1469*0957b409SSimon J. Gerraty 	void Generate(string outBase, string coreRun,
1470*0957b409SSimon J. Gerraty 		params string[] entryPoints)
1471*0957b409SSimon J. Gerraty 	{
1472*0957b409SSimon J. Gerraty 		/*
1473*0957b409SSimon J. Gerraty 		 * Gather all words that are part of the generated
1474*0957b409SSimon J. Gerraty 		 * code. This is done by exploring references
1475*0957b409SSimon J. Gerraty 		 * transitively. All such words are thus implicitly
1476*0957b409SSimon J. Gerraty 		 * resolved.
1477*0957b409SSimon J. Gerraty 		 */
1478*0957b409SSimon J. Gerraty 		IDictionary<string, Word> wordSet =
1479*0957b409SSimon J. Gerraty 			new SortedDictionary<string, Word>(
1480*0957b409SSimon J. Gerraty 				StringComparer.Ordinal);
1481*0957b409SSimon J. Gerraty 		Queue<Word> tx = new Queue<Word>();
1482*0957b409SSimon J. Gerraty 		foreach (string ep in entryPoints) {
1483*0957b409SSimon J. Gerraty 			if (wordSet.ContainsKey(ep)) {
1484*0957b409SSimon J. Gerraty 				continue;
1485*0957b409SSimon J. Gerraty 			}
1486*0957b409SSimon J. Gerraty 			Word w = Lookup(ep);
1487*0957b409SSimon J. Gerraty 			wordSet[w.Name] = w;
1488*0957b409SSimon J. Gerraty 			tx.Enqueue(w);
1489*0957b409SSimon J. Gerraty 		}
1490*0957b409SSimon J. Gerraty 		while (tx.Count > 0) {
1491*0957b409SSimon J. Gerraty 			Word w = tx.Dequeue();
1492*0957b409SSimon J. Gerraty 			foreach (Word w2 in w.GetReferences()) {
1493*0957b409SSimon J. Gerraty 				if (wordSet.ContainsKey(w2.Name)) {
1494*0957b409SSimon J. Gerraty 					continue;
1495*0957b409SSimon J. Gerraty 				}
1496*0957b409SSimon J. Gerraty 				wordSet[w2.Name] = w2;
1497*0957b409SSimon J. Gerraty 				tx.Enqueue(w2);
1498*0957b409SSimon J. Gerraty 			}
1499*0957b409SSimon J. Gerraty 		}
1500*0957b409SSimon J. Gerraty 
1501*0957b409SSimon J. Gerraty 		/*
1502*0957b409SSimon J. Gerraty 		 * Do flow analysis.
1503*0957b409SSimon J. Gerraty 		 */
1504*0957b409SSimon J. Gerraty 		if (enableFlowAnalysis) {
1505*0957b409SSimon J. Gerraty 			foreach (string ep in entryPoints) {
1506*0957b409SSimon J. Gerraty 				Word w = wordSet[ep];
1507*0957b409SSimon J. Gerraty 				w.AnalyseFlow();
1508*0957b409SSimon J. Gerraty 				Console.WriteLine("{0}: ds={1} rs={2}",
1509*0957b409SSimon J. Gerraty 					ep, w.MaxDataStack, w.MaxReturnStack);
1510*0957b409SSimon J. Gerraty 				if (w.MaxDataStack > dsLimit) {
1511*0957b409SSimon J. Gerraty 					throw new Exception("'" + ep
1512*0957b409SSimon J. Gerraty 						+ "' exceeds data stack limit");
1513*0957b409SSimon J. Gerraty 				}
1514*0957b409SSimon J. Gerraty 				if (w.MaxReturnStack > rsLimit) {
1515*0957b409SSimon J. Gerraty 					throw new Exception("'" + ep
1516*0957b409SSimon J. Gerraty 						+ "' exceeds return stack"
1517*0957b409SSimon J. Gerraty 						+ " limit");
1518*0957b409SSimon J. Gerraty 				}
1519*0957b409SSimon J. Gerraty 			}
1520*0957b409SSimon J. Gerraty 		}
1521*0957b409SSimon J. Gerraty 
1522*0957b409SSimon J. Gerraty 		/*
1523*0957b409SSimon J. Gerraty 		 * Gather referenced data areas and compute their
1524*0957b409SSimon J. Gerraty 		 * addresses in the generated data block. The address
1525*0957b409SSimon J. Gerraty 		 * 0 in the data block is unaffected so that no
1526*0957b409SSimon J. Gerraty 		 * valid runtime pointer is equal to null.
1527*0957b409SSimon J. Gerraty 		 */
1528*0957b409SSimon J. Gerraty 		IDictionary<long, ConstData> blocks =
1529*0957b409SSimon J. Gerraty 			new SortedDictionary<long, ConstData>();
1530*0957b409SSimon J. Gerraty 		foreach (Word w in wordSet.Values) {
1531*0957b409SSimon J. Gerraty 			foreach (ConstData cd in w.GetDataBlocks()) {
1532*0957b409SSimon J. Gerraty 				blocks[cd.ID] = cd;
1533*0957b409SSimon J. Gerraty 			}
1534*0957b409SSimon J. Gerraty 		}
1535*0957b409SSimon J. Gerraty 		int dataLen = 1;
1536*0957b409SSimon J. Gerraty 		foreach (ConstData cd in blocks.Values) {
1537*0957b409SSimon J. Gerraty 			cd.Address = dataLen;
1538*0957b409SSimon J. Gerraty 			dataLen += cd.Length;
1539*0957b409SSimon J. Gerraty 		}
1540*0957b409SSimon J. Gerraty 
1541*0957b409SSimon J. Gerraty 		/*
1542*0957b409SSimon J. Gerraty 		 * Generated code is a sequence of "slot numbers", each
1543*0957b409SSimon J. Gerraty 		 * referencing either a piece of explicit C code, or an
1544*0957b409SSimon J. Gerraty 		 * entry in the table of interpreted words.
1545*0957b409SSimon J. Gerraty 		 *
1546*0957b409SSimon J. Gerraty 		 * Opcodes other than "call" get the slots 0 to 6:
1547*0957b409SSimon J. Gerraty 		 *
1548*0957b409SSimon J. Gerraty 		 *   0   ret           no argument
1549*0957b409SSimon J. Gerraty 		 *   1   const         signed value
1550*0957b409SSimon J. Gerraty 		 *   2   get local     local number
1551*0957b409SSimon J. Gerraty 		 *   3   put local     local number
1552*0957b409SSimon J. Gerraty 		 *   4   jump          signed offset
1553*0957b409SSimon J. Gerraty 		 *   5   jump if       signed offset
1554*0957b409SSimon J. Gerraty 		 *   6   jump if not   signed offset
1555*0957b409SSimon J. Gerraty 		 *
1556*0957b409SSimon J. Gerraty 		 * The argument, if any, is in "7E" format: the value is
1557*0957b409SSimon J. Gerraty 		 * encoded in 7-bit chunk, with big-endian signed
1558*0957b409SSimon J. Gerraty 		 * convention. Each 7-bit chunk is encoded over one byte;
1559*0957b409SSimon J. Gerraty 		 * the upper bit is 1 for all chunks except the last one.
1560*0957b409SSimon J. Gerraty 		 *
1561*0957b409SSimon J. Gerraty 		 * Words with explicit C code get the slot numbers
1562*0957b409SSimon J. Gerraty 		 * immediately after 6. Interpreted words come afterwards.
1563*0957b409SSimon J. Gerraty 		 */
1564*0957b409SSimon J. Gerraty 		IDictionary<string, int> slots = new Dictionary<string, int>();
1565*0957b409SSimon J. Gerraty 		int curSlot = 7;
1566*0957b409SSimon J. Gerraty 
1567*0957b409SSimon J. Gerraty 		/*
1568*0957b409SSimon J. Gerraty 		 * Get explicit C code for words which have such code.
1569*0957b409SSimon J. Gerraty 		 * We use string equality on C code so that words with
1570*0957b409SSimon J. Gerraty 		 * identical implementations get merged.
1571*0957b409SSimon J. Gerraty 		 *
1572*0957b409SSimon J. Gerraty 		 * We also check that words with no explicit C code are
1573*0957b409SSimon J. Gerraty 		 * interpreted.
1574*0957b409SSimon J. Gerraty 		 */
1575*0957b409SSimon J. Gerraty 		IDictionary<string, int> ccodeUni =
1576*0957b409SSimon J. Gerraty 			new Dictionary<string, int>();
1577*0957b409SSimon J. Gerraty 		IDictionary<int, string> ccodeNames =
1578*0957b409SSimon J. Gerraty 			new Dictionary<int, string>();
1579*0957b409SSimon J. Gerraty 		foreach (Word w in wordSet.Values) {
1580*0957b409SSimon J. Gerraty 			string ccode = GetCCode(w.Name);
1581*0957b409SSimon J. Gerraty 			if (ccode == null) {
1582*0957b409SSimon J. Gerraty 				if (w is WordNative) {
1583*0957b409SSimon J. Gerraty 					throw new Exception(String.Format(
1584*0957b409SSimon J. Gerraty 						"No C code for native '{0}'",
1585*0957b409SSimon J. Gerraty 						w.Name));
1586*0957b409SSimon J. Gerraty 				}
1587*0957b409SSimon J. Gerraty 				continue;
1588*0957b409SSimon J. Gerraty 			}
1589*0957b409SSimon J. Gerraty 			int sn;
1590*0957b409SSimon J. Gerraty 			if (ccodeUni.ContainsKey(ccode)) {
1591*0957b409SSimon J. Gerraty 				sn = ccodeUni[ccode];
1592*0957b409SSimon J. Gerraty 				ccodeNames[sn] += " " + EscapeCComment(w.Name);
1593*0957b409SSimon J. Gerraty 			} else {
1594*0957b409SSimon J. Gerraty 				sn = curSlot ++;
1595*0957b409SSimon J. Gerraty 				ccodeUni[ccode] = sn;
1596*0957b409SSimon J. Gerraty 				ccodeNames[sn] = EscapeCComment(w.Name);
1597*0957b409SSimon J. Gerraty 			}
1598*0957b409SSimon J. Gerraty 			slots[w.Name] = sn;
1599*0957b409SSimon J. Gerraty 			w.Slot = sn;
1600*0957b409SSimon J. Gerraty 		}
1601*0957b409SSimon J. Gerraty 
1602*0957b409SSimon J. Gerraty 		/*
1603*0957b409SSimon J. Gerraty 		 * Assign slot values to all remaining words; we know they
1604*0957b409SSimon J. Gerraty 		 * are all interpreted.
1605*0957b409SSimon J. Gerraty 		 */
1606*0957b409SSimon J. Gerraty 		int slotInterpreted = curSlot;
1607*0957b409SSimon J. Gerraty 		foreach (Word w in wordSet.Values) {
1608*0957b409SSimon J. Gerraty 			if (GetCCode(w.Name) != null) {
1609*0957b409SSimon J. Gerraty 				continue;
1610*0957b409SSimon J. Gerraty 			}
1611*0957b409SSimon J. Gerraty 			int sn = curSlot ++;
1612*0957b409SSimon J. Gerraty 			slots[w.Name] = sn;
1613*0957b409SSimon J. Gerraty 			w.Slot = sn;
1614*0957b409SSimon J. Gerraty 		}
1615*0957b409SSimon J. Gerraty 		int numInterpreted = curSlot - slotInterpreted;
1616*0957b409SSimon J. Gerraty 
1617*0957b409SSimon J. Gerraty 		/*
1618*0957b409SSimon J. Gerraty 		 * Verify that all entry points are interpreted words.
1619*0957b409SSimon J. Gerraty 		 */
1620*0957b409SSimon J. Gerraty 		foreach (string ep in entryPoints) {
1621*0957b409SSimon J. Gerraty 			if (GetCCode(ep) != null) {
1622*0957b409SSimon J. Gerraty 				throw new Exception(
1623*0957b409SSimon J. Gerraty 					"Non-interpreted entry point");
1624*0957b409SSimon J. Gerraty 			}
1625*0957b409SSimon J. Gerraty 		}
1626*0957b409SSimon J. Gerraty 
1627*0957b409SSimon J. Gerraty 		/*
1628*0957b409SSimon J. Gerraty 		 * Compute the code block. Each word (without any C code)
1629*0957b409SSimon J. Gerraty 		 * yields some CodeElement instances.
1630*0957b409SSimon J. Gerraty 		 */
1631*0957b409SSimon J. Gerraty 		List<CodeElement> gcodeList = new List<CodeElement>();
1632*0957b409SSimon J. Gerraty 		CodeElement[] interpretedEntry =
1633*0957b409SSimon J. Gerraty 			new CodeElement[numInterpreted];
1634*0957b409SSimon J. Gerraty 		foreach (Word w in wordSet.Values) {
1635*0957b409SSimon J. Gerraty 			if (GetCCode(w.Name) != null) {
1636*0957b409SSimon J. Gerraty 				continue;
1637*0957b409SSimon J. Gerraty 			}
1638*0957b409SSimon J. Gerraty 			int n = gcodeList.Count;
1639*0957b409SSimon J. Gerraty 			w.GenerateCodeElements(gcodeList);
1640*0957b409SSimon J. Gerraty 			interpretedEntry[w.Slot - slotInterpreted] =
1641*0957b409SSimon J. Gerraty 				gcodeList[n];
1642*0957b409SSimon J. Gerraty 		}
1643*0957b409SSimon J. Gerraty 		CodeElement[] gcode = gcodeList.ToArray();
1644*0957b409SSimon J. Gerraty 
1645*0957b409SSimon J. Gerraty 		/*
1646*0957b409SSimon J. Gerraty 		 * If there are less than 256 words in total (C +
1647*0957b409SSimon J. Gerraty 		 * interpreted) then we can use "one-byte code" which is
1648*0957b409SSimon J. Gerraty 		 * more compact when the number of words is in the
1649*0957b409SSimon J. Gerraty 		 * 128..255 range.
1650*0957b409SSimon J. Gerraty 		 */
1651*0957b409SSimon J. Gerraty 		bool oneByteCode;
1652*0957b409SSimon J. Gerraty 		if (slotInterpreted + numInterpreted >= 256) {
1653*0957b409SSimon J. Gerraty 			Console.WriteLine("WARNING: more than 255 words");
1654*0957b409SSimon J. Gerraty 			oneByteCode = false;
1655*0957b409SSimon J. Gerraty 		} else {
1656*0957b409SSimon J. Gerraty 			oneByteCode = true;
1657*0957b409SSimon J. Gerraty 		}
1658*0957b409SSimon J. Gerraty 
1659*0957b409SSimon J. Gerraty 		/*
1660*0957b409SSimon J. Gerraty 		 * Compute all addresses and offsets. This loops until
1661*0957b409SSimon J. Gerraty 		 * the addresses stabilize.
1662*0957b409SSimon J. Gerraty 		 */
1663*0957b409SSimon J. Gerraty 		int totalLen = -1;
1664*0957b409SSimon J. Gerraty 		int[] gcodeLen = new int[gcode.Length];
1665*0957b409SSimon J. Gerraty 		for (;;) {
1666*0957b409SSimon J. Gerraty 			for (int i = 0; i < gcode.Length; i ++) {
1667*0957b409SSimon J. Gerraty 				gcodeLen[i] = gcode[i].GetLength(oneByteCode);
1668*0957b409SSimon J. Gerraty 			}
1669*0957b409SSimon J. Gerraty 			int off = 0;
1670*0957b409SSimon J. Gerraty 			for (int i = 0; i < gcode.Length; i ++) {
1671*0957b409SSimon J. Gerraty 				gcode[i].Address = off;
1672*0957b409SSimon J. Gerraty 				gcode[i].LastLength = gcodeLen[i];
1673*0957b409SSimon J. Gerraty 				off += gcodeLen[i];
1674*0957b409SSimon J. Gerraty 			}
1675*0957b409SSimon J. Gerraty 			if (off == totalLen) {
1676*0957b409SSimon J. Gerraty 				break;
1677*0957b409SSimon J. Gerraty 			}
1678*0957b409SSimon J. Gerraty 			totalLen = off;
1679*0957b409SSimon J. Gerraty 		}
1680*0957b409SSimon J. Gerraty 
1681*0957b409SSimon J. Gerraty 		/*
1682*0957b409SSimon J. Gerraty 		 * Produce output file.
1683*0957b409SSimon J. Gerraty 		 */
1684*0957b409SSimon J. Gerraty 		using (TextWriter tw = File.CreateText(outBase + ".c")) {
1685*0957b409SSimon J. Gerraty 			tw.NewLine = "\n";
1686*0957b409SSimon J. Gerraty 
1687*0957b409SSimon J. Gerraty 			tw.WriteLine("{0}",
1688*0957b409SSimon J. Gerraty @"/* Automatically generated code; do not modify directly. */
1689*0957b409SSimon J. Gerraty 
1690*0957b409SSimon J. Gerraty #include <stddef.h>
1691*0957b409SSimon J. Gerraty #include <stdint.h>
1692*0957b409SSimon J. Gerraty 
1693*0957b409SSimon J. Gerraty typedef struct {
1694*0957b409SSimon J. Gerraty 	uint32_t *dp;
1695*0957b409SSimon J. Gerraty 	uint32_t *rp;
1696*0957b409SSimon J. Gerraty 	const unsigned char *ip;
1697*0957b409SSimon J. Gerraty } t0_context;
1698*0957b409SSimon J. Gerraty 
1699*0957b409SSimon J. Gerraty static uint32_t
1700*0957b409SSimon J. Gerraty t0_parse7E_unsigned(const unsigned char **p)
1701*0957b409SSimon J. Gerraty {
1702*0957b409SSimon J. Gerraty 	uint32_t x;
1703*0957b409SSimon J. Gerraty 
1704*0957b409SSimon J. Gerraty 	x = 0;
1705*0957b409SSimon J. Gerraty 	for (;;) {
1706*0957b409SSimon J. Gerraty 		unsigned y;
1707*0957b409SSimon J. Gerraty 
1708*0957b409SSimon J. Gerraty 		y = *(*p) ++;
1709*0957b409SSimon J. Gerraty 		x = (x << 7) | (uint32_t)(y & 0x7F);
1710*0957b409SSimon J. Gerraty 		if (y < 0x80) {
1711*0957b409SSimon J. Gerraty 			return x;
1712*0957b409SSimon J. Gerraty 		}
1713*0957b409SSimon J. Gerraty 	}
1714*0957b409SSimon J. Gerraty }
1715*0957b409SSimon J. Gerraty 
1716*0957b409SSimon J. Gerraty static int32_t
1717*0957b409SSimon J. Gerraty t0_parse7E_signed(const unsigned char **p)
1718*0957b409SSimon J. Gerraty {
1719*0957b409SSimon J. Gerraty 	int neg;
1720*0957b409SSimon J. Gerraty 	uint32_t x;
1721*0957b409SSimon J. Gerraty 
1722*0957b409SSimon J. Gerraty 	neg = ((**p) >> 6) & 1;
1723*0957b409SSimon J. Gerraty 	x = (uint32_t)-neg;
1724*0957b409SSimon J. Gerraty 	for (;;) {
1725*0957b409SSimon J. Gerraty 		unsigned y;
1726*0957b409SSimon J. Gerraty 
1727*0957b409SSimon J. Gerraty 		y = *(*p) ++;
1728*0957b409SSimon J. Gerraty 		x = (x << 7) | (uint32_t)(y & 0x7F);
1729*0957b409SSimon J. Gerraty 		if (y < 0x80) {
1730*0957b409SSimon J. Gerraty 			if (neg) {
1731*0957b409SSimon J. Gerraty 				return -(int32_t)~x - 1;
1732*0957b409SSimon J. Gerraty 			} else {
1733*0957b409SSimon J. Gerraty 				return (int32_t)x;
1734*0957b409SSimon J. Gerraty 			}
1735*0957b409SSimon J. Gerraty 		}
1736*0957b409SSimon J. Gerraty 	}
1737*0957b409SSimon J. Gerraty }
1738*0957b409SSimon J. Gerraty 
1739*0957b409SSimon J. Gerraty #define T0_VBYTE(x, n)   (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
1740*0957b409SSimon J. Gerraty #define T0_FBYTE(x, n)   (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
1741*0957b409SSimon J. Gerraty #define T0_SBYTE(x)      (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
1742*0957b409SSimon J. Gerraty #define T0_INT1(x)       T0_FBYTE(x, 0)
1743*0957b409SSimon J. Gerraty #define T0_INT2(x)       T0_VBYTE(x, 7), T0_FBYTE(x, 0)
1744*0957b409SSimon J. Gerraty #define T0_INT3(x)       T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
1745*0957b409SSimon J. Gerraty #define T0_INT4(x)       T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
1746*0957b409SSimon J. Gerraty #define T0_INT5(x)       T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
1747*0957b409SSimon J. Gerraty 
1748*0957b409SSimon J. Gerraty /* static const unsigned char t0_datablock[]; */
1749*0957b409SSimon J. Gerraty ");
1750*0957b409SSimon J. Gerraty 
1751*0957b409SSimon J. Gerraty 			/*
1752*0957b409SSimon J. Gerraty 			 * Add declarations (not definitions) for the
1753*0957b409SSimon J. Gerraty 			 * entry point initialisation functions, and the
1754*0957b409SSimon J. Gerraty 			 * runner.
1755*0957b409SSimon J. Gerraty 			 */
1756*0957b409SSimon J. Gerraty 			tw.WriteLine();
1757*0957b409SSimon J. Gerraty 			foreach (string ep in entryPoints) {
1758*0957b409SSimon J. Gerraty 				tw.WriteLine("void {0}_init_{1}(void *t0ctx);",
1759*0957b409SSimon J. Gerraty 					coreRun, ep);
1760*0957b409SSimon J. Gerraty 			}
1761*0957b409SSimon J. Gerraty 			tw.WriteLine();
1762*0957b409SSimon J. Gerraty 			tw.WriteLine("void {0}_run(void *t0ctx);", coreRun);
1763*0957b409SSimon J. Gerraty 
1764*0957b409SSimon J. Gerraty 			/*
1765*0957b409SSimon J. Gerraty 			 * Add preamble elements here. They may be needed
1766*0957b409SSimon J. Gerraty 			 * for evaluating constant expressions in the
1767*0957b409SSimon J. Gerraty 			 * code block.
1768*0957b409SSimon J. Gerraty 			 */
1769*0957b409SSimon J. Gerraty 			foreach (string pp in extraCode) {
1770*0957b409SSimon J. Gerraty 				tw.WriteLine();
1771*0957b409SSimon J. Gerraty 				tw.WriteLine("{0}", pp);
1772*0957b409SSimon J. Gerraty 			}
1773*0957b409SSimon J. Gerraty 
1774*0957b409SSimon J. Gerraty 			BlobWriter bw;
1775*0957b409SSimon J. Gerraty 			tw.WriteLine();
1776*0957b409SSimon J. Gerraty 			tw.Write("static const unsigned char"
1777*0957b409SSimon J. Gerraty 				+ " t0_datablock[] = {");
1778*0957b409SSimon J. Gerraty 			bw = new BlobWriter(tw, 78, 1);
1779*0957b409SSimon J. Gerraty 			bw.Append((byte)0);
1780*0957b409SSimon J. Gerraty 			foreach (ConstData cd in blocks.Values) {
1781*0957b409SSimon J. Gerraty 				cd.Encode(bw);
1782*0957b409SSimon J. Gerraty 			}
1783*0957b409SSimon J. Gerraty 			tw.WriteLine();
1784*0957b409SSimon J. Gerraty 			tw.WriteLine("};");
1785*0957b409SSimon J. Gerraty 
1786*0957b409SSimon J. Gerraty 			tw.WriteLine();
1787*0957b409SSimon J. Gerraty 			tw.Write("static const unsigned char"
1788*0957b409SSimon J. Gerraty 				+ " t0_codeblock[] = {");
1789*0957b409SSimon J. Gerraty 			bw = new BlobWriter(tw, 78, 1);
1790*0957b409SSimon J. Gerraty 			foreach (CodeElement ce in gcode) {
1791*0957b409SSimon J. Gerraty 				ce.Encode(bw, oneByteCode);
1792*0957b409SSimon J. Gerraty 			}
1793*0957b409SSimon J. Gerraty 			tw.WriteLine();
1794*0957b409SSimon J. Gerraty 			tw.WriteLine("};");
1795*0957b409SSimon J. Gerraty 
1796*0957b409SSimon J. Gerraty 			tw.WriteLine();
1797*0957b409SSimon J. Gerraty 			tw.Write("static const uint16_t t0_caddr[] = {");
1798*0957b409SSimon J. Gerraty 			for (int i = 0; i < interpretedEntry.Length; i ++) {
1799*0957b409SSimon J. Gerraty 				if (i != 0) {
1800*0957b409SSimon J. Gerraty 					tw.Write(',');
1801*0957b409SSimon J. Gerraty 				}
1802*0957b409SSimon J. Gerraty 				tw.WriteLine();
1803*0957b409SSimon J. Gerraty 				tw.Write("\t{0}", interpretedEntry[i].Address);
1804*0957b409SSimon J. Gerraty 			}
1805*0957b409SSimon J. Gerraty 			tw.WriteLine();
1806*0957b409SSimon J. Gerraty 			tw.WriteLine("};");
1807*0957b409SSimon J. Gerraty 
1808*0957b409SSimon J. Gerraty 			tw.WriteLine();
1809*0957b409SSimon J. Gerraty 			tw.WriteLine("#define T0_INTERPRETED   {0}",
1810*0957b409SSimon J. Gerraty 				slotInterpreted);
1811*0957b409SSimon J. Gerraty 			tw.WriteLine();
1812*0957b409SSimon J. Gerraty 			tw.WriteLine("{0}",
1813*0957b409SSimon J. Gerraty @"#define T0_ENTER(ip, rp, slot)   do { \
1814*0957b409SSimon J. Gerraty 		const unsigned char *t0_newip; \
1815*0957b409SSimon J. Gerraty 		uint32_t t0_lnum; \
1816*0957b409SSimon J. Gerraty 		t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
1817*0957b409SSimon J. Gerraty 		t0_lnum = t0_parse7E_unsigned(&t0_newip); \
1818*0957b409SSimon J. Gerraty 		(rp) += t0_lnum; \
1819*0957b409SSimon J. Gerraty 		*((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
1820*0957b409SSimon J. Gerraty 		(ip) = t0_newip; \
1821*0957b409SSimon J. Gerraty 	} while (0)");
1822*0957b409SSimon J. Gerraty 			tw.WriteLine();
1823*0957b409SSimon J. Gerraty 			tw.WriteLine("{0}",
1824*0957b409SSimon J. Gerraty @"#define T0_DEFENTRY(name, slot) \
1825*0957b409SSimon J. Gerraty void \
1826*0957b409SSimon J. Gerraty name(void *ctx) \
1827*0957b409SSimon J. Gerraty { \
1828*0957b409SSimon J. Gerraty 	t0_context *t0ctx = ctx; \
1829*0957b409SSimon J. Gerraty 	t0ctx->ip = &t0_codeblock[0]; \
1830*0957b409SSimon J. Gerraty 	T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
1831*0957b409SSimon J. Gerraty }");
1832*0957b409SSimon J. Gerraty 
1833*0957b409SSimon J. Gerraty 			tw.WriteLine();
1834*0957b409SSimon J. Gerraty 			foreach (string ep in entryPoints) {
1835*0957b409SSimon J. Gerraty 				tw.WriteLine("T0_DEFENTRY({0}, {1})",
1836*0957b409SSimon J. Gerraty 					coreRun + "_init_" + ep,
1837*0957b409SSimon J. Gerraty 					wordSet[ep].Slot);
1838*0957b409SSimon J. Gerraty 			}
1839*0957b409SSimon J. Gerraty 			tw.WriteLine();
1840*0957b409SSimon J. Gerraty 			if (oneByteCode) {
1841*0957b409SSimon J. Gerraty 				tw.WriteLine("{0}",
1842*0957b409SSimon J. Gerraty @"#define T0_NEXT(t0ipp)   (*(*(t0ipp)) ++)");
1843*0957b409SSimon J. Gerraty 			} else {
1844*0957b409SSimon J. Gerraty 				tw.WriteLine("{0}",
1845*0957b409SSimon J. Gerraty @"#define T0_NEXT(t0ipp)   t0_parse7E_unsigned(t0ipp)");
1846*0957b409SSimon J. Gerraty 			}
1847*0957b409SSimon J. Gerraty 			tw.WriteLine();
1848*0957b409SSimon J. Gerraty 			tw.WriteLine("void");
1849*0957b409SSimon J. Gerraty 			tw.WriteLine("{0}_run(void *t0ctx)", coreRun);
1850*0957b409SSimon J. Gerraty 			tw.WriteLine("{0}",
1851*0957b409SSimon J. Gerraty @"{
1852*0957b409SSimon J. Gerraty 	uint32_t *dp, *rp;
1853*0957b409SSimon J. Gerraty 	const unsigned char *ip;
1854*0957b409SSimon J. Gerraty 
1855*0957b409SSimon J. Gerraty #define T0_LOCAL(x)    (*(rp - 2 - (x)))
1856*0957b409SSimon J. Gerraty #define T0_POP()       (*-- dp)
1857*0957b409SSimon J. Gerraty #define T0_POPi()      (*(int32_t *)(-- dp))
1858*0957b409SSimon J. Gerraty #define T0_PEEK(x)     (*(dp - 1 - (x)))
1859*0957b409SSimon J. Gerraty #define T0_PEEKi(x)    (*(int32_t *)(dp - 1 - (x)))
1860*0957b409SSimon J. Gerraty #define T0_PUSH(v)     do { *dp = (v); dp ++; } while (0)
1861*0957b409SSimon J. Gerraty #define T0_PUSHi(v)    do { *(int32_t *)dp = (v); dp ++; } while (0)
1862*0957b409SSimon J. Gerraty #define T0_RPOP()      (*-- rp)
1863*0957b409SSimon J. Gerraty #define T0_RPOPi()     (*(int32_t *)(-- rp))
1864*0957b409SSimon J. Gerraty #define T0_RPUSH(v)    do { *rp = (v); rp ++; } while (0)
1865*0957b409SSimon J. Gerraty #define T0_RPUSHi(v)   do { *(int32_t *)rp = (v); rp ++; } while (0)
1866*0957b409SSimon J. Gerraty #define T0_ROLL(x)     do { \
1867*0957b409SSimon J. Gerraty 	size_t t0len = (size_t)(x); \
1868*0957b409SSimon J. Gerraty 	uint32_t t0tmp = *(dp - 1 - t0len); \
1869*0957b409SSimon J. Gerraty 	memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
1870*0957b409SSimon J. Gerraty 	*(dp - 1) = t0tmp; \
1871*0957b409SSimon J. Gerraty } while (0)
1872*0957b409SSimon J. Gerraty #define T0_SWAP()      do { \
1873*0957b409SSimon J. Gerraty 	uint32_t t0tmp = *(dp - 2); \
1874*0957b409SSimon J. Gerraty 	*(dp - 2) = *(dp - 1); \
1875*0957b409SSimon J. Gerraty 	*(dp - 1) = t0tmp; \
1876*0957b409SSimon J. Gerraty } while (0)
1877*0957b409SSimon J. Gerraty #define T0_ROT()       do { \
1878*0957b409SSimon J. Gerraty 	uint32_t t0tmp = *(dp - 3); \
1879*0957b409SSimon J. Gerraty 	*(dp - 3) = *(dp - 2); \
1880*0957b409SSimon J. Gerraty 	*(dp - 2) = *(dp - 1); \
1881*0957b409SSimon J. Gerraty 	*(dp - 1) = t0tmp; \
1882*0957b409SSimon J. Gerraty } while (0)
1883*0957b409SSimon J. Gerraty #define T0_NROT()       do { \
1884*0957b409SSimon J. Gerraty 	uint32_t t0tmp = *(dp - 1); \
1885*0957b409SSimon J. Gerraty 	*(dp - 1) = *(dp - 2); \
1886*0957b409SSimon J. Gerraty 	*(dp - 2) = *(dp - 3); \
1887*0957b409SSimon J. Gerraty 	*(dp - 3) = t0tmp; \
1888*0957b409SSimon J. Gerraty } while (0)
1889*0957b409SSimon J. Gerraty #define T0_PICK(x)      do { \
1890*0957b409SSimon J. Gerraty 	uint32_t t0depth = (x); \
1891*0957b409SSimon J. Gerraty 	T0_PUSH(T0_PEEK(t0depth)); \
1892*0957b409SSimon J. Gerraty } while (0)
1893*0957b409SSimon J. Gerraty #define T0_CO()         do { \
1894*0957b409SSimon J. Gerraty 	goto t0_exit; \
1895*0957b409SSimon J. Gerraty } while (0)
1896*0957b409SSimon J. Gerraty #define T0_RET()        goto t0_next
1897*0957b409SSimon J. Gerraty 
1898*0957b409SSimon J. Gerraty 	dp = ((t0_context *)t0ctx)->dp;
1899*0957b409SSimon J. Gerraty 	rp = ((t0_context *)t0ctx)->rp;
1900*0957b409SSimon J. Gerraty 	ip = ((t0_context *)t0ctx)->ip;
1901*0957b409SSimon J. Gerraty 	goto t0_next;
1902*0957b409SSimon J. Gerraty 	for (;;) {
1903*0957b409SSimon J. Gerraty 		uint32_t t0x;
1904*0957b409SSimon J. Gerraty 
1905*0957b409SSimon J. Gerraty 	t0_next:
1906*0957b409SSimon J. Gerraty 		t0x = T0_NEXT(&ip);
1907*0957b409SSimon J. Gerraty 		if (t0x < T0_INTERPRETED) {
1908*0957b409SSimon J. Gerraty 			switch (t0x) {
1909*0957b409SSimon J. Gerraty 				int32_t t0off;
1910*0957b409SSimon J. Gerraty 
1911*0957b409SSimon J. Gerraty 			case 0: /* ret */
1912*0957b409SSimon J. Gerraty 				t0x = T0_RPOP();
1913*0957b409SSimon J. Gerraty 				rp -= (t0x >> 16);
1914*0957b409SSimon J. Gerraty 				t0x &= 0xFFFF;
1915*0957b409SSimon J. Gerraty 				if (t0x == 0) {
1916*0957b409SSimon J. Gerraty 					ip = NULL;
1917*0957b409SSimon J. Gerraty 					goto t0_exit;
1918*0957b409SSimon J. Gerraty 				}
1919*0957b409SSimon J. Gerraty 				ip = &t0_codeblock[t0x];
1920*0957b409SSimon J. Gerraty 				break;
1921*0957b409SSimon J. Gerraty 			case 1: /* literal constant */
1922*0957b409SSimon J. Gerraty 				T0_PUSHi(t0_parse7E_signed(&ip));
1923*0957b409SSimon J. Gerraty 				break;
1924*0957b409SSimon J. Gerraty 			case 2: /* read local */
1925*0957b409SSimon J. Gerraty 				T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
1926*0957b409SSimon J. Gerraty 				break;
1927*0957b409SSimon J. Gerraty 			case 3: /* write local */
1928*0957b409SSimon J. Gerraty 				T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
1929*0957b409SSimon J. Gerraty 				break;
1930*0957b409SSimon J. Gerraty 			case 4: /* jump */
1931*0957b409SSimon J. Gerraty 				t0off = t0_parse7E_signed(&ip);
1932*0957b409SSimon J. Gerraty 				ip += t0off;
1933*0957b409SSimon J. Gerraty 				break;
1934*0957b409SSimon J. Gerraty 			case 5: /* jump if */
1935*0957b409SSimon J. Gerraty 				t0off = t0_parse7E_signed(&ip);
1936*0957b409SSimon J. Gerraty 				if (T0_POP()) {
1937*0957b409SSimon J. Gerraty 					ip += t0off;
1938*0957b409SSimon J. Gerraty 				}
1939*0957b409SSimon J. Gerraty 				break;
1940*0957b409SSimon J. Gerraty 			case 6: /* jump if not */
1941*0957b409SSimon J. Gerraty 				t0off = t0_parse7E_signed(&ip);
1942*0957b409SSimon J. Gerraty 				if (!T0_POP()) {
1943*0957b409SSimon J. Gerraty 					ip += t0off;
1944*0957b409SSimon J. Gerraty 				}
1945*0957b409SSimon J. Gerraty 				break;");
1946*0957b409SSimon J. Gerraty 
1947*0957b409SSimon J. Gerraty 			SortedDictionary<int, string> nccode =
1948*0957b409SSimon J. Gerraty 				new SortedDictionary<int, string>();
1949*0957b409SSimon J. Gerraty 			foreach (string k in ccodeUni.Keys) {
1950*0957b409SSimon J. Gerraty 				nccode[ccodeUni[k]] = k;
1951*0957b409SSimon J. Gerraty 			}
1952*0957b409SSimon J. Gerraty 			foreach (int sn in nccode.Keys) {
1953*0957b409SSimon J. Gerraty 				tw.WriteLine(
1954*0957b409SSimon J. Gerraty @"			case {0}: {{
1955*0957b409SSimon J. Gerraty 				/* {1} */
1956*0957b409SSimon J. Gerraty {2}
1957*0957b409SSimon J. Gerraty 				}}
1958*0957b409SSimon J. Gerraty 				break;", sn, ccodeNames[sn], nccode[sn]);
1959*0957b409SSimon J. Gerraty 			}
1960*0957b409SSimon J. Gerraty 
1961*0957b409SSimon J. Gerraty 			tw.WriteLine(
1962*0957b409SSimon J. Gerraty @"			}
1963*0957b409SSimon J. Gerraty 
1964*0957b409SSimon J. Gerraty 		} else {
1965*0957b409SSimon J. Gerraty 			T0_ENTER(ip, rp, t0x);
1966*0957b409SSimon J. Gerraty 		}
1967*0957b409SSimon J. Gerraty 	}
1968*0957b409SSimon J. Gerraty t0_exit:
1969*0957b409SSimon J. Gerraty 	((t0_context *)t0ctx)->dp = dp;
1970*0957b409SSimon J. Gerraty 	((t0_context *)t0ctx)->rp = rp;
1971*0957b409SSimon J. Gerraty 	((t0_context *)t0ctx)->ip = ip;
1972*0957b409SSimon J. Gerraty }");
1973*0957b409SSimon J. Gerraty 
1974*0957b409SSimon J. Gerraty 			/*
1975*0957b409SSimon J. Gerraty 			 * Add the "postamblr" elements here. These are
1976*0957b409SSimon J. Gerraty 			 * elements that may need access to the data
1977*0957b409SSimon J. Gerraty 			 * block or code block, so they must occur after
1978*0957b409SSimon J. Gerraty 			 * their definition.
1979*0957b409SSimon J. Gerraty 			 */
1980*0957b409SSimon J. Gerraty 			foreach (string pp in extraCodeDefer) {
1981*0957b409SSimon J. Gerraty 				tw.WriteLine();
1982*0957b409SSimon J. Gerraty 				tw.WriteLine("{0}", pp);
1983*0957b409SSimon J. Gerraty 			}
1984*0957b409SSimon J. Gerraty 		}
1985*0957b409SSimon J. Gerraty 
1986*0957b409SSimon J. Gerraty 		int codeLen = 0;
1987*0957b409SSimon J. Gerraty 		foreach (CodeElement ce in gcode) {
1988*0957b409SSimon J. Gerraty 			codeLen += ce.GetLength(oneByteCode);
1989*0957b409SSimon J. Gerraty 		}
1990*0957b409SSimon J. Gerraty 		int dataBlockLen = 0;
1991*0957b409SSimon J. Gerraty 		foreach (ConstData cd in blocks.Values) {
1992*0957b409SSimon J. Gerraty 			dataBlockLen += cd.Length;
1993*0957b409SSimon J. Gerraty 		}
1994*0957b409SSimon J. Gerraty 
1995*0957b409SSimon J. Gerraty 		/*
1996*0957b409SSimon J. Gerraty 		 * Write some statistics on produced code.
1997*0957b409SSimon J. Gerraty 		 */
1998*0957b409SSimon J. Gerraty 		Console.WriteLine("code length: {0,6} byte(s)", codeLen);
1999*0957b409SSimon J. Gerraty 		Console.WriteLine("data length: {0,6} byte(s)", dataLen);
2000*0957b409SSimon J. Gerraty 		Console.WriteLine("total words: {0} (interpreted: {1})",
2001*0957b409SSimon J. Gerraty 			slotInterpreted + numInterpreted, numInterpreted);
2002*0957b409SSimon J. Gerraty 	}
2003*0957b409SSimon J. Gerraty 
Lookup(string name)2004*0957b409SSimon J. Gerraty 	internal Word Lookup(string name)
2005*0957b409SSimon J. Gerraty 	{
2006*0957b409SSimon J. Gerraty 		Word w = LookupNF(name);
2007*0957b409SSimon J. Gerraty 		if (w != null) {
2008*0957b409SSimon J. Gerraty 			return w;
2009*0957b409SSimon J. Gerraty 		}
2010*0957b409SSimon J. Gerraty 		throw new Exception(String.Format("No such word: '{0}'", name));
2011*0957b409SSimon J. Gerraty 	}
2012*0957b409SSimon J. Gerraty 
LookupNF(string name)2013*0957b409SSimon J. Gerraty 	internal Word LookupNF(string name)
2014*0957b409SSimon J. Gerraty 	{
2015*0957b409SSimon J. Gerraty 		Word w;
2016*0957b409SSimon J. Gerraty 		words.TryGetValue(name, out w);
2017*0957b409SSimon J. Gerraty 		return w;
2018*0957b409SSimon J. Gerraty 	}
2019*0957b409SSimon J. Gerraty 
StringToBlob(string s)2020*0957b409SSimon J. Gerraty 	internal TValue StringToBlob(string s)
2021*0957b409SSimon J. Gerraty 	{
2022*0957b409SSimon J. Gerraty 		return new TValue(0, new TPointerBlob(this, s));
2023*0957b409SSimon J. Gerraty 	}
2024*0957b409SSimon J. Gerraty 
TryParseLiteral(string tt, out TValue tv)2025*0957b409SSimon J. Gerraty 	internal bool TryParseLiteral(string tt, out TValue tv)
2026*0957b409SSimon J. Gerraty 	{
2027*0957b409SSimon J. Gerraty 		tv = new TValue(0);
2028*0957b409SSimon J. Gerraty 		if (tt.StartsWith("\"")) {
2029*0957b409SSimon J. Gerraty 			tv = StringToBlob(tt.Substring(1));
2030*0957b409SSimon J. Gerraty 			return true;
2031*0957b409SSimon J. Gerraty 		}
2032*0957b409SSimon J. Gerraty 		if (tt.StartsWith("`")) {
2033*0957b409SSimon J. Gerraty 			tv = DecodeCharConst(tt.Substring(1));
2034*0957b409SSimon J. Gerraty 			return true;
2035*0957b409SSimon J. Gerraty 		}
2036*0957b409SSimon J. Gerraty 		bool neg = false;
2037*0957b409SSimon J. Gerraty 		if (tt.StartsWith("-")) {
2038*0957b409SSimon J. Gerraty 			neg = true;
2039*0957b409SSimon J. Gerraty 			tt = tt.Substring(1);
2040*0957b409SSimon J. Gerraty 		} else if (tt.StartsWith("+")) {
2041*0957b409SSimon J. Gerraty 			tt = tt.Substring(1);
2042*0957b409SSimon J. Gerraty 		}
2043*0957b409SSimon J. Gerraty 		uint radix = 10;
2044*0957b409SSimon J. Gerraty 		if (tt.StartsWith("0x") || tt.StartsWith("0X")) {
2045*0957b409SSimon J. Gerraty 			radix = 16;
2046*0957b409SSimon J. Gerraty 			tt = tt.Substring(2);
2047*0957b409SSimon J. Gerraty 		} else if (tt.StartsWith("0b") || tt.StartsWith("0B")) {
2048*0957b409SSimon J. Gerraty 			radix = 2;
2049*0957b409SSimon J. Gerraty 			tt = tt.Substring(2);
2050*0957b409SSimon J. Gerraty 		}
2051*0957b409SSimon J. Gerraty 		if (tt.Length == 0) {
2052*0957b409SSimon J. Gerraty 			return false;
2053*0957b409SSimon J. Gerraty 		}
2054*0957b409SSimon J. Gerraty 		uint acc = 0;
2055*0957b409SSimon J. Gerraty 		bool overflow = false;
2056*0957b409SSimon J. Gerraty 		uint maxV = uint.MaxValue / radix;
2057*0957b409SSimon J. Gerraty 		foreach (char c in tt) {
2058*0957b409SSimon J. Gerraty 			int d = HexVal(c);
2059*0957b409SSimon J. Gerraty 			if (d < 0 || d >= radix) {
2060*0957b409SSimon J. Gerraty 				return false;
2061*0957b409SSimon J. Gerraty 			}
2062*0957b409SSimon J. Gerraty 			if (acc > maxV) {
2063*0957b409SSimon J. Gerraty 				overflow = true;
2064*0957b409SSimon J. Gerraty 			}
2065*0957b409SSimon J. Gerraty 			acc *= radix;
2066*0957b409SSimon J. Gerraty 			if ((uint)d > uint.MaxValue - acc) {
2067*0957b409SSimon J. Gerraty 				overflow = true;
2068*0957b409SSimon J. Gerraty 			}
2069*0957b409SSimon J. Gerraty 			acc += (uint)d;
2070*0957b409SSimon J. Gerraty 		}
2071*0957b409SSimon J. Gerraty 		int x = (int)acc;
2072*0957b409SSimon J. Gerraty 		if (neg) {
2073*0957b409SSimon J. Gerraty 			if (acc > (uint)0x80000000) {
2074*0957b409SSimon J. Gerraty 				overflow = true;
2075*0957b409SSimon J. Gerraty 			}
2076*0957b409SSimon J. Gerraty 			x = -x;
2077*0957b409SSimon J. Gerraty 		}
2078*0957b409SSimon J. Gerraty 		if (overflow) {
2079*0957b409SSimon J. Gerraty 			throw new Exception(
2080*0957b409SSimon J. Gerraty 				"invalid literal integer (overflow)");
2081*0957b409SSimon J. Gerraty 		}
2082*0957b409SSimon J. Gerraty 		tv = x;
2083*0957b409SSimon J. Gerraty 		return true;
2084*0957b409SSimon J. Gerraty 	}
2085*0957b409SSimon J. Gerraty 
ParseInteger(string tt)2086*0957b409SSimon J. Gerraty 	int ParseInteger(string tt)
2087*0957b409SSimon J. Gerraty 	{
2088*0957b409SSimon J. Gerraty 		TValue tv;
2089*0957b409SSimon J. Gerraty 		if (!TryParseLiteral(tt, out tv)) {
2090*0957b409SSimon J. Gerraty 			throw new Exception("not an integer: " + ToString());
2091*0957b409SSimon J. Gerraty 		}
2092*0957b409SSimon J. Gerraty 		return (int)tv;
2093*0957b409SSimon J. Gerraty 	}
2094*0957b409SSimon J. Gerraty 
CheckCompiling()2095*0957b409SSimon J. Gerraty 	void CheckCompiling()
2096*0957b409SSimon J. Gerraty 	{
2097*0957b409SSimon J. Gerraty 		if (!compiling) {
2098*0957b409SSimon J. Gerraty 			throw new Exception("Not in compilation mode");
2099*0957b409SSimon J. Gerraty 		}
2100*0957b409SSimon J. Gerraty 	}
2101*0957b409SSimon J. Gerraty 
EscapeCComment(string s)2102*0957b409SSimon J. Gerraty 	static string EscapeCComment(string s)
2103*0957b409SSimon J. Gerraty 	{
2104*0957b409SSimon J. Gerraty 		StringBuilder sb = new StringBuilder();
2105*0957b409SSimon J. Gerraty 		foreach (char c in s) {
2106*0957b409SSimon J. Gerraty 			if (c >= 33 && c <= 126 && c != '%') {
2107*0957b409SSimon J. Gerraty 				sb.Append(c);
2108*0957b409SSimon J. Gerraty 			} else if (c < 0x100) {
2109*0957b409SSimon J. Gerraty 				sb.AppendFormat("%{0:X2}", (int)c);
2110*0957b409SSimon J. Gerraty 			} else if (c < 0x800) {
2111*0957b409SSimon J. Gerraty 				sb.AppendFormat("%{0:X2}%{0:X2}",
2112*0957b409SSimon J. Gerraty 					((int)c >> 6) | 0xC0,
2113*0957b409SSimon J. Gerraty 					((int)c & 0x3F) | 0x80);
2114*0957b409SSimon J. Gerraty 			} else {
2115*0957b409SSimon J. Gerraty 				sb.AppendFormat("%{0:X2}%{0:X2}%{0:X2}",
2116*0957b409SSimon J. Gerraty 					((int)c >> 12) | 0xE0,
2117*0957b409SSimon J. Gerraty 					(((int)c >> 6) & 0x3F) | 0x80,
2118*0957b409SSimon J. Gerraty 					((int)c & 0x3F) | 0x80);
2119*0957b409SSimon J. Gerraty 			}
2120*0957b409SSimon J. Gerraty 		}
2121*0957b409SSimon J. Gerraty 		return sb.ToString().Replace("*/", "%2A/");
2122*0957b409SSimon J. Gerraty 	}
2123*0957b409SSimon J. Gerraty }
2124