Esempio n. 1
0
        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));
 }