public static BaseParser BuildParser(GrammarType type, string text, List <Message> messages) { var builtGrammar = BuildGrammar(type, text, messages); if (messages.Count(m => m.Type == MessageType.Error) != 0) { return(null); } builtGrammar.RebuildUserificationCache(); BaseTable table = null; switch (type) { case GrammarType.LL: table = new TableLL1(builtGrammar); break; case GrammarType.LR: table = new TableLR1(builtGrammar); break; } messages.AddRange(table.CheckValidity()); table.ExportToCsv(TempName("current_table.csv")); var lexerType = BuildLexer(builtGrammar, "CurrentLexer", messages); if (messages.Count(m => m.Type == MessageType.Error) != 0) { return(null); } /// Создаём парсер BaseParser parser = null; switch (type) { case GrammarType.LL: parser = new Parsing.LL.Parser(builtGrammar, new AntlrLexerAdapter( (Antlr4.Runtime.ICharStream stream) => (Antlr4.Runtime.Lexer)Activator.CreateInstance(lexerType, stream) ) ); break; case GrammarType.LR: parser = new Parsing.LR.Parser(builtGrammar, new AntlrLexerAdapter( (Antlr4.Runtime.ICharStream stream) => (Antlr4.Runtime.Lexer)Activator.CreateInstance(lexerType, stream) ) ); break; } return(parser); }
/// <summary> /// Генерация библиотеки с парсером /// </summary> /// <param name="type">Тип парсера (LL или LR)</param> /// <param name="text">Грамматика разбираемого формата файлов</param> /// <param name="namespace">Пространство имён для сгенерированного парсера</param> /// <param name="path">Путь к каталогу, в котором необходимо сгенерировать библиотеку</param> /// <param name="messages">Лог генерации парсера</param> /// <returns>Признак успешности выполнения операции</returns> public static bool GenerateLibrary( GrammarType type, string text, string @namespace, string path, string keyPath, List <Message> messages ) { const string ANTLR_LIBRARY = "Antlr4.Runtime.Standard.dll"; /// Строим объект грамматики и проверяем, корректно ли прошло построение var builtGrammar = BuildGrammar(type, text, messages); /// Проверяем, не появились ли ошибки после построения грамматики if (messages.Count(m => m.Type == MessageType.Error) != 0) { return(false); } builtGrammar.RebuildUserificationCache(); /// Строим таблицу и проверяем, соответствует ли она указанному типу грамматики BaseTable table = null; switch (type) { case GrammarType.LL: table = new TableLL1(builtGrammar); break; case GrammarType.LR: table = new TableLR1(builtGrammar); break; } messages.AddRange(table.CheckValidity()); /// Проверяем, не появились ли ошибки после построения таблицы if (messages.Count(m => m.Type == MessageType.Error) != 0) { return(false); } var lexerFileName = TempName($"{@namespace.Replace('.', '_')}_Lexer.cs"); var parserFileName = TempName($"{@namespace.Replace('.', '_')}_Parser.cs"); var grammarFileName = TempName($"{@namespace.Replace('.', '_')}_Grammar.cs"); var nodeGeneratorFileName = TempName($"{@namespace.Replace('.', '_')}_NodeGenerator.cs"); BuildLexer(builtGrammar, Path.GetFileNameWithoutExtension(lexerFileName), messages); /// Проверяем, не появились ли ошибки после генерации исходников лексера if (messages.Count(m => m.Type == MessageType.Error) != 0) { return(false); } File.WriteAllText(grammarFileName, GetGrammarProviderText(builtGrammar, @namespace)); File.WriteAllText(parserFileName, GetParserProviderText(@namespace)); File.WriteAllText(nodeGeneratorFileName, GetNodeGeneratorText(builtGrammar, @namespace)); if (!String.IsNullOrEmpty(keyPath) && !File.Exists(keyPath)) { /// Создаём файл ключа Process process = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo() { FileName = "cmd.exe", Arguments = $"/C chcp 1251 | \"Resources/sn.exe\" -k \"{keyPath}\"", CreateNoWindow = true, RedirectStandardOutput = true, UseShellExecute = false }; process.StartInfo = startInfo; process.Start(); process.WaitForExit(); } /// Компилируем библиотеку var codeProvider = new CSharpCodeProvider();; var compilerParams = new System.CodeDom.Compiler.CompilerParameters(); compilerParams.GenerateInMemory = false; compilerParams.OutputAssembly = Path.Combine(path, $"{@namespace}.dll"); compilerParams.ReferencedAssemblies.Add(ANTLR_LIBRARY); compilerParams.ReferencedAssemblies.Add("Land.Core.dll"); compilerParams.ReferencedAssemblies.Add("System.dll"); compilerParams.ReferencedAssemblies.Add("System.Core.dll"); compilerParams.ReferencedAssemblies.Add("mscorlib.dll"); if (!String.IsNullOrEmpty(keyPath)) { compilerParams.CompilerOptions = $"/keyfile:\"{keyPath}\""; } var compilationResult = codeProvider.CompileAssemblyFromFile(compilerParams, lexerFileName, grammarFileName, parserFileName, nodeGeneratorFileName); if (compilationResult.Errors.Count == 0) { File.Copy(ANTLR_LIBRARY, Path.Combine(path, ANTLR_LIBRARY), true); return(true); } else { foreach (System.CodeDom.Compiler.CompilerError error in compilationResult.Errors) { if (error.IsWarning) { messages.Add(Message.Warning( $"Предупреждение: {error.FileName}; ({error.Line}, {error.Column}); {error.ErrorText}", null, "C# Compiler" )); } else { messages.Add(Message.Error( $"Ошибка: {error.FileName}; ({error.Line}, {error.Column}); {error.ErrorText}", null, "C# Compiler" )); } } return(messages.All(m => m.Type != MessageType.Error)); } }