public BNF Parse(string bnfGrammarFile) { BNF BNF = new BNF(); Queue <string> bnfFile = new Queue <string>(System.IO.File.ReadAllText(bnfGrammarFile).Split(new[] { ' ', '\n', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries)); string word, production = "ERROR"; int expansionIndex = 0; while (bnfFile.Count > 0) { word = bnfFile.Dequeue(); if (bnfFile.Count > 1 && bnfFile.Peek() == "->") { production = word; expansionIndex = 0; BNF.Add(production, new List <List <string> >()); BNF[production].Add(new List <string>()); bnfFile.Dequeue(); } else if (word == "|") { expansionIndex++; BNF[production].Add(new List <string>()); } else if (word[0] == '\\') { BNF[production][expansionIndex].Add(word.Substring(1)); } else { BNF[production][expansionIndex].Add(word); } } return(BNF); }
private void скачатьToolStripMenuItem_Click(object sender, EventArgs e) { try { if (saveFileDialog1.ShowDialog() == DialogResult.Cancel) { return; } // получаем выбранный файл string filename = saveFileDialog1.FileName; var str = ""; if (KS != null) { str += "КС грамматика: " + Environment.NewLine; str += "Алфавит: " + KS.GetVTString() + Environment.NewLine; str += "Алфавит нетерминальный: " + KS.GetVNString() + Environment.NewLine; str += "Лямбда: " + KS.Lambda + Environment.NewLine; str += "Стартовый символ: " + KS.Start + Environment.NewLine; str += "Грамматика: " + KS.ToString() + Environment.NewLine; if (ChainKS != null) { str += "Цепочки: " + Environment.NewLine; foreach (var ch in ChainKS) { str += ch.Str + Environment.NewLine; } } } if (BNF != null) { str += "БНФ грамматика: " + Environment.NewLine; str += "Алфавит: " + BNF.GetVTString() + Environment.NewLine; str += "Алфавит нетерминальный: " + BNF.GetVNString() + Environment.NewLine; str += "Лямбда: " + BNF.Lambda + Environment.NewLine; str += "Стартовый символ: " + BNF.Start + Environment.NewLine; str += "Грамматика: " + BNF.ToString() + Environment.NewLine; if (ChainBNF != null) { str += "Цепочки: " + Environment.NewLine; foreach (var ch in ChainBNF) { str += ch.Str + Environment.NewLine; } } } // сохраняем текст в файл System.IO.File.WriteAllText(filename, str); MessageBox.Show("Файл сохранен"); } catch (Exception ex) { textBox1.Text += Environment.NewLine + ex.Message; } }
public FirstSetTable GetFirstSets(BNF bnf) { FirstSetTable sets = new FirstSetTable(); foreach (var production in bnf) { GetSymbolFirstSet(production.Key, bnf, sets); } return(sets); }
HashSet <string> GetSymbolFirstSet(string symbol, BNF bnf, FirstSetTable firstSets) { if (firstSets.SymbolSets.ContainsKey(symbol)) { return(firstSets.SymbolSets[symbol]); } else { if (IsTerminal(symbol, bnf)) { HashSet <string> set = new HashSet <string>() { symbol }; firstSets.SymbolSets.Add(symbol, set); return(set); } else { HashSet <string> set = new HashSet <string>(); var expansions = bnf[symbol]; for (int index = 0; index < expansions.Count; index++) { var expansionSet = GetExpansionFirstSet(symbol, index, bnf, firstSets); if (expansions[index].Count == 1 && expansions[index][0] == _emptySymbol) { set.Add(_emptySymbol); } else { set.UnionWith(expansionSet); } } firstSets.SymbolSets.Add(symbol, set); return(set); } } }
private void button4_Click(object sender, EventArgs e) { label12.Text = "Статус грамматик"; isSuccessfullyGrammaticBNF = false; if (!isSuccessfullyGrammaticKS) { textBox1.Text += Environment.NewLine + "Ошибка! Запишите сначала КС-грамматику"; } try { BNF = KS.ConvertToBNFGrammatik(); textBox9.Text = BNF.ToString(); textBox10.Text = BNF.GetVTString(); textBox12.Text = BNF.GetVNString(); textBox11.Text = BNF.Start; isSuccessfullyGrammaticBNF = true; } catch (Exception ex) { textBox1.Text += Environment.NewLine + "Ошибка! " + ex.Message; } }
static void Main(string[] args) { IClassGenerator classGenerator = new ClassGenerator(); IBNFAnalyzer bnfAnalyzer = new BNFAnalyzer(); IBNFParser bnfParser = new BNFParser(); IParserGenerator parserGenerator = new ParserGenerator(bnfAnalyzer); #if GENERATEGENERATOR Console.WriteLine("Generating generator..."); BNF bnf = bnfParser.Parse("../../docs/translator.bnf"); string translatorParserName = "TranslatorParser"; string translatorVisitorName = "TranslatorVisitor"; string dataNamespace = "Generator.Translation.Data"; string parsingNamespace = "Generator.Translation.Parsing"; string visitorNamespace = "Generator.Translation.Visitors"; ClassType[] translatorParser = parserGenerator.GenerateParserClasses(bnf, translatorParserName, dataNamespace, parsingNamespace); ClassType[] translatorVisitors = parserGenerator.GenerateVisitorClasses(bnf, translatorVisitorName, dataNamespace, visitorNamespace); ClassType[] translatorData = parserGenerator.GenerateSyntaxTreeClasses(bnf, translatorVisitorName, dataNamespace, visitorNamespace); var classTypes = translatorData.Union(translatorVisitors).Union(translatorParser); foreach (ClassType classType in classTypes) { string folder = $"../{string.Join("/", classType.NameSpace.Split('.'))}"; Directory.CreateDirectory(folder); classGenerator.Generate(classType, $"{folder}/{classType.Identifier.Split('<')[0]}.cs"); } Console.WriteLine($"...DONE {2 + classTypes.Count()} classes generated."); #else ITranslatorGenerator translatorGenerator = new TranslatorGenerator(); Console.WriteLine("Generating compiler..."); Console.WriteLine("\tGenerating parser..."); BNF bnf = bnfParser.Parse("../../docs/tang.bnf"); string programParserName = "ProgramParser"; string programVisitorName = "ProgramVisitor"; string dataNamespace = "Compiler.Parsing.Data"; string parsingNamespace = "Compiler.Parsing"; string visitorNamespace = "Compiler.Parsing.Visitors"; ClassType[] programParserClasses = parserGenerator.GenerateParserClasses(bnf, programParserName, dataNamespace, parsingNamespace); ClassType[] programVisitors = parserGenerator.GenerateVisitorClasses(bnf, programVisitorName, dataNamespace, visitorNamespace); ClassType[] programData = parserGenerator.GenerateSyntaxTreeClasses(bnf, programVisitorName, dataNamespace, visitorNamespace); IEnumerable <ClassType> classesToGenerate = programData.Union(programVisitors).Union(programParserClasses); Console.WriteLine("\tGenerating Translators..."); Lexer lexer = new Lexer("../../docs/translator.tokens.json"); try { IEnumerator <Translation.Data.Token> tokens = lexer.Analyse(File.ReadAllText("../../docs/tang-ast.translator"), "ast-c.translator").Select(t => new Translation.Data.Token() { FileName = "tang-ast.translator", Name = t.Name, Value = t.Value, Row = t.Row, Column = t.Column }).GetEnumerator(); tokens.MoveNext(); IEnumerator <Translation.Data.Token> toCTranslatorTokens = lexer.Analyse(File.ReadAllText("../../docs/ast-c.translator"), "ast-c.translator").Select(t => new Translation.Data.Token() { FileName = "ast-c.translator", Name = t.Name, Value = t.Value, Row = t.Row, Column = t.Column }).GetEnumerator(); toCTranslatorTokens.MoveNext(); TranslatorParser translatorParser = new TranslatorParser(); Translation.Data.Translator astTranslator = translatorParser.ParseTranslator(tokens); Translation.Data.Translator cTranslator = translatorParser.ParseTranslator(toCTranslatorTokens); string translatorName = "ProgramToASTTranslator"; string translatorNamespace = "Compiler.Translation.ProgramToAST"; string cTranslatorName = "ASTToCTranslator"; string cTranslatorNamespace = "Compiler.Translation.ASTToC"; string symbolTableDataNamspace = "Compiler.Translation.SymbolTable.Data"; string symbolTableVisitorNamspace = "Compiler.Translation.SymbolTable.Visitors"; string symbolTableVisitorName = "SymbolTableVisitor"; string astDataNamspace = "Compiler.AST.Data"; string astVisitorNamespace = "Compiler.AST.Visitors"; string astVisitorName = "ASTVisitor"; string cDataNamspace = "Compiler.C.Data"; string cVisitorNamespace = "Compiler.C.Visitors"; string cVisitorName = "CVisitor"; BNF cGrammar = bnfParser.Parse("../../docs/c.bnf"); BNF astGrammar = bnfParser.Parse("../../docs/ast.bnf"); BNF symbolTableGrammar = bnfParser.Parse("../../docs/symboltable.bnf"); classesToGenerate = classesToGenerate.Union(parserGenerator.GenerateVisitorClasses(symbolTableGrammar, symbolTableVisitorName, symbolTableDataNamspace, symbolTableVisitorNamspace)); classesToGenerate = classesToGenerate.Union(parserGenerator.GenerateSyntaxTreeClasses(symbolTableGrammar, symbolTableVisitorName, symbolTableDataNamspace, symbolTableVisitorNamspace)); classesToGenerate = classesToGenerate.Union(parserGenerator.GenerateVisitorClasses(astGrammar, astVisitorName, astDataNamspace, astVisitorNamespace)); classesToGenerate = classesToGenerate.Union(parserGenerator.GenerateSyntaxTreeClasses(astGrammar, astVisitorName, astDataNamspace, astVisitorNamespace)); classesToGenerate = classesToGenerate.Union(parserGenerator.GenerateVisitorClasses(cGrammar, cVisitorName, cDataNamspace, cVisitorNamespace)); classesToGenerate = classesToGenerate.Union(parserGenerator.GenerateSyntaxTreeClasses(cGrammar, cVisitorName, cDataNamspace, cVisitorNamespace)); List <RelationDomain> relationDomains = new List <RelationDomain>() { new RelationDomain() { Identifier = "Program", Grammar = bnf, DataNamespace = dataNamespace, VisitorNamespace = visitorNamespace }, new RelationDomain() { Identifier = "AST", Grammar = astGrammar, DataNamespace = astDataNamspace, VisitorNamespace = astVisitorNamespace }, new RelationDomain() { Identifier = "SymbolTable", Grammar = symbolTableGrammar, DataNamespace = symbolTableDataNamspace, VisitorNamespace = symbolTableVisitorNamspace }, }; ClassType toASTTranslator = translatorGenerator.GenerateTranslatorClass(astTranslator, translatorName, relationDomains, translatorNamespace); classesToGenerate = classesToGenerate.Append(toASTTranslator); List <RelationDomain> cRelationDomains = new List <RelationDomain>() { new RelationDomain() { Identifier = "AST", Grammar = astGrammar, DataNamespace = astDataNamspace, VisitorNamespace = astVisitorNamespace }, new RelationDomain() { Identifier = "C", Grammar = cGrammar, DataNamespace = cDataNamspace, VisitorNamespace = cVisitorNamespace }, }; ClassType toCTranslator = translatorGenerator.GenerateTranslatorClass(cTranslator, cTranslatorName, cRelationDomains, cTranslatorNamespace); classesToGenerate = classesToGenerate.Append(toCTranslator); foreach (ClassType classType in classesToGenerate) { string folder = $"../{string.Join("/", classType.NameSpace.Split('.'))}"; Directory.CreateDirectory(folder); classGenerator.Generate(classType, $"{folder}/{classType.Identifier.Split('<')[0]}.cs"); } Console.WriteLine($"...Done {classesToGenerate.Count()} classes generated. Approximately {classesToGenerate.Sum(c => c.Methods.Sum(m => m.Body.Count + 3) + c.Usings.Count + c.Fields.Count)} lines of code. Thank You."); } catch (LexicalException exception) { Console.WriteLine($"Unexpected symbol near {exception.Symbol} in {exception.FileName} line {exception.Row + 1} column {exception.Column + 1}."); } catch (UnexpectedTokenException exception) { if (exception.Token.Name == exception.Token.Value) { if (exception.Token.FileName != null) { Console.WriteLine($"Unexpected '{exception.Token.Name}' in {exception.Token.FileName} line {exception.Token.Row + 1} column {exception.Token.Column + 1}."); } else { Console.WriteLine($"Unexpected '{exception.Token.Name}' at line {exception.Token.Row + 1} column {exception.Token.Column + 1}."); } } else { Console.WriteLine($"Unexpected {exception.Token.Name} '{exception.Token.Value}' in {exception.Token.FileName} line {exception.Token.Row + 1} column {exception.Token.Column + 1}."); } } #endif }
public ClassType[] GenerateParserClasses(BNF bnf, string parserName, string dataNamespace, string parserNamespace) { List <ClassType> classes = new List <ClassType>(); GrammarInfo grammarInfo = _bnfAnalyzer.Analyze(bnf); ClassType parserClass = new ClassType(parserNamespace, "public", parserName, null) { Usings = new List <string>() { $"using {dataNamespace};", "using System;", "using System.Collections.Generic;" } }; parserClass.Methods = new List <MethodType>(); MethodType parseTerminalMethod = new MethodType("public", $"{dataNamespace}.Token", "ParseTerminal") { Parameters = new List <ParameterType>() { new ParameterType($"IEnumerator<{dataNamespace}.Token>", "tokens"), new ParameterType("string", "expected") }, Body = new List <string>() { "if(expected == \"EPSILON\")", "{", $" return new {dataNamespace}.Token() {{ Name = \"EPSILON\" }};", "}", $"{dataNamespace}.Token token = tokens.Current;", "if(token.Name == expected)", "{", " tokens.MoveNext();", " return token;", "}", "else", "{", " throw new UnexpectedTokenException(token);", "}" } }; parserClass.Methods.Add(parseTerminalMethod); foreach (var production in bnf) { MethodType parseMethod = new MethodType("public", $"{dataNamespace}.{production.Key}", $"Parse{production.Key}") { Parameters = new List <ParameterType>() { new ParameterType($"IEnumerator<{dataNamespace}.Token>", "tokens") } }; List <string> methodStatements = new List <string>(); methodStatements.Add($"{dataNamespace}.{production.Key} node = new {dataNamespace}.{production.Key}(){{ Name = \"{production.Key}\" }};"); methodStatements.Add("switch(tokens.Current.Name)"); methodStatements.Add("{"); for (int expansionIndex = 0; expansionIndex < production.Value.Count; expansionIndex++) { foreach (var predictSymbol in grammarInfo.PredictsSets[(production.Key, expansionIndex)])
private bool IsTerminal(string symbol, BNF bnf) { return(!bnf.ContainsKey(symbol)); }
HashSet <string> GetExpansionFirstSet(string production, int expansionIndex, BNF bnf, FirstSetTable firstSets) { if (firstSets.ExpansionSets.ContainsKey((production, expansionIndex))) { return(firstSets.ExpansionSets[(production, expansionIndex)]); }
bool IsNonTerminal(string symbol, BNF bnf) { return(!IsTerminal(symbol, bnf)); }