// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using PascalABCCompiler.Errors; using System.IO; using System.Linq; using System.Globalization; namespace PascalABCCompiler { /*class mc { public static int meth() { return 3; } }*/ class ConsoleCompiler { private static string StringsPrefix = "PABCNETC_"; public static PascalABCCompiler.Compiler Compiler=null; public static string FileName = ""; public static CompilerOptions.OutputType outputType; public static DateTime StartTime; private static string StringResourcesGet(string Key) { return StringResources.Get(StringsPrefix + Key); } /*public static void ShowConnectedParsers() { if (LanguageProvider.Instance.Languages.Count > 0) { Console.Write(StringResourcesGet("CONNECTED_PARSERS")); foreach (ILanguage lang in LanguageProvider.Instance.Languages) Console.Write(FormatTools.LanguageAndExtensionsFormatted(lang.Name, lang.FilesExtensions)+"; "); Console.WriteLine(); } }*/ public static bool CheckAndSplitDirective(string directive, out string name, out string value) { System.Diagnostics.Debug.Assert(directive[0] == '/'); directive = directive.Remove(0, 1); name = null; value = null; var ss = directive.Split( new[]{':'}, 2); name = ss[0].ToLower(); if (ss.Length > 1) { value = ss[1].Trim(); } return true; } public static bool ApplyDirective(string name, string value, CompilerOptions co) { switch (name) { case "debug": switch (value) { case "0": co.Debug = false; co.Optimise = true; return true; case "1": co.Debug = true; return true; default: Console.WriteLine("Bad value in 'Debug' directive '{0}'. Acceptable values are 0 or 1", value); return false; } case "define": co.ForceDefines.Add(value); return true; case "output": if (!Compiler.CheckPathValid(value)) return false; co.OutputFileName = Path.GetFileName(value); if (Path.IsPathRooted(value)) { co.OutputDirectory = Path.GetDirectoryName(value); } return true; case "searchdir": if (!Directory.Exists(value)) { Console.WriteLine($"SearchDir \"{value}\" not found relative to \"{Environment.CurrentDirectory}\""); return false; } co.SearchDirectories.Insert(0, value); // .Insert, чтобы определённые пользователем папки имели бОльший приоритет, чем стандартная return true; case "locale": co.Locale = value; return true; default: Console.WriteLine("No such directive name: '{0}'", name); return false; } } public static bool CheckAndApplyDirective(string directive, CompilerOptions co) { string name, value; var b = CheckAndSplitDirective(directive,out name, out value); if (!b) return false; b = ApplyDirective(name, value, co); return b; } public static void OutputHelp() { Console.WriteLine("Command line: "); Console.WriteLine("pabcnetcclear /directive1:value1 /directive2:value2 ... [inputfile]\n"); Console.WriteLine("Available directives:"); //Console.WriteLine(" /Help /H /?"); - запретил - конкурирует с pabcnetcclear /w/a.pas Console.WriteLine(" /Debug:<0/1>"); Console.WriteLine(" /Define:"); Console.WriteLine(" /Output:<[path\\]name>"); Console.WriteLine(" /SearchDir:"); Console.WriteLine(" /Locale:"); Console.WriteLine(" /Version:"); Console.WriteLine(); Console.WriteLine("/Help show this message"); Console.WriteLine("/Output:<[path\\]name> compile into an executable called \"name\" and save it in \"path\" directory"); Console.WriteLine("/Debug:0 generates code with all .NET optimizations"); Console.WriteLine("/SearchDir: add \"path\" to list of standart unit search directories. Last added paths would be searched first"); Console.WriteLine("/Locale: set locale of main thread of compiled program executable"); Console.WriteLine("/Version: outputs PascalABC.NET version"); } public static int Main(string[] args) { // SSM 18.03.19 Делаю параметры командной строки. Формат: pabcnetc.exe /Dir1=value1 /Dir2=value2 ... fname dir // dir - это пережиток старого - так можно было задавать каталог раньше. Пока - увы - пусть останется // Пока сделаю только директивы /Help /H /? и /Debug=0(1) // Имя директивы - это одно слово. Равенства может не быть - тогда value директивы равно null // Вычленяем первое равенство и делим директиву: до него - name, после него - value. Если name или value - пустые строки, то ошибка // 2022 г. К сожалению, директива с / конкурирует с именами каталогов в Linux. Надо писать новый консольный компилятор DateTime ldt = DateTime.Now; PascalABCCompiler.StringResourcesLanguage.LoadDefaultConfig(); // загрузка всех парсеров и других составляющих языков EVA Languages.Integration.LanguageIntegrator.LoadAllLanguages(); Compiler = new PascalABCCompiler.Compiler(null, null); Compiler.InternalDebug.SkipPCUErrors = false; CultureInfo ci = CultureInfo.InstalledUICulture; if (StringResourcesLanguage.CurrentTwoLetterISO == "ru" && ci.TwoLetterISOLanguageName != "ru") StringResourcesLanguage.CurrentLanguageName = StringResourcesLanguage.AccessibleLanguages[StringResourcesLanguage.TwoLetterISOLanguages.IndexOf("en")]; else StringResourcesLanguage.CurrentLanguageName = StringResourcesLanguage.AccessibleLanguages[StringResourcesLanguage.TwoLetterISOLanguages.IndexOf(StringResourcesLanguage.CurrentTwoLetterISO)]; //Console.WriteLine("OK {0}ms", (DateTime.Now - ldt).TotalMilliseconds); ldt = DateTime.Now; //ShowConnectedParsers(); var n = args.Length; if (n == 0) { //Console.WriteLine(StringResourcesGet("COMMANDLINEISABSENT")); OutputHelp(); return 2; } // /W/a.pas расценивается как директива. Нужен более сложный паттерн: начинается с \буквы: //var n1 = args.TakeWhile(a => a[0] == '/').Count(); // количество директив // Поменяем: SSM 14/12/21 var n1 = args.TakeWhile(a => System.Text.RegularExpressions.Regex.IsMatch(a, @"^/\w+:")).Count(); // количество директив if (n1