public S2AScript(string script, string[] args, string type) { context = this; Console.WriteLine("Parsing script..."); try { ParseScriptInit("=type '" + type.ToLowerInvariant() + "'\n" + File.ReadAllText(script).Replace("\t", "").Replace("\r", ""), args, -1); } catch (Exception e) { error(e.ToString()); } }
// helper method to collect some variables used in conversion private void InitConvertVars() { try { // get global subscript endian = S2AScript.GetEquate("endian").val; offset = Parse.BasicUint(S2AScript.GetEquate("offset").val); if (debug) { Debug("--> InitConvertVars: endian=" + endian + " offset=" + toHexString(offset, 4)); } } catch (Exception e) { cvterror(null, new Exception("Missing equates when getting convert variables! Required equates are: 'endian' and 'offset'.", e).ToString()); } }
// function to calculate the optimized arrays of items or array items to quickly return items for certain types of requests public GenericScriptItem[] Optimize() { Optimized = new GenericScriptItem[0x100]; foreach (GenericScriptItem entry in Items) { switch (entry.type) { case ScriptItemType.NULL: screrr(entry.line, "Type of item is NULL! This is most likely a programming error in SMPS2ASM!"); break; case ScriptItemType.Equate: ScriptEquate eq = (entry as ScriptEquate); // only pre-calculated equates are possible to be used if (!eq.CheckEvaluate()) { S2AScript.screrr(entry.line, "Equates that are being optimized into a look-up-table must be possible to be pre-calculated! Equate with contents '" + eq.val + "' failed to be pre-calculated."); } // get offset int v; if (!Parse.DoubleToInt(GetEquate(eq.equ).value, out v)) { screrr(entry.line, "Equate value can not be accurately converted from double floating point to int! Equate with contents '" + eq.val + "' failed to be conveted to 32-bit signed integer."); } // save entry or throw error. if (Optimized[v] == null) { Optimized[v] = entry; } else { screrr(entry.line, "Entity " + entry.identifier + " conflicts with " + Optimized[v].identifier + " at line " + Optimized[v].line + ", both trying to occupy the value " + v + " (0x" + v.ToString("X2") + ")! Optimization requires no such conflicts."); } break; case ScriptItemType.Macro: ScriptMacro ma = (entry as ScriptMacro); // collect range int rangeStart, rangeEnd; if (!ma.GetRange(0, out rangeStart, out rangeEnd)) { S2AScript.screrr(entry.line, "Unable to parse first level macro range. Macro range of '" + (ma.pre.Length > 0 ? ma.pre[0] : "") + "' is not valid."); } // if true, there is only 1 level to this macro bool onlylevel = ma.pre.Length == 1; for (int i = rangeStart; i <= rangeEnd; i++) { if (onlylevel) { if (Optimized[i] == null) { Optimized[i] = ma; } else if (Optimized[i].type == ScriptItemType.ArrayItem) { (Optimized[i] as ScriptArrayItem).CombineFree(ma); } else { screrr(entry.line, "Entity " + entry.identifier + " conflicts with " + Optimized[i].identifier + " at line " + Optimized[i].line + ", both trying to occupy the value " + i + " (0x" + i.ToString("X2") + ")! Optimization requires no such conflicts."); } } else { if (Optimized[i] == null) { Optimized[i] = new ScriptArrayItem(parent); (Optimized[i] as ScriptArrayItem).Combine(ma, 1); } else if (Optimized[i].type == ScriptItemType.ArrayItem) { (Optimized[i] as ScriptArrayItem).Combine(ma, 1); } else { screrr(entry.line, "Entity " + entry.identifier + " conflicts with " + Optimized[i].identifier + " at line " + Optimized[i].line + ", both trying to occupy the value " + i + " (0x" + i.ToString("X2") + ")! Optimization requires no such conflicts."); } } } break; case ScriptItemType.ArrayItem: screrr(entry.line, "Unoptimized list contains a pre-occupied technical element that may not be interpreted. This is likely a programming error, please report to devs!"); break; case ScriptItemType.Import: ScriptArray sc = context.GetSubscript((entry as ScriptImport).name); if (sc.Optimized == null) { sc.Optimize(); } Optimized = ConvertSMPS.context.Combine(new GenericScriptItem[][] { Optimized, sc.Optimized }); break; // all these items are invalid inside the LUT. default: screrr(entry.line, "Optimized look-up-table may only contain unoptimizable elements! Look-up-tables may contain either Equates, or macros."); break; } } return(Optimized); }
static void Main(string[] args) { Console.Title = "SMPS2ASM/NAT Built: " + new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime.ToShortDateString() + " " + new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime.ToShortTimeString(); // args[input file with ext, Sound driver name, label, extra: may be used by script] // get the exe folder string[] a = args; //check if we have a debug option opcheck: if (args.Length > 0 && args[0] == "-d") { args = args.Skip(1).ToArray(); debug = true; goto opcheck; } //check if we have a pause option if (args.Length > 0 && args[0] == "-p") { args = args.Skip(1).ToArray(); pause = true; goto opcheck; } //check if we have a type option if (args.Length > 1 && args[0] == "-t") { type = args[1]; args = args.Skip(2).ToArray(); goto opcheck; } //check if a script file was dragged in if (args.Length > 0) { if (File.Exists(args[0]) && args[0].EndsWith(".smpss")) { folder = Environment.CurrentDirectory; string script = args[0]; args = args.Skip(1).ToArray(); // check if all arguments are gotten if (args.Length < 2) { pause = true; args = ConsoleArguments.Get(args, new ArgHandler[] { new ArgHandler("Music file name with extension:", chkfilext2), new ArgHandler("Project name:", chkname), }, new ButtonHandler[] { new ButtonHandler(ConsoleKey.Escape, "Quit the program", quitprg, quitcl), new ButtonHandler(ConsoleKey.F1, "Pause program at the end", pauseprg, pausecl), new ButtonHandler(ConsoleKey.F2, "Print debug info", debugprg, debugcl), }); } else { args[0] = chkfilext2(args[0], true); args[1] = chkname(args[1], true); } string[] ax = new string[1 + args.Length]; ax[0] = args[0]; ax[2] = args[1]; ax[1] = script; for (int i = 3; i < ax.Length; i++) { ax[i] = args[i - 1]; } args = ax; goto oops; } } // check if all arguments are gotten if (args.Length < 3) { folder = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Environment.CurrentDirectory), @"")); pause = true; args = ConsoleArguments.Get(args, new ArgHandler[] { new ArgHandler("Music file name with extension:", chkfilext), new ArgHandler("Sound driver folder name:", chkfolext), new ArgHandler("Project name:", chkname), }, new ButtonHandler[] { new ButtonHandler(ConsoleKey.Escape, "Quit the program", quitprg, quitcl), new ButtonHandler(ConsoleKey.F1, "Pause program at the end", pauseprg, pausecl), new ButtonHandler(ConsoleKey.F2, "Print debug info", debugprg, debugcl), }); } else { folder = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Environment.CurrentDirectory), @"")); args[0] = chkfilext(args[0], true); args[1] = chkfolext(args[1], true); args[2] = chkname(args[2], true); } // time how long this will take oops: timer = new Stopwatch(); timer.Start(); // remove bin folder from path // if (folder.EndsWith("\\bin") || folder.EndsWith("\\bin\\")) folder = folder.Substring(0, folder.LastIndexOf("\\")); // removes the extension of input file and adds .asm as the extension of output file string fileout; if (args[0].IndexOf(".", args[0].LastIndexOf("\\")) > 0) { fileout = args[0].Substring(0, args[0].LastIndexOf(".")) + ".asm"; } else { fileout = args[0] + ".asm"; } // init debugwriter and put in debug info if (debug) { string db; if (args[0].IndexOf(".", args[0].LastIndexOf("\\")) > 0) { db = args[0].Substring(0, args[0].LastIndexOf(".")) + ".smpsd"; } else { db = args[0] + ".smpsd"; } //init stream dbWr = new StreamWriter(db); // write info about args Debug("--; args=[" + string.Join(", ", a) + "]"); Debug("--; filein=" + args[0]); Debug("--; fileout=" + fileout); Debug("--; folder=" + folder); Debug("--; script=" + args[1]); Debug("--; lable=" + args[2]); Debug("--; type=" + type); } // get new SMPS object ConvertSMPS cvt = new ConvertSMPS(args[0], fileout, args[2]); // get the file for smps2asm script S2AScript scr = new S2AScript(args[1], args.Skip(3).ToArray(), type); // print timer info long tra = timer.ElapsedMilliseconds; Console.WriteLine("Script translated! Took " + tra + " ms!"); // restart timer timer.Reset(); timer.Start(); // do teh conversion cvt.Convert(scr); // print timer info long con = timer.ElapsedMilliseconds; Console.WriteLine("File converted! Took " + con + " ms!"); // restart timer timer.Reset(); timer.Start(); // write teh file Output.DoIt(cvt); // print timer info long pot = timer.ElapsedMilliseconds; Console.WriteLine("File saved to disk! Took " + pot + " ms!"); Console.WriteLine("Conversion done! Took " + (pot + tra + con) + " ms!"); if (debug) { Debug(new string('-', 80)); Debug("--; Time for Script " + tra + " ms"); Debug("--; Time for Convert " + con + " ms"); Debug("--; Time for Save " + pot + " ms"); Debug("--; Time for Total " + (pot + tra + con) + " ms"); dbWr.Flush(); } if (pause) { Console.ReadKey(); } }
// convert main script public void Convert(S2AScript scr) { if (debug) { Debug("Prepare conversion"); } this.scr = scr; UnunsedChk = new List <uint>(); Lables = new List <OffsetString>(); Lines = new List <OffsetString>(); data = File.ReadAllBytes(filein); skipped = new bool[data.Length + 1]; skipped[data.Length] = true; // skip last byte for output if (debug) { Debug(new string('-', 80)); } // run conveter string[] a = null; if (debug) { Debug("--> Start conversion with subscript ''"); } try { ConvertRun(scr.subscripts[""].Items, ref a, baselable, out bool asses, out string c); } catch (DataException) { } // convert unused data if (scr.subscripts.ContainsKey("unused")) { List <GenericScriptItem> uscr = scr.subscripts["unused"].Items; for (int i = 0; i < UnunsedChk.Count; i++) { uint p = UnunsedChk[i]; // check if this is not used if (skipped[p]) { continue; } foreach (OffsetString o in Lines) { if (o.offset <= p && o.offset + o.length >= p) { goto next; } } // unused, deal with it try { pos = p; ConvertRun(uscr, ref a, baselable, out bool asses, out string c); } catch (DataException) { } next :; } } if (debug) { Debug(new string('-', 80)); } }