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