public static void AssertBNF(BNFRule rule, string expectedName, params BasicBNFRule[] expetedOrs) { Assert.IsNotNull(rule); Assert.AreEqual(expectedName, rule.Name); Assert.AreEqual(expetedOrs.Length, rule.Count); for (int i = 0; i < expetedOrs.Length; i++) { Assert.AreEqual(expetedOrs[i], rule[i]); } }
private List <char> GetFirstChars(BNFRule rule) { if (rule.IsTerminal) { return new List <char> { rule.TerminalValue[0] } } ; else { return(rule.Alternatives .Select(a => a.FirstOrDefault()) .SelectMany(r => GetFirstChars(r)) .ToList()); } }
private bool IsRecursion(BNFRule rule, out BNFRule theOtherRule) { if (rule.Alternatives != null && rule.Alternatives.Count == 2) // jei yra 2 alternatyvos ir viena ju turi dvi taisykles, is kuriu viena yra pati taisykle 'rule' { var otherRule = rule.Alternatives.FirstOrDefault(r => r.Count == 1)?.FirstOrDefault(); theOtherRule = otherRule; if (otherRule == null) { return(false); } if (otherRule.IsTerminal) { return(rule.Alternatives.Any(rs => rs.Count == 2 && rs.Any(r => r.Equals(rule)) && rs.Any(r => r.TerminalValue == otherRule.TerminalValue))); } return(rule.Alternatives.Any(rs => rs.Count == 2 && rs.Any(r => r.Equals(rule)) && rs.Any(r => r.Equals(otherRule)))); } theOtherRule = null; return(false); }
private List <State> AddRule(BNFRule bnfRule, List <State> startingStates, bool shouldBeFinal, string lexemeType, RecursionState tracker = null, bool isFirstStateOfRecursion = false, State atomState = null, bool isRoot = false) { var newCurrentStates = new HashSet <State>(); if (IsRecursion(bnfRule, out var otherRule)) { List <State> unfinishedStates = startingStates; var finishedStates = new List <State>(); do { tracker = new RecursionState(); var someStates = AddRule(otherRule, unfinishedStates, shouldBeFinal, lexemeType, tracker, true, atomState, true); newCurrentStates.AddRange(someStates.Where(s => s.RecursionState != null && s.RecursionState.CreatedNewStateOnFirstStep)); var x = someStates .Where(s => !s.RecursionState.CreatedNewStateOnFirstStep) .Where(s => s.RecursionState.RecursionName == bnfRule.Name).ToList(); finishedStates.AddRange(x); unfinishedStates = someStates .Where(s => !s.RecursionState.CreatedNewStateOnFirstStep) .Where(s => s.RecursionState.RecursionName != bnfRule.Name) .ToList(); } while (unfinishedStates.Any()); foreach (var state in newCurrentStates) { foreach (var otherState in newCurrentStates) { foreach (var firstChar in otherState.RecursionState.FirstReccursionChars) { if (state.Transitions[firstChar] == null) { state.Transitions[firstChar] = otherState.RecursionState.FirstState; } } } state.RecursionState.RecursionName = bnfRule.Name; } newCurrentStates.AddRange(finishedStates); } else { if (bnfRule.IsAtom && atomState == null) { atomState = new State(); } foreach (var alternative in bnfRule.Alternatives) { var newTacker = isRoot && !bnfRule.IsAtom ? new RecursionState() : tracker;//?.Clone(); jei root, darai kopija if (bnfRule.IsAtom && tracker != null && isFirstStateOfRecursion) { newTacker.CreatedNewStateOnFirstStep = false; } var currentStates = startingStates; for (var i = 0; i < alternative.Count; i++) { var rule = alternative[i]; if (rule.IsTerminal) { currentStates = AddTerminalRule(rule, currentStates, shouldBeFinal && i == alternative.Count - 1, lexemeType, newTacker, isFirstStateOfRecursion && i == 0, atomState); } else { currentStates = AddRule(rule, currentStates, shouldBeFinal && i == alternative.Count - 1, lexemeType, newTacker, isFirstStateOfRecursion && i == 0, atomState); } } newCurrentStates.AddRange(currentStates); } } return(newCurrentStates.ToList()); }
private static List <State> AddTerminalRule(BNFRule bnfRule, List <State> currentStates, bool shouldBeFinal, string lexemeType, RecursionState tracker = null, bool isFirstStateOfRecursion = false, State atomState = null) { var newCurrentStates = new HashSet <State>(); foreach (var cs in currentStates) { var newTracker = tracker;//?.Clone(); var currentState = cs; var chars = bnfRule.TerminalValue.ToCharArray(); for (var j = 0; j < chars.Length; j++) { var c = chars[j]; if (currentState.Transitions[c] != null)// jei is einamos busenos jau yra perejimas su duotu simboliu { currentState = currentState.Transitions[c]; if (shouldBeFinal && j == chars.Length - 1 && !currentState.IsFinal) // jei paskutinis einamos alternatyvos simbolis { currentState.IsFinal = true; currentState.LexemeType = lexemeType; } if (tracker != null && atomState != null && j == 0 && isFirstStateOfRecursion)// && atomState.RecursionState != null) { //atomState.RecursionState.FirstReccursionChars.Add(c); tracker.CreatedNewStateOnFirstStep = false; } } else { var newState = atomState ?? new State(); if (newTracker != null && j == 0 && isFirstStateOfRecursion) { newTracker.CreatedNewStateOnFirstStep = true; newTracker.FirstState = newState; newTracker.FirstReccursionChars.Add(c); } if (shouldBeFinal && j == chars.Length - 1) // jei paskutinis einamos alternatyvos simbolis { newState.IsFinal = true; newState.LexemeType = lexemeType; } currentState.Transitions[c] = newState; currentState = newState; } } if (newTracker != null) { if (currentState.RecursionState == null) { currentState.RecursionState = newTracker.Clone(); } else { currentState.RecursionState.CreatedNewStateOnFirstStep = newTracker.CreatedNewStateOnFirstStep; currentState.RecursionState.FirstState = newTracker.FirstState; } } newCurrentStates.Add(currentState); } return(newCurrentStates.ToList()); }
private BnfData GetRules(string[] BNFRules) { var rules = new List <BNFRule>(); var helpers = new List <BNFRule>(); var skippableRules = new List <string>(); foreach (var rule in BNFRules) { var newRootRule = new BNFRule { IsTerminal = false, Alternatives = new List <List <BNFRule> >() }; var x = rule.Split("::="); var name = x[0].Trim(); List <BNFRule> currentRules; if (name.StartsWith('*')) { currentRules = helpers; name = name.Substring(1); } else if (name.StartsWith('+')) { currentRules = helpers; name = name.Substring(1); newRootRule.IsAtom = true; } else if (name.StartsWith('s')) { currentRules = rules; name = name.Substring(1); skippableRules.Add(name.Substring(1, name.Length - 2)); } else { currentRules = rules; } newRootRule.Name = name.Substring(1, name.Length - 2); var alternatives = x[1].Split(" | "); foreach (var alternative in alternatives) { var newRules = new List <BNFRule>(); var altRules = alternative.Trim().Split(' '); // neleidzia turet tarpo simbolio. (\"[^\"]*\")|(<[^\"]*>) foreach (var r in altRules) { var altRule = r.Trim(); BNFRule newRule; if (altRule.StartsWith('\"') && altRule.EndsWith('\"')) { newRule = new BNFRule { IsTerminal = true, TerminalValue = ReplaceWithEscapeChars(altRule.Substring(1, altRule.Length - 2)) }; } else { newRule = new BNFRule { IsTerminal = false, Name = ReplaceWithEscapeChars(altRule.Substring(1, altRule.Length - 2)) }; } newRules.Add(newRule); } newRootRule.Alternatives.Add(newRules); } currentRules.Add(newRootRule); } return(new BnfData { Rules = rules, HelperRules = helpers, SkippableRules = skippableRules }); }