Skip to content

Commit 4c2821c

Browse files
authored
Fix hopcroft DFA minimization and add plot graph function
1 parent 5d3a828 commit 4c2821c

File tree

2 files changed

+177
-32
lines changed

2 files changed

+177
-32
lines changed

ParserGenerator.cs

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/*
22
33
Copyright (C) 2019. rollrat All Rights Reserved.
44
@@ -13,41 +13,24 @@
1313

1414
namespace ParserGenerator
1515
{
16-
public class ParserAction
17-
{
18-
public Action<ParsingTree.ParsingTreeNode> SemanticAction;
19-
public static ParserAction Create(Action<ParsingTree.ParsingTreeNode> action)
20-
=> new ParserAction { SemanticAction = action };
21-
}
22-
2316
public class ParserProduction
2417
{
2518
public int index;
2619
public string production_name;
2720
public bool isterminal;
2821
public List<ParserProduction> contents = new List<ParserProduction>();
2922
public List<List<ParserProduction>> sub_productions = new List<List<ParserProduction>>();
30-
public List<ParserAction> temp_actions = new List<ParserAction>();
31-
public List<ParserAction> actions = new List<ParserAction>();
3223

3324
public static ParserProduction operator +(ParserProduction p1, ParserProduction p2)
3425
{
3526
p1.contents.Add(p2);
3627
return p1;
3728
}
3829

39-
public static ParserProduction operator +(ParserProduction pp, ParserAction ac)
40-
{
41-
pp.temp_actions.Add(ac);
42-
return pp;
43-
}
44-
4530
public static ParserProduction operator |(ParserProduction p1, ParserProduction p2)
4631
{
4732
p2.contents.Insert(0, p2);
4833
p1.sub_productions.Add(new List<ParserProduction>(p2.contents));
49-
p1.actions.AddRange(p2.temp_actions);
50-
p2.temp_actions.Clear();
5134
p2.contents.Clear();
5235
return p1;
5336
}
@@ -1283,7 +1266,6 @@ public ShiftReduceParser CreateShiftReduceParserInstance()
12831266
var grammar = new List<List<int>>();
12841267
var grammar_group = new List<int>();
12851268
var production_mapping = new List<List<int>>();
1286-
var semantic_rules = new List<ParserAction>();
12871269
var pm_count = 0;
12881270

12891271
foreach (var pr in production_rules)
@@ -1298,7 +1280,6 @@ public ShiftReduceParser CreateShiftReduceParserInstance()
12981280
}
12991281
grammar.AddRange(ll);
13001282
production_mapping.Add(pm);
1301-
semantic_rules.AddRange(pr.actions);
13021283
}
13031284

13041285
for (int i = 0; i < number_of_states; i++)
@@ -1335,7 +1316,7 @@ public ShiftReduceParser CreateShiftReduceParserInstance()
13351316
}
13361317
}
13371318

1338-
return new ShiftReduceParser(symbol_table, jump_table, goto_table, grammar_group.ToArray(), grammar.Select(x => x.ToArray()).ToArray(), semantic_rules);
1319+
return new ShiftReduceParser(symbol_table, jump_table, goto_table, grammar_group.ToArray(), grammar.Select(x => x.ToArray()).ToArray());
13391320
}
13401321
}
13411322

@@ -1358,7 +1339,7 @@ public static ParsingTreeNode NewNode(string production, string contents)
13581339
=> new ParsingTreeNode { Parent = null, Childs = new List<ParsingTreeNode>(), Produnction = production, Contents = contents };
13591340
}
13601341

1361-
public ParsingTreeNode root;
1342+
ParsingTreeNode root;
13621343

13631344
public ParsingTree(ParsingTreeNode root)
13641345
{
@@ -1375,7 +1356,6 @@ public class ShiftReduceParser
13751356
List<string> symbol_index_name = new List<string>();
13761357
Stack<int> state_stack = new Stack<int>();
13771358
Stack<ParsingTree.ParsingTreeNode> treenode_stack = new Stack<ParsingTree.ParsingTreeNode>();
1378-
List<ParserAction> actions;
13791359

13801360
// 3 1 2 0
13811361
// Accept? Shift? Reduce? Error?
@@ -1384,14 +1364,13 @@ public class ShiftReduceParser
13841364
int[][] production;
13851365
int[] group_table;
13861366

1387-
public ShiftReduceParser(Dictionary<string, int> symbol_table, int[][] jump_table, int[][] goto_table, int[] group_table, int[][] production, List<ParserAction> actions)
1367+
public ShiftReduceParser(Dictionary<string, int> symbol_table, int[][] jump_table, int[][] goto_table, int[] group_table, int[][] production)
13881368
{
13891369
symbol_name_index = symbol_table;
13901370
this.jump_table = jump_table;
13911371
this.goto_table = goto_table;
13921372
this.production = production;
13931373
this.group_table = group_table;
1394-
this.actions = actions;
13951374
var l = symbol_table.ToList().Select(x => new Tuple<int, string>(x.Value, x.Key)).ToList();
13961375
l.Sort();
13971376
l.ForEach(x => symbol_index_name.Add(x.Item2));
@@ -1472,7 +1451,6 @@ private void reduce(int index)
14721451
reduction_parent.Contents = string.Join("", reduce_treenodes.Select(x => x.Contents));
14731452
reduction_parent.Childs = reduce_treenodes;
14741453
treenode_stack.Push(reduction_parent);
1475-
actions[reduction_parent.ProductionRuleIndex].SemanticAction(reduction_parent);
14761454
}
14771455
}
1478-
}
1456+
}

ScannerGenerator.cs

Lines changed: 172 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,11 @@ public class diagram
6262
public void MakeNFA(string pattern) { Diagram = make_nfa("(" + pattern + ")"); }
6363
public void OptimizeNFA() { while (opt_nfa(Diagram)) ; }
6464
public void NFAtoDFA() { Diagram = nfa2dfa(Diagram); }
65-
public void MinimizeDFA() { opt_dfa(Diagram); }
65+
public void MinimizeDFA() { opt_dfa_hopcroft(Diagram); }
6666
public string PrintDiagram() { return print_diagram(Diagram); }
6767

6868
public static string PrintDiagram(diagram dia) { return print_diagram(dia); }
69+
public static string PrintGraph(diagram dia) { return print_diagram_for_graphviz(dia); }
6970

7071
/// <summary>
7172
/// Try simple-regular-expression to optimized DFA
@@ -342,6 +343,86 @@ private static string print_diagram(diagram d)
342343
return builder.ToString();
343344
}
344345

346+
private static string print_diagram_for_graphviz(diagram d)
347+
{
348+
var builder = new StringBuilder();
349+
var used = new HashSet<int>();
350+
351+
var stack_used = new Stack<transition_node>();
352+
var check_used = new List<bool>(d.count_of_vertex);
353+
check_used.AddRange(Enumerable.Repeat(false, d.count_of_vertex));
354+
355+
stack_used.Push(d.start_node);
356+
used.Add(d.start_node.index);
357+
358+
while (stack_used.Count != 0)
359+
{
360+
var tn = stack_used.Pop();
361+
if (check_used[tn.index]) continue;
362+
check_used[tn.index] = true;
363+
364+
used.Add(tn.index);
365+
366+
tn.transition.ForEach(x => stack_used.Push(x.Item2));
367+
}
368+
369+
builder.Append("digraph finite_state_machine {\r\n");
370+
builder.Append(" rankdir=LR;\r\n");
371+
builder.Append(" size=\"20,30\"\r\n");
372+
373+
// print doublecircle
374+
builder.Append(" node [shape = doublecircle]; ");
375+
foreach (var dd in d.nodes)
376+
if (dd.is_acceptable && used.Contains(dd.index))
377+
builder.Append(dd.index + "; ");
378+
builder.Append("\r\n");
379+
380+
// print point
381+
builder.Append(" node [shape = point]; ss\r\n");
382+
383+
// print circle
384+
builder.Append(" node [shape = circle];\r\n");
385+
386+
var stack = new Stack<transition_node>();
387+
var check = new List<bool>(d.count_of_vertex);
388+
check.AddRange(Enumerable.Repeat(false, d.count_of_vertex));
389+
390+
stack.Push(d.start_node);
391+
builder.Append($" ss -> {d.start_node.index}");
392+
393+
while (stack.Count != 0)
394+
{
395+
var tn = stack.Pop();
396+
if (check[tn.index]) continue;
397+
check[tn.index] = true;
398+
399+
foreach (var j in tn.transition)
400+
{
401+
string v = "";
402+
if (j.Item1 == e_closure)
403+
v = "&epsilon;";
404+
else if (j.Item1 == '"')
405+
v = "\"";
406+
else if (j.Item1 == '\n')
407+
v = "\\n";
408+
else if (j.Item1 == '\r')
409+
v = "\\r";
410+
else if (j.Item1 == '\t')
411+
v = "\\t";
412+
else
413+
v = new string(j.Item1, 1);
414+
415+
builder.Append($@" {tn.index} -> {j.Item2.index} [ label = ""{v}"" ];" + "\r\n");
416+
}
417+
418+
tn.transition.ForEach(x => stack.Push(x.Item2));
419+
}
420+
421+
builder.Append("}");
422+
423+
return builder.ToString();
424+
}
425+
345426
/// <summary>
346427
/// Get inverse array of diagram nodes
347428
/// </summary>
@@ -612,8 +693,7 @@ private diagram nfa2dfa(diagram dia)
612693
break;
613694
}
614695
}
615-
616-
696+
617697
diagram.count_of_vertex = transition_node_list.Count;
618698
diagram.nodes = transition_node_list;
619699
diagram.start_node = transition_node_list[0];
@@ -661,7 +741,7 @@ private void opt_dfa(diagram dia)
661741
}
662742

663743
color_count++;
664-
744+
665745
while (true)
666746
{
667747
// Collect transition color
@@ -700,6 +780,93 @@ private void opt_dfa(diagram dia)
700780

701781
previous_group = group;
702782
}
783+
784+
var dicc = new Dictionary<int, int>();
785+
var inverse_transition = get_inverse_transtition(dia);
786+
for (int i = 0; i < color.Count; i++)
787+
if (!dicc.ContainsKey(color[i]))
788+
dicc.Add(color[i], i);
789+
else if (inverse_transition.ContainsKey(i))
790+
{
791+
foreach (var inv in inverse_transition[i])
792+
for (int j = 0; j < dia.nodes[inv].transition.Count; j++)
793+
if (dia.nodes[inv].transition[j].Item2.index == i)
794+
dia.nodes[inv].transition[j] = new Tuple<char, transition_node>(dia.nodes[inv].transition[j].Item1, dia.nodes[dicc[color[i]]]);
795+
}
796+
}
797+
798+
/// <summary>
799+
/// Minimization DFA using Hopcroft Algorithm
800+
/// </summary>
801+
/// <param name="dia"></param>
802+
/// <returns></returns>
803+
private void opt_dfa_hopcroft(diagram dia)
804+
{
805+
var visit = new HashSet<string>();
806+
var queue = new Queue<List<int>>();
807+
808+
// Enqueue Nodes
809+
var acc_nodes = new List<int>();
810+
var nacc_nodes = new List<int>();
811+
foreach (var node in dia.nodes)
812+
if (node.is_acceptable)
813+
acc_nodes.Add(node.index);
814+
else
815+
nacc_nodes.Add(node.index);
816+
817+
queue.Enqueue(acc_nodes);
818+
queue.Enqueue(nacc_nodes);
819+
820+
var color = new List<int>();
821+
var color_count = 1;
822+
color.AddRange(Enumerable.Repeat(0, dia.count_of_vertex));
823+
824+
acc_nodes.ForEach(x => color[x] = color_count);
825+
color_count = 1;
826+
827+
while (queue.Count > 0)
828+
{
829+
var front = queue.Dequeue();
830+
front.Sort();
831+
var str = string.Join(",", front);
832+
833+
if (visit.Contains(str)) continue;
834+
visit.Add(str);
835+
836+
//foreach (var node in front)
837+
// color[node] = color_count;
838+
//color_count++;
839+
840+
// Collect transition color
841+
var dic = new Dictionary<int, SortedDictionary<char, int>>();
842+
foreach (var index in front)
843+
{
844+
var node = dia.nodes[index];
845+
foreach (var ts in node.transition)
846+
{
847+
if (!dic.ContainsKey(node.index))
848+
dic.Add(node.index, new SortedDictionary<char, int>());
849+
dic[node.index].Add(ts.Item1, color[ts.Item2.index]);
850+
}
851+
}
852+
853+
var list = dic.ToList();
854+
var group = new Dictionary<string, List<int>>();
855+
for (int i = 0; i < list.Count; i++)
856+
{
857+
var ds = dic2str(list[i].Value);
858+
if (!group.ContainsKey(ds))
859+
group.Add(ds, new List<int>());
860+
group[ds].Add(list[i].Key);
861+
}
862+
863+
foreach (var gi in group)
864+
{
865+
queue.Enqueue(gi.Value);
866+
gi.Value.ForEach(x => color[x] = color_count);
867+
color_count++;
868+
}
869+
}
703870

704871
var dicc = new Dictionary<int, int>();
705872
var inverse_transition = get_inverse_transtition(dia);
@@ -1004,4 +1171,4 @@ public Tuple<string, string, int, int> Lookahead()
10041171
return result;
10051172
}
10061173
}
1007-
}
1174+
}

0 commit comments

Comments
 (0)