예제 #1
0
        public void TestSimple2()
        {
            var a1 = new ConcreteDfa <bool, char>(); // ab

            a1.AddEdge(0, 'b', 3);
            a1.AddEdge(0, 'a', 1);
            a1.AddEdge(1, 'b', 2);
            a1.Labels[0] = false;
            a1.Labels[1] = false;
            a1.Labels[2] = true;
            a1.Labels[3] = false;

            var a2 = new ConcreteDfa <bool, char>(); // (ab)*

            a2.AddEdge(0, 'a', 1);
            a2.AddEdge(1, 'b', 0);
            a2.Labels[0] = true;
            a2.Labels[1] = false;

            var merged1 = DfaMerger <int, char> .Merge(
                new Dictionary <int, IDfa <bool, char> > {
                { 1, a1 }, { 2, a2 }
            },
                (labels) => !labels.Any()? 0 : labels.Min());

            Assert.AreEqual(2, GetTargetLabel(merged1, string.Empty, 0));
            Assert.AreEqual(0, GetTargetLabel(merged1, "a", 0));
            Assert.AreEqual(1, GetTargetLabel(merged1, "ab", 0));
            Assert.AreEqual(2, GetTargetLabel(merged1, "abab", 0));
            Assert.AreEqual(2, GetTargetLabel(merged1, "ababab", 0));
            Assert.AreEqual(0, GetTargetLabel(merged1, "ababa", 0));

            Assert.IsTrue(DfaEquivalence <int, char> .AreEquivalent(merged1, merged1));

            var merged2 = new ConcreteDfa <int, char>();

            merged2.AddEdge(0, 'a', 1);
            merged2.AddEdge(1, 'b', 2);
            merged2.AddEdge(2, 'a', 3);
            merged2.AddEdge(3, 'b', 4);
            merged2.AddEdge(4, 'a', 3);

            merged2.AddEdge(0, 'b', 5);
            merged2.AddEdge(1, 'a', 5);
            merged2.AddEdge(2, 'b', 5);
            merged2.AddEdge(3, 'a', 5);
            merged2.AddEdge(4, 'b', 5);

            merged2.AddEdge(5, 'a', 5);
            merged2.AddEdge(5, 'b', 5);

            merged2.Labels[0] = 2;
            merged2.Labels[1] = 0;
            merged2.Labels[2] = 1;
            merged2.Labels[3] = 0;
            merged2.Labels[4] = 2;
            merged2.Labels[5] = 0;

            Assert.IsTrue(DfaEquivalence <int, char> .AreEquivalent(merged1, merged2));
        }
예제 #2
0
        public void SingleDfaTest()
        {
            var grammar = new CompiledGrammar <Tag>();
            var rules   = new Dictionary <Tag, IDfa <Optional <Rule <Tag> >, Tag> >();

            var dfa = new ConcreteDfa <Optional <Rule <Tag> >, Tag>();

            dfa.AddEdge(0, Tag.A, 1);
            dfa.AddEdge(1, Tag.A, 2);
            dfa.AddEdge(1, Tag.B, 1);
            dfa.AddEdge(2, Tag.A, 2);

            dfa.Labels.Add(0, Optional <Rule <Tag> > .None());
            dfa.Labels.Add(1, Optional <Rule <Tag> > .None());
            var r = new Rule <Tag>
            {
                Lhs = Tag.A
            };

            dfa.Labels.Add(2, Optional <Rule <Tag> > .Some(r));

            rules.Add(Tag.A, dfa);
            grammar.Rules = rules;

            var output = NullablesHelper <Tag> .GetNullableSymbols(grammar);

            Assert.AreEqual(1, output.Count);
        }
예제 #3
0
        private static DfaAndState <string> GetMockState()
        {
            IDfa <Optional <Rule <string> >, string> dfa = new ConcreteDfa <Optional <Rule <string> >, string>();

            return(new DfaAndState <string> {
                Dfa = dfa, State = dfa.StartingState()
            });
        }
예제 #4
0
        private static ConcreteDfa <bool, char> CreateLetterPlusDfa(char letter)
        {
            var result = new ConcreteDfa <bool, char>(); // 'letter'+

            result.AddEdge(0, letter, 1);
            result.AddEdge(1, letter, 1);
            result.Labels[0] = false;
            result.Labels[1] = true;
            return(result);
        }
예제 #5
0
        public void AlmostAllNullable()
        {
            var dfa1 = new ConcreteDfa <Optional <Rule <Tag> >, Tag>();

            dfa1.AddEdge(0, Tag.B, 0);
            dfa1.AddEdge(0, Tag.A, 1);

            var rules1 = new Rule <Tag>()
            {
                Lhs = Tag.A,
                Rhs = new ConcatRegex <Tag>(new AtomicRegex <Tag>(Tag.B), new AtomicRegex <Tag>(Tag.A))
            };

            dfa1.Labels.Add(0, Optional <Rule <Tag> > .Some(rules1));
            var rules2 = new Rule <Tag>
            {
                Lhs = Tag.A,
                Rhs = new ConcatRegex <Tag>(new AtomicRegex <Tag>(Tag.B), new AtomicRegex <Tag>(Tag.B))
            };

            dfa1.Labels.Add(1, Optional <Rule <Tag> > .Some(rules2));

            var dfa2 = new ConcreteDfa <Optional <Rule <Tag> >, Tag>();

            dfa2.AddEdge(0, Tag.A, 1);
            dfa2.AddEdge(0, Tag.B, 0);
            dfa2.AddEdge(0, Tag.B, 3);
            dfa2.AddEdge(1, Tag.A, 2);
            dfa2.AddEdge(2, Tag.A, 2);
            dfa2.AddEdge(2, Tag.B, 2);

            var rules3 = new Rule <Tag>()
            {
                Lhs = Tag.B,
                Rhs = new ConcatRegex <Tag>(new AtomicRegex <Tag>(Tag.A), new AtomicRegex <Tag>(Tag.A))
            };

            dfa2.Labels.Add(0, Optional <Rule <Tag> > .None());
            dfa2.Labels.Add(1, Optional <Rule <Tag> > .None());
            dfa2.Labels.Add(2, Optional <Rule <Tag> > .Some(rules3));
            dfa2.Labels.Add(3, Optional <Rule <Tag> > .None());

            var grammar = new CompiledGrammar <Tag>();
            var rules   = new Dictionary <Tag, IDfa <Optional <Rule <Tag> >, Tag> > {
                { Tag.A, dfa1 }, { Tag.B, dfa2 }
            };

            grammar.Rules = rules;
            var nullables = NullablesHelper <Tag> .GetNullableSymbols(grammar);

            Assert.AreEqual(5, nullables.Count);
        }
예제 #6
0
        public void TestSimple()
        {
            var a1 = CreateLetterPlusDfa('a'); // a+
            var a2 = CreateLetterPlusDfa('b'); // b+

            Assert.AreEqual(true, GetTargetLabel(a2, "bbb", false));
            Assert.AreEqual(false, GetTargetLabel(a2, string.Empty, false));

            var merged = DfaMerger <int, char> .Merge(
                new Dictionary <int, IDfa <bool, char> > {
                { 1, a1 }, { 2, a2 }
            },
                (labels) => !labels.Any()? 0 : labels.Min());

            Assert.AreEqual(1, GetTargetLabel(merged, "a", 0));
            Assert.AreEqual(2, GetTargetLabel(merged, "b", 0));
            Assert.AreEqual(2, GetTargetLabel(merged, "bb", 0));
            Assert.AreEqual(2, GetTargetLabel(merged, "bbbbb", 0));
            Assert.AreEqual(1, GetTargetLabel(merged, "aaaaaaaaaa", 0));
            Assert.AreEqual(0, GetTargetLabel(merged, string.Empty, 0));
            Assert.AreEqual(0, GetTargetLabel(merged, "baa", 0));

            var merged2 = new ConcreteDfa <int, char>();

            merged2.AddEdge(0, 'a', 1);
            merged2.AddEdge(0, 'b', 2);

            merged2.AddEdge(1, 'a', 1);
            merged2.AddEdge(1, 'b', 3);

            merged2.AddEdge(2, 'a', 3);
            merged2.AddEdge(2, 'b', 2);

            merged2.AddEdge(3, 'a', 3);
            merged2.AddEdge(3, 'b', 3);

            merged2.Labels[0] = 0;
            merged2.Labels[1] = 1;
            merged2.Labels[2] = 2;
            merged2.Labels[3] = 0;

            Assert.IsTrue(DfaEquivalence <int, char> .AreEquivalent(merged, merged2));
        }
예제 #7
0
        public void TestConflict()
        {
            var a1 = CreateLetterPlusDfa('a'); // a+

            var merged1 = DfaMerger <int, char> .Merge(
                new Dictionary <int, IDfa <bool, char> > {
                { 1, a1 }, { 2, a1 }
            },
                labels => !labels.Any()? 0 : labels.Min());

            Assert.AreEqual(0, GetTargetLabel(merged1, string.Empty, 0));
            Assert.AreEqual(1, GetTargetLabel(merged1, "a", 0));
            Assert.AreEqual(0, GetTargetLabel(merged1, "b", 0));

            var a1Numeric = new ConcreteDfa <int, char>(); // a+

            a1Numeric.AddEdge(0, 'a', 1);
            a1Numeric.AddEdge(1, 'a', 1);
            a1Numeric.Labels[0] = 0;
            a1Numeric.Labels[1] = 1;

            Assert.IsTrue(DfaEquivalence <int, char> .AreEquivalent(merged1, a1Numeric));
        }
예제 #8
0
        public void TestGetAllStates()
        {
            var dfa = new ConcreteDfa <bool, char>();

            Assert.AreEqual(dfa.GetAllStates().Count, 1);

            dfa.AddEdge(0, 'a', 1);
            dfa.AddEdge(1, 'b', 2);

            Assert.AreEqual(dfa.GetAllStates().Count, 3);

            dfa.AddEdge(0, 'c', 3);
            dfa.AddEdge(3, 'd', 2);
            dfa.AddEdge(0, 'e', 2);

            Assert.AreEqual(dfa.GetAllStates().Count, 4);

            dfa.AddEdge(2, 'f', 4);
            dfa.AddEdge(4, 'g', 0);
            dfa.AddEdge(0, 'h', 5);

            Assert.AreEqual(dfa.GetAllStates().Count, 6);
        }
예제 #9
0
        public void ThreeDfasTest()
        {
            var firstDfa = new Dfa <string>();

            firstDfa.AddEdge(0, "D", 1);
            firstDfa.AddEdge(0, "F", 4);
            firstDfa.AddEdge(0, "C", 3);
            firstDfa.AddEdge(0, "B", 2);
            firstDfa.AddEdge(2, "B", 7);
            firstDfa.AddEdge(3, "A", 5);
            firstDfa.AddEdge(4, "G", 6);
            firstDfa.AddEdge(6, "A", 5);

            var secondDfa = new Dfa <string>();

            secondDfa.AddEdge(0, "B", 1);
            secondDfa.AddEdge(0, "C", 2);
            secondDfa.AddEdge(2, "A", 3);
            secondDfa.AddEdge(1, "E", 4);

            var thirdDfa = new Dfa <string>();

            var rules = new Dictionary <string, IDfa <Optional <Rule <string> >, string> >
            {
                ["A"] = firstDfa,
                ["B"] = secondDfa,
                ["C"] = thirdDfa
            };

            var grammar = new CompiledGrammar <string> {
                Rules = rules
            };

            var nullables = new List <DfaAndState <string> >
            {
                new DfaAndState <string> {
                    Dfa = thirdDfa, State = new ValueState <int>(0)
                }
            };

            var firstSymbols = FirstHelper <string> .GetFirstSymbols(grammar, nullables);

            var expected = new[]
            {
                new[] { "A,B,C,D,F", string.Empty, "A,B,C,D,F", "A,B,C,D,F", "G", string.Empty, "A,B,C,D,F", string.Empty },
                new[] { "A,B,C,D,F", "E", "A,B,C,D,F", string.Empty, string.Empty },
                new[] { string.Empty }
            };
            var size = new int[] { 8, 5, 1 };
            var dfas = new ConcreteDfa <Optional <Rule <string> >, string>[] { firstDfa, secondDfa, thirdDfa };

            for (int test = 0; test < 3; ++test)
            {
                for (int i = 0; i < size[test]; ++i)
                {
                    var stateEntity = new DfaAndState <string> {
                        Dfa = dfas[test], State = new ValueState <int>(i)
                    };
                    string output = string.Join(',', firstSymbols[stateEntity].OrderBy(x => x));
                    Assert.AreEqual(expected[test][i], output, $"Unexpected output on test ({test}, {i}): expected is [{expected[test][i]}], but found [{output}]");
                }
            }
        }
예제 #10
0
        public void Test1()
        {
            // Z –> d | XYZ
            // Y –> c | a
            // X –> Y | ε

            var rules = new Dictionary <char, IDfa <Optional <Rule <char> >, char> >();

            var zdfa = new ConcreteDfa <Optional <Rule <char> >, char>();

            zdfa.Magic = 0;
            zdfa.AddEdge(0, 'X', 1);
            zdfa.AddEdge(1, 'Y', 2);
            zdfa.AddEdge(2, 'Z', 3);
            zdfa.AddEdge(0, 'd', 3);
            zdfa.Labels.Add(0, REJECT);
            zdfa.Labels.Add(1, REJECT);
            zdfa.Labels.Add(2, REJECT);
            zdfa.Labels.Add(3, this.ACCEPT('Z'));
            rules.Add('Z', zdfa);

            var ydfa = new ConcreteDfa <Optional <Rule <char> >, char>();

            ydfa.Magic = 1;
            ydfa.AddEdge(0, 'c', 1);
            ydfa.AddEdge(0, 'a', 1);
            ydfa.Labels.Add(0, REJECT);
            ydfa.Labels.Add(1, this.ACCEPT('Y'));
            rules.Add('Y', ydfa);

            var xdfa = new ConcreteDfa <Optional <Rule <char> >, char>();

            xdfa.Magic = 2;
            xdfa.AddEdge(0, 'Y', 1);
            xdfa.Labels.Add(0, this.ACCEPT('X'));
            xdfa.Labels.Add(1, this.ACCEPT('X'));
            rules.Add('X', xdfa);

            var grammar = new CompiledGrammar <char> {
                Rules = rules, StartSymbol = 'Z'
            };
            var nullables = NullablesHelper <char> .GetNullableSymbols(grammar);

            {
                var output = nullables.OrderBy(x => (x.Dfa as ConcreteDfa <Optional <Rule <char> >, char>).Magic).ThenBy(x => (x.State as ValueState <int>).Value).ToList();
                Assert.AreEqual(4, output.Count);
                Assert.AreEqual(0, (output[0].Dfa as ConcreteDfa <Optional <Rule <char> >, char>).Magic);
                Assert.AreEqual(3, (output[0].State as ValueState <int>).Value);
                Assert.AreEqual(1, (output[1].Dfa as ConcreteDfa <Optional <Rule <char> >, char>).Magic);
                Assert.AreEqual(1, (output[1].State as ValueState <int>).Value);
                Assert.AreEqual(2, (output[2].Dfa as ConcreteDfa <Optional <Rule <char> >, char>).Magic);
                Assert.AreEqual(0, (output[2].State as ValueState <int>).Value);
                Assert.AreEqual(2, (output[3].Dfa as ConcreteDfa <Optional <Rule <char> >, char>).Magic);
                Assert.AreEqual(1, (output[3].State as ValueState <int>).Value);
            }

            var first = FirstHelper <char> .GetFirstSymbols(grammar, nullables);

            {
                var output = first.OrderBy(x => (x.Key.Dfa as ConcreteDfa <Optional <Rule <char> >, char>).Magic).ThenBy(x => (x.Key.State as ValueState <int>).Value).ToList();

                var symbols = output[0].Value.ToList(); // Z0
                symbols.Sort();
                Assert.AreEqual(5, symbols.Count);
                Assert.AreEqual('X', symbols[0]);
                Assert.AreEqual('Y', symbols[1]);
                Assert.AreEqual('a', symbols[2]);
                Assert.AreEqual('c', symbols[3]);
                Assert.AreEqual('d', symbols[4]);

                symbols = output[1].Value.ToList(); // Z1
                symbols.Sort();
                Assert.AreEqual(3, symbols.Count);
                Assert.AreEqual('Y', symbols[0]);
                Assert.AreEqual('a', symbols[1]);
                Assert.AreEqual('c', symbols[2]);

                symbols = output[2].Value.ToList(); // Z2
                symbols.Sort();
                Assert.AreEqual(6, symbols.Count);
                Assert.AreEqual('X', symbols[0]);
                Assert.AreEqual('Y', symbols[1]);
                Assert.AreEqual('Z', symbols[2]);
                Assert.AreEqual('a', symbols[3]);
                Assert.AreEqual('c', symbols[4]);
                Assert.AreEqual('d', symbols[5]);

                symbols = output[3].Value.ToList(); // Z3
                Assert.AreEqual(0, symbols.Count);

                symbols = output[4].Value.ToList(); // Y0
                symbols.Sort();
                Assert.AreEqual(2, symbols.Count);
                Assert.AreEqual('a', symbols[0]);
                Assert.AreEqual('c', symbols[1]);

                symbols = output[5].Value.ToList(); // Y1
                Assert.AreEqual(0, symbols.Count);

                symbols = output[6].Value.ToList(); // X0
                symbols.Sort();
                Assert.AreEqual(3, symbols.Count);
                Assert.AreEqual('Y', symbols[0]);
                Assert.AreEqual('a', symbols[1]);
                Assert.AreEqual('c', symbols[2]);

                symbols = output[7].Value.ToList(); // X1
                Assert.AreEqual(0, symbols.Count);
            }

            var follow = FollowHelper <char> .GetFollowSymbols(grammar, nullables, first.InverseRelation(), '\uffff');

            {
                var output = follow.OrderBy(x => (x.Key.Dfa as ConcreteDfa <Optional <Rule <char> >, char>).Magic).ThenBy(x => (x.Key.State as ValueState <int>).Value).ToList();

                var symbols = output[0].Value.ToList(); // Z3
                Assert.AreEqual(1, symbols.Count);
                Assert.AreEqual('\uffff', symbols[0]);

                symbols = output[1].Value.ToList(); // Y1
                symbols.Sort();
                Assert.AreEqual(6, symbols.Count);
                Assert.AreEqual('X', symbols[0]);
                Assert.AreEqual('Y', symbols[1]);
                Assert.AreEqual('Z', symbols[2]);
                Assert.AreEqual('a', symbols[3]);
                Assert.AreEqual('c', symbols[4]);
                Assert.AreEqual('d', symbols[5]);

                symbols = output[2].Value.ToList(); // X0
                symbols.Sort();
                Assert.AreEqual(3, symbols.Count);
                Assert.AreEqual('Y', symbols[0]);
                Assert.AreEqual('a', symbols[1]);
                Assert.AreEqual('c', symbols[2]);

                symbols = output[3].Value.ToList(); // X1
                symbols.Sort();
                Assert.AreEqual(3, symbols.Count);
                Assert.AreEqual('Y', symbols[0]);
                Assert.AreEqual('a', symbols[1]);
                Assert.AreEqual('c', symbols[2]);
            }
        }
예제 #11
0
        public void Test0SimpleParens()
        {
            var rules = new Dictionary <char, IDfa <Optional <Rule <char> >, char> >();

            var dfa = new ConcreteDfa <Optional <Rule <char> >, char>();

            dfa.AddEdge(0, '(', 1);
            dfa.AddEdge(1, 'S', 2);
            dfa.AddEdge(2, ')', 3);
            dfa.Labels.Add(0, this.ACCEPT('S'));
            dfa.Labels.Add(1, REJECT);
            dfa.Labels.Add(2, REJECT);
            dfa.Labels.Add(3, this.ACCEPT('S'));
            rules.Add('S', dfa);
            var grammar = new CompiledGrammar <char> {
                Rules = rules, StartSymbol = 'S'
            };
            var nullables = NullablesHelper <char> .GetNullableSymbols(grammar);

            {
                Assert.AreEqual(2, nullables.Count);
                var states = nullables.Select(x => ((ValueState <int>)x.State).Value).ToList();
                states.Sort();
                Assert.AreEqual(0, states[0]);
                Assert.AreEqual(3, states[1]);
            }

            var first = FirstHelper <char> .GetFirstSymbols(grammar, nullables);

            {
                var output = first.OrderBy(x => (x.Key.State as ValueState <int>).Value).ToList();

                var symbols = output[0].Value.ToList();
                Assert.AreEqual(1, symbols.Count);
                Assert.AreEqual('(', symbols[0]);

                symbols = output[1].Value.ToList();
                symbols.Sort();
                Assert.AreEqual(3, symbols.Count);
                Assert.AreEqual('(', symbols[0]);
                Assert.AreEqual(')', symbols[1]);
                Assert.AreEqual('S', symbols[2]);

                symbols = output[2].Value.ToList();
                Assert.AreEqual(1, symbols.Count);
                Assert.AreEqual(')', symbols[0]);

                symbols = output[3].Value.ToList();
                Assert.AreEqual(0, symbols.Count);
            }

            var follow = FollowHelper <char> .GetFollowSymbols(grammar, nullables, first.InverseRelation(), '\uffff');

            {
                var output = follow.OrderBy(x => (x.Key.State as ValueState <int>).Value).ToList();

                var symbols = output[0].Value.ToList(); // state 0
                symbols.Sort();
                Assert.AreEqual(2, symbols.Count);
                Assert.AreEqual(')', symbols[0]);
                Assert.AreEqual('\uffff', symbols[1]);

                symbols = output[1].Value.ToList(); // state 3
                symbols.Sort();
                Assert.AreEqual(2, symbols.Count);
                Assert.AreEqual(')', symbols[0]);
                Assert.AreEqual('\uffff', symbols[1]);
            }
        }