private Nonterminal Map(NonterminalExpr rule) { if (!Nonterminals.TryGetValue(rule, out var mapped)) { mapped = new Nonterminal(rule.Name); Nonterminals.Add(rule, mapped); foreach (var chain in rule.Body) { var body = new List <Symbol>(); foreach (var symbol in chain) { switch (symbol) { case TerminalExpr terminal: body.Add(Map(terminal)); break; case NonterminalExpr nonterminal: body.Add(Map(nonterminal)); break; } } Productions.Add(new Production(mapped, body)); } } return(mapped); }
private void MakeIsNullable() { var nullables = new HashSet <Symbol>(); var loop = true; while (loop) { loop = false; foreach (var rule in Nonterminals.Where(rule => !nullables.Contains(rule))) { foreach (var production in rule.Body) { var count = production.Count(symbol => !nullables.Contains(symbol)); if (count == 0) { loop = nullables.Add(production.Head); break; } } } } foreach (var nullable in nullables) { nullable.IsNullable = true; } }
public int VerifyLLk() { for (int k = 1; k <= 10; k++) { GenerateFollowK(k); ParserTable.Clear(); var result = true; Nonterminals.ForEach(n => { result = result && Verify(n, k); }); if (result == true) { return(k); } } return(-1); }
public Grammar( SymbolCache <TTokenKind, Terminal <TTokenKind> > terminals, SymbolCache <TNonterminal, Nonterminal> nonterminals, Nonterminal startSymbol, IEnumerable <Production> productions, Func <Grammar <TTokenKind, TNonterminal>, IFollowSymbolsAnalyzer <TTokenKind> > analyzerFactory) { if (productions == null) { throw new ArgumentNullException(nameof(productions)); } StartSymbol = startSymbol ?? throw new ArgumentNullException(nameof(startSymbol)); Nonterminals = nonterminals ?? throw new ArgumentNullException(nameof(nonterminals)); Terminals = terminals ?? throw new ArgumentNullException(nameof(terminals)); // Productions are numbered 0,1,2,...,^Productions.Count var prods = new List <Production>(); // Variables (productions on the shorter form (A -> α | β | ...) are numbered 0,1,...,^Variables.Count var productionMap = Nonterminals.ToDictionary(symbol => symbol, _ => new List <(int, Production)>()); int index = 0; foreach (var production in productions) { prods.Add(production); productionMap[production.Head].Add((index, production)); index += 1; } ProductionsFor = productionMap.ToImmutableDictionary(kvp => kvp.Key, kvp => (IReadOnlyList <(int, Production)>)kvp.Value); if (prods.Count == 0) { throw new ArgumentException("The productions are empty.", nameof(productions)); } Productions = prods; // Calculate lookahead sets (Erasable, First, Follow) using strategy provided by the caller _analyzer = analyzerFactory(this); }
public void ReadFromFile(string filePath) { int number = 1; string[] lines = System.IO.File.ReadAllLines(@filePath); foreach (string line in lines) { string[] parts = line.Split("-"); Nonterminals.Add(parts[0]); string[] fileProductions = parts[1].Split("|"); var havePoductions = Productions.TryGetValue(parts[0], out var productions); if (!havePoductions) { productions = new List <string>(); } foreach (string production in fileProductions) { productions.Add(production); ProductionNumber.Add(Tuple.Create(parts[0], production), number); number++; } Productions.Add(parts[0], productions); } }
public Nonterminal GetNonterminal(string name) { return(Nonterminals.Where(o => o.Name == name).FirstOrDefault()); }