/
GrammarAnalysis.cs
123 lines (103 loc) · 4.12 KB
/
GrammarAnalysis.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Shields.DataStructures;
namespace GrammarTools
{
public class GrammarAnalysis
{
public Grammar Grammar { get; }
private GrammarChomskyType? grammarType;
public GrammarAnalysis(Grammar grammar)
{
Grammar = grammar;
}
public GrammarChomskyType GrammarType
{
get
{
if (grammarType != null) return grammarType.Value;
var usedStartSymbol = false;
var containsStartToEpsilon = false;
var canBeType1 = true;
var canBeType3 = true;
var canBeType2 = true;
foreach (var rule in Grammar.Rules.TakeWhile(rule => canBeType1 || canBeType2 || canBeType3))
{
if (!usedStartSymbol && rule.WordToInsert.Contains(Grammar.StartSymbol))
{
usedStartSymbol = true;
if (containsStartToEpsilon)
canBeType1 = false;
}
if (canBeType1)
{
if (rule.WordToReplace.Length > rule.WordToInsert.Length)
{
if (rule.WordToReplace.Length == 1 && rule.WordToReplace[0] == Grammar.StartSymbol)
{
containsStartToEpsilon = true;
if (usedStartSymbol)
canBeType1 = false;
}
else
canBeType1 = false;
}
}
if (canBeType2)
{
if (rule.WordToReplace.Length != 1)
canBeType2 = false;
else if (rule.WordToReplace.IsTerminalWord)
canBeType2 = false;
}
if (canBeType3)
{
if (rule.WordToReplace.Length != 1)
canBeType3 = false;
else if (rule.WordToReplace.IsTerminalWord)
canBeType3 = false;
else if (rule.WordToInsert.Length > 2)
canBeType3 = false;
else if (rule.WordToInsert.Length == 2 && rule.WordToInsert[0] is NonTerminalSymbol)
canBeType3 = false;
}
}
if (canBeType3)
grammarType = GrammarChomskyType.Type3;
else if (canBeType2)
grammarType = GrammarChomskyType.Type2;
else if (canBeType1)
grammarType = GrammarChomskyType.Type1;
else
grammarType = GrammarChomskyType.Type0;
return grammarType.Value;
}
}
public IEnumerable<Tuple<Word, int>> Derive()
{
var derivedWords = new HashSet<string>();
var pq = new PairingHeap<Word, int>();
pq.Add(new Word(Grammar.StartSymbol), 0);
var rules = Grammar.Rules.OrderBy(r => r.WordToInsert.Length - r.WordToReplace.Length).ToArray();
while (pq.Count > 0)
{
var elementToDerive = pq.Min;
pq.Remove(elementToDerive);
var wordToDerive = elementToDerive.Key;
foreach (var nw in rules.SelectMany(rule => wordToDerive.ReplaceAll(rule.WordToReplace, rule.WordToInsert))
.Where(nw => !derivedWords.Contains(nw.ToString())))
{
derivedWords.Add(nw.ToString());
pq.Add(nw, nw.Length);
yield return Tuple.Create(nw, wordToDerive.Length);
}
}
}
public Grammar ToChomskyNormalform()
{
return ChomskyNormalform.Transform(this);
}
}
}