/// <summary> /// Build all rules for nonterminal /// </summary> /// <param name="grammarRuleContext"></param> private void BuildGrammarRule(GrammarRuleContext grammarRuleContext) { string name = grammarRuleContext.grammarName().GetText(); //save start rule if (firstRuleName.Equals("")) { firstRuleName = name; } if (NonTerminals.ContainsKey(name)) { throw new GrammarBuilderException($"Nonterminal {name} is defined twice"); } var nonTerminal = NonTerminals[name] = new NonTerminal(name); ProductionsContext productions = grammarRuleContext.productions(); do { nonTerminal.Productions.Add(BuildProduction(productions.production())); productions = productions.productions(); } while (productions != null); }
/// <summary> /// Initialize NonTerminals and Terminals with rules. /// /// </summary> public void Build() { GrammarFileGrammarLexer speakLexer = new GrammarFileGrammarLexer(inputStream); CommonTokenStream commonTokenStream = new CommonTokenStream(speakLexer); GrammarFileGrammarParser grammarParser = new GrammarFileGrammarParser(commonTokenStream); foreach (var line in grammarParser.file().line()) { if (line.lexerRule() != null) { BuildLexerRule(line.lexerRule()); } else { BuildGrammarRule(line.grammarRule()); } } InputStartNonTerminal = StartNonTerminal = NonTerminals[firstRuleName]; if (NonTerminals.ContainsKey("startRule")) { throw new Exception("The name \"startRule\" is reserved, change the name for this nonterminal"); } NonTerminals.Add("startRule", new NonTerminal("startRule")); NonTerminals["startRule"].AddRule(new Production(productionRuleID++, new NonTerminalProduction(firstRuleName))); firstRuleName = "startRule"; StartNonTerminal = NonTerminals[firstRuleName]; ///Checking, that we have all terminals and nonterminals, which was mentioned in rules foreach (var nonTerminals in NonTerminals.Values) { foreach (var rule in nonTerminals.Productions) { foreach (var element in rule.ProductionElements) { if (element is TerminalProduction) { var e = element as TerminalProduction; if (e.needSetTerminal) { if (!Terminals.ContainsKey(e.Name)) { throw new Exception($"Nonterminal {e} is not defined"); } e.Terminal = Terminals[e.Name]; } } else if (element is NonTerminalProduction) { var e = element as NonTerminalProduction; if (!NonTerminals.ContainsKey(e.Name)) { throw new Exception($"Nonterminal {e} is not defined"); } e.NonTerminal = NonTerminals[e.Name]; } } } } //Calculate FIRST and FOLLOW for each nonterminal //First: CalculateFirst(); //Follow CalculateFollow(); }