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);
        }
Beispiel #2
0
        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);
                }
            }
        }