bool VerifyProductionReferences() { var success = true; var ntReferences = new Dictionary <Segment, List <ConfigToken> >(); var ntDefinitions = new Dictionary <Segment, List <ConfigToken> >(); foreach (var entryPoint in _config.EntryPoints) { AddToList(ntReferences, entryPoint.Segment, entryPoint.NonTerminal); } foreach (var nonTerminal in _config.Productions) { AddToList(ntDefinitions, nonTerminal.Segment, nonTerminal.Target); foreach (var rule in nonTerminal.Rules) { foreach (var segment in rule.Segments) { if (segment.Token.Type == ConfigTokenType.NonTerminal) { AddToList(ntReferences, segment.Segment, segment.Token); } } } } foreach (var pair in ntDefinitions) { ntReferences.Remove(pair.Key); var list = pair.Value; for (var i = 1; i < list.Count; i++) { var token = list[i]; ReporterHelper.AddWarning(_reporter, token, "The non-terminal <{0}> has already been defined.", token.Text); } } foreach (var pair in ntReferences) { foreach (var token in pair.Value) { ReporterHelper.AddError(_reporter, token, "The non-terminal <{0}> is not defined.", token.Text); success = false; } } return(success); }
Graph BuildDFA(Dictionary <string, int> typeLookup) { var nfa = new Graph <NodeData, CharSet> .Builder(); for (var i = 0; i < _config.States.Count; i++) { var state = _config.States[i]; if (state.Rules.Count == 0) { ReporterHelper.AddError(_reporter, state.Label, "The state '{0}' does not define any rules.", state.Label.Text); continue; } var startState = nfa.NewState(true, new NodeData(i, null)); for (var j = 0; j < state.Rules.Count; j++) { var rule = state.Rules[j]; ReElement element; if (!typeLookup.TryGetValue(rule.Token.Text, out var endStateID)) { endStateID = typeLookup.Count; typeLookup.Add(rule.Token.Text, endStateID); } try { element = ReParser.Parse(rule.Regex.Text); } catch (ReParseException ex) { ReporterHelper.AddError(_reporter, rule.Regex, ex.Message); continue; } if (element.MatchesEmptyString) { ReporterHelper.AddWarning( _reporter, rule.Regex, "This regular expression claims to match the empty string, " + "this is not supported and usually indicates a typeo in the regular expression"); } element.GenerateNFA(nfa, startState, nfa.NewState(false, new NodeData(null, endStateID, j))); } } return(FATools.CreateDfa(nfa.Graph)); }
void PopulateTopLevelSegments() { if (_config.EntryPoints.Count > 0) { var segments = new Dictionary <Segment, bool>(); foreach (var entryPoint in _config.EntryPoints) { var segment = GetNonTerminal(entryPoint.NonTerminal.Text); entryPoint.Segment = segment; if (_ntTypes.TryGetValue(segment, out var cUsing)) { entryPoint.Using = cUsing; } if (segments.ContainsKey(segment)) { ReporterHelper.AddWarning(_reporter, entryPoint.NonTerminal, "The non-terminal <{0}> is already an entry point.", entryPoint.NonTerminal.Text); } else { segments.Add(segment, true); } } _config.TopLevelSegments = SegmentSet.New(segments.Keys); } else if (_config.Productions.Count > 0) { _config.TopLevelSegments = SegmentSet.New(new Segment[] { _config.Productions[0].Segment, }); _config.EntryPoints.Add(new ConfigEntryPoint() { Segment = _config.Productions[0].Segment, NonTerminal = _config.Productions[0].Target, Using = _config.Productions[0].Using, }); } else { _config.TopLevelSegments = SegmentSet.EmptySet; } }
void DecorateRule(ConfigProduction cProduction, ConfigRule cRule, int ruleNum) { var cSegments = cRule.Segments; ImmutableArray <Segment> segments; if (cSegments.Count == 0) { cRule.FromPos = cProduction.Target.FromPos; cRule.ToPos = cProduction.Target.ToPos; segments = ImmutableArray <Segment> .Empty; } else { var builder = ImmutableArray.CreateBuilder <Segment>(cSegments.Count); cRule.FromPos = cSegments[0].Token.FromPos; cRule.ToPos = cSegments[cSegments.Count - 1].Token.ToPos; for (var i = 0; i < cSegments.Count; i++) { var cSegment = cSegments[i]; var segment = GetSegment(cSegment.Token, cSegment.Modifier); cSegment.Segment = segment; builder.Add(segment); } segments = builder.MoveToImmutable(); } var production = new Production(cProduction.Segment, segments); cRule.Production = production; PopulateCommand(cProduction, cRule, ruleNum); if (!_config.RuleLookup.ContainsKey(production)) { _config.RuleLookup.Add(production, cRule); } else { ReporterHelper.AddWarning(_reporter, cRule, "The production '{0}' has already been defined.", production); } }
void DetectUnreachableNonTerminals() { var references = new Dictionary <Segment, List <Segment> >(); foreach (var production in _config.Productions) { var list = new List <Segment>(); if (!references.TryGetValue(production.Segment, out list)) { list = new List <Segment>(); references.Add(production.Segment, list); } foreach (var rule in production.Rules) { foreach (var seg in rule.Segments) { var segment = seg.Segment; if (!segment.IsTerminal) { list.Add(segment); } } } } var reachable = new Dictionary <Segment, bool>(); var pending = new Queue <Segment>(); foreach (var entryPoint in _config.EntryPoints) { var segment = entryPoint.Segment; if (!reachable.ContainsKey(segment)) { pending.Enqueue(segment); reachable.Add(segment, true); } } while (pending.Count > 0) { var segment = pending.Dequeue(); if (references.TryGetValue(segment, out var reach)) { foreach (var next in reach) { if (!reachable.ContainsKey(next)) { pending.Enqueue(next); reachable.Add(next, true); } } } } foreach (var production in _config.Productions) { if (!reachable.ContainsKey(production.Segment)) { ReporterHelper.AddWarning(_reporter, production.Target, "The non-terminal <{0}> is not reachable.", production.Target.Text); } } }