|
@@ -0,0 +1,301 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Concurrent;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.IO;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using NTERA.Interpreter;
|
|
|
+using NTERA.Interpreter.Compiler;
|
|
|
+
|
|
|
+namespace NTERA.Compiler
|
|
|
+{
|
|
|
+ public class Compiler
|
|
|
+ {
|
|
|
+ public string InputDirectory { get; }
|
|
|
+
|
|
|
+ public List<Tuple<ParserError, string>> Errors { get; } = new List<Tuple<ParserError, string>>();
|
|
|
+
|
|
|
+ public Dictionary<FunctionDefinition, string> DeclaredFunctions = new Dictionary<FunctionDefinition, string>();
|
|
|
+
|
|
|
+ public Compiler(string inputDirectory)
|
|
|
+ {
|
|
|
+ InputDirectory = inputDirectory;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Compile(string outputDirectory)
|
|
|
+ {
|
|
|
+ var globals = new VariableDictionary
|
|
|
+ {
|
|
|
+ ["LOCAL"] = 0,
|
|
|
+ ["LOCALS"] = "",
|
|
|
+ ["ARG"] = "",
|
|
|
+ ["ARGS"] = "",
|
|
|
+ ["GLOBAL"] = "",
|
|
|
+ ["GLOBALS"] = "",
|
|
|
+ ["NICKNAME"] = "",
|
|
|
+ ["MASTERNAME"] = "",
|
|
|
+ ["CSTR"] = "",
|
|
|
+ ["CUP"] = "",
|
|
|
+ ["CDOWN"] = "",
|
|
|
+ ["DOWNBASE"] = "",
|
|
|
+ ["TCVAR"] = "",
|
|
|
+ ["CDFLAG"] = "",
|
|
|
+ ["ITEMPRICE"] = "",
|
|
|
+ ["TRAINNAME"] = "",
|
|
|
+ ["BASENAME"] = "",
|
|
|
+ ["EQUIPNAME"] = "",
|
|
|
+ ["TEQUIPNAME"] = "",
|
|
|
+ ["STAINNAME"] = "",
|
|
|
+ ["EXNAME"] = "",
|
|
|
+ ["SOURCENAME"] = "",
|
|
|
+ ["FLAGNAME"] = "",
|
|
|
+ ["TFLAGNAME"] = "",
|
|
|
+ ["CFLAGNAME"] = "",
|
|
|
+ ["TCVARNAME"] = "",
|
|
|
+ ["STRNAME"] = "",
|
|
|
+ ["TSTRNAME"] = "",
|
|
|
+ ["CSTRNAME"] = "",
|
|
|
+ ["SAVESTRNAME"] = "",
|
|
|
+ ["CDFLAGNAME"] = "",
|
|
|
+ ["CDFLAGNAME"] = "",
|
|
|
+ ["GLOBALNAME"] = "",
|
|
|
+ ["GLOBALSNAME"] = "",
|
|
|
+ ["GAMEBASE_AUTHOR"] = "",
|
|
|
+ ["GAMEBASE_INFO"] = "",
|
|
|
+ ["GAMEBASE_YEAR"] = "",
|
|
|
+ ["GAMEBASE_TITLE"] = "",
|
|
|
+ ["GAMEBASE_GAMECODE"] = "",
|
|
|
+ ["GAMEBASE_VERSION"] = "",
|
|
|
+ ["GAMEBASE_ALLOWVERSION"] = "",
|
|
|
+ ["GAMEBASE_DEFAULTCHARA"] = "",
|
|
|
+ ["GAMEBASE_NOITEM"] = "",
|
|
|
+ ["WINDOW_TITLE"] = "",
|
|
|
+ ["MONEYLABEL"] = "",
|
|
|
+ ["DRAWLINESTR"] = "",
|
|
|
+ ["LASTLOAD_VERSION"] = "",
|
|
|
+ ["LASTLOAD_NO"] = "",
|
|
|
+ ["LASTLOAD_TEXT"] = "",
|
|
|
+ ["SAVEDATA_TEXT"] = "",
|
|
|
+ ["TSTR"] = "",
|
|
|
+ ["RANDDATA"] = "",
|
|
|
+ ["LINECOUNT"] = "",
|
|
|
+ ["ISTIMEOUT"] = "",
|
|
|
+ ["__INT_MAX__"] = "",
|
|
|
+ ["__INT_MIN__"] = "",
|
|
|
+ ["NAME"] = "",
|
|
|
+ ["CALLNAME"] = "",
|
|
|
+ ["RAND"] = "",
|
|
|
+ ["CHARANUM"] = "",
|
|
|
+ ["TALENT"] = "",
|
|
|
+ ["FLAG"] = "",
|
|
|
+ ["TFLAG"] = "",
|
|
|
+ ["CFLAG"] = "",
|
|
|
+ ["MASTER"] = "",
|
|
|
+ ["BASE"] = "",
|
|
|
+ ["MAXBASE"] = "",
|
|
|
+ ["SOURCE"] = "",
|
|
|
+ ["ABL"] = "",
|
|
|
+ ["PALAM"] = "",
|
|
|
+ ["TEQUIP"] = "",
|
|
|
+ ["EQUIP"] = "",
|
|
|
+ ["DAY"] = "",
|
|
|
+ ["MARK"] = "",
|
|
|
+ ["PALAMLV"] = "",
|
|
|
+ ["TARGET"] = "",
|
|
|
+ ["PLAYER"] = "",
|
|
|
+ ["NOWEX"] = "",
|
|
|
+ ["EX"] = "",
|
|
|
+ ["EXNAME"] = "",
|
|
|
+ ["STAIN"] = "",
|
|
|
+ ["EXP"] = "",
|
|
|
+ ["ASSIPLAY"] = "",
|
|
|
+ ["ASSI"] = "",
|
|
|
+ ["ITEM"] = "",
|
|
|
+ ["EXPLV"] = "",
|
|
|
+ ["TIME"] = "",
|
|
|
+ ["MONEY"] = "",
|
|
|
+ ["SELECTCOM"] = "",
|
|
|
+ ["JUEL"] = "",
|
|
|
+ ["STR"] = "",
|
|
|
+ ["PREVCOM"] = "",
|
|
|
+ ["SAVESTR"] = "",
|
|
|
+ ["ABLNAME"] = "",
|
|
|
+ ["MARKNAME"] = "",
|
|
|
+ ["TALENTNAME"] = "",
|
|
|
+ ["ITEMNAME"] = "",
|
|
|
+ ["PALAMNAME"] = "",
|
|
|
+ ["EXPNAME"] = "",
|
|
|
+ ["DITEMTYPE"] = "",
|
|
|
+ ["NO"] = "",
|
|
|
+ ["RELATION"] = "",
|
|
|
+ ["IS"] = ""
|
|
|
+ };
|
|
|
+
|
|
|
+ foreach (char c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
|
+ globals[c.ToString()] = "";
|
|
|
+
|
|
|
+ var funcs = new List<FunctionDefinition>
|
|
|
+ {
|
|
|
+ new FunctionDefinition("RAND", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("TOSTR", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0], "") }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("STRCOUNT", new[] { new FunctionParameter("input", new string[0]), new FunctionParameter("match", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("MIN", new[] { new FunctionParameter("a", new string[0], isArrayParameter: true), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("MAX", new[] { new FunctionParameter("a", new string[0], isArrayParameter: true), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("POWER", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("GETPALAMLV", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("GETBIT", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("UNICODE", new[] { new FunctionParameter("a", new string[0]) }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("MATCH", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]), new FunctionParameter("c", new string[0], "a"), new FunctionParameter("d", new string[0], "f"), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("INRANGE", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("b", new string[0]), new FunctionParameter("c", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("HE_SHE", new[] { new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("SUBSTRING", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("STRLENS", new[] { new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("CSVNAME", new[] { new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("CSVNAME", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("CSVTALENT", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("CSVCSTR", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("GETNUM", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("FINDCHARA", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("LIMIT", new[] { new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), new FunctionParameter("a", new string[0]), }, new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("GETTIME", new FunctionParameter[0], new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("SAVENOS", new FunctionParameter[0], new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("GETCOLOR", new FunctionParameter[0], new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ new FunctionDefinition("CURRENTREDRAW", new FunctionParameter[0], new FunctionVariable[0], true, "_GLOBAL", new Marker()),
|
|
|
+ };
|
|
|
+
|
|
|
+ var stringStatements = new List<string>
|
|
|
+ {
|
|
|
+ "DRAWLINEFORM",
|
|
|
+ "PRINTFORML",
|
|
|
+ "PRINT",
|
|
|
+ "PRINTW",
|
|
|
+ "PRINTV",
|
|
|
+ "PRINTL",
|
|
|
+ "PRINTLC",
|
|
|
+ "PRINTC",
|
|
|
+ "ALIGNMENT",
|
|
|
+ "CALL",
|
|
|
+ "CUSTOMDRAWLINE",
|
|
|
+ "DATAFORM",
|
|
|
+ "GOTO",
|
|
|
+ "PRINTFORMDL",
|
|
|
+ "PRINTFORMW",
|
|
|
+ "PRINTFORMDW",
|
|
|
+ "PRINTFORMC",
|
|
|
+ "PRINTFORMLC",
|
|
|
+ "PRINTFORM",
|
|
|
+ "PRINTPLAINFORM",
|
|
|
+ "DEBUGPRINTL",
|
|
|
+ "DEBUGPRINTFORML",
|
|
|
+ "REUSELASTLINE",
|
|
|
+ "PRINTPLAIN",
|
|
|
+ "PRINT_TRAIN_NAME",
|
|
|
+ "PRINT_STR",
|
|
|
+ };
|
|
|
+
|
|
|
+ string csvPath = Path.Combine(InputDirectory, "CSV");
|
|
|
+ string erbPath = Path.Combine(InputDirectory, "ERB");
|
|
|
+
|
|
|
+ var csvDefinition = new CSVDefinition();
|
|
|
+
|
|
|
+
|
|
|
+ foreach (var file in Directory.EnumerateFiles(csvPath, "*.csv", SearchOption.AllDirectories))
|
|
|
+ {
|
|
|
+ string path = Path.GetFileNameWithoutExtension(file);
|
|
|
+
|
|
|
+ if (path.EndsWith("_TR"))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ Preprocessor.ProcessCSV(csvDefinition, path, File.ReadLines(file, Encoding.UTF8));
|
|
|
+ }
|
|
|
+
|
|
|
+ ConcurrentDictionary<FunctionDefinition, string> preprocessedFunctions = new ConcurrentDictionary<FunctionDefinition, string>();
|
|
|
+
|
|
|
+#if DEBUG
|
|
|
+ foreach (var file in Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories))
|
|
|
+#else
|
|
|
+ Parallel.ForEach(Directory.EnumerateFiles(erbPath, "*.erb", SearchOption.AllDirectories), new ParallelOptions
|
|
|
+ {
|
|
|
+ MaxDegreeOfParallelism = 4
|
|
|
+ }, file =>
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ foreach (var kv in Preprocessor.PreprocessFile(File.ReadAllText(file), Path.GetFileName(file)))
|
|
|
+ preprocessedFunctions[kv.Key] = kv.Value;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ lock (Errors)
|
|
|
+ Errors.Add(new Tuple<ParserError, string>(new ParserError($"Internal pre-process lexer error [{ex}]", new Marker()), Path.GetFileName(file)));
|
|
|
+ }
|
|
|
+#if DEBUG
|
|
|
+ }
|
|
|
+#else
|
|
|
+ });
|
|
|
+#endif
|
|
|
+
|
|
|
+ DeclaredFunctions = preprocessedFunctions.ToDictionary(kv => kv.Key, kv => kv.Value);
|
|
|
+
|
|
|
+ funcs.AddRange(DeclaredFunctions.Keys.Where(x => x.IsReturnFunction));
|
|
|
+ var procedures = DeclaredFunctions.Keys.Where(x => !x.IsReturnFunction).ToList();
|
|
|
+
|
|
|
+
|
|
|
+#if DEBUG
|
|
|
+ foreach (var kv in DeclaredFunctions)
|
|
|
+#else
|
|
|
+ Parallel.ForEach(DeclaredFunctions, new ParallelOptions
|
|
|
+ {
|
|
|
+ MaxDegreeOfParallelism = 4
|
|
|
+ }, kv =>
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var locals = new VariableDictionary();
|
|
|
+ foreach (var param in kv.Key.Variables)
|
|
|
+ locals[param.Name] = param.DefaultValue ?? param.ValueType == Interpreter.ValueType.String ? new Value("") : new Value(0d);
|
|
|
+
|
|
|
+ Parser parser = new Parser(kv.Value, kv.Key, funcs, procedures, globals, locals, stringStatements, csvDefinition);
|
|
|
+
|
|
|
+ var nodes = parser.Parse(out var localErrors);
|
|
|
+
|
|
|
+ lock (Errors)
|
|
|
+ Errors.AddRange(localErrors.Select(x => new Tuple<ParserError, string>(x, $"{kv.Key.Filename} - {kv.Key.Name}")));
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ lock (Errors)
|
|
|
+ Errors.Add(new Tuple<ParserError, string>(new ParserError($"Internal post-process lexer error [{ex}]", new Marker()), $"{kv.Key.Filename} - {kv.Key.Name}"));
|
|
|
+ }
|
|
|
+#if DEBUG
|
|
|
+ }
|
|
|
+#else
|
|
|
+ });
|
|
|
+#endif
|
|
|
+
|
|
|
+ long fileSize = 0;
|
|
|
+ int fileCount = 0;
|
|
|
+
|
|
|
+ foreach (var file in Directory.EnumerateFiles(InputDirectory, "*.erb", SearchOption.AllDirectories))
|
|
|
+ {
|
|
|
+ var info = new FileInfo(file);
|
|
|
+ fileSize += info.Length;
|
|
|
+ fileCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ var htmlWriter = new HTMLWriter
|
|
|
+ {
|
|
|
+ Errors = Errors.OrderBy(x => x.Item2).ToList(),
|
|
|
+ FunctionCount = DeclaredFunctions.Count,
|
|
|
+ TotalFileSize = fileSize,
|
|
|
+ TotalFileCount = fileCount
|
|
|
+ };
|
|
|
+
|
|
|
+ using (var stream = File.Create(Path.Combine(outputDirectory, "report.html")))
|
|
|
+ htmlWriter.WriteReportToFile(stream);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|