Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d7d4049

Browse files
authored
fix parser-generator error occurring when state closure overrapped
1 parent b0ef1f1 commit d7d4049

File tree

1 file changed

+138
-20
lines changed

1 file changed

+138
-20
lines changed

‎ParserGenerator.cs‎

Lines changed: 138 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,88 @@
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+
1623
public class ParserProduction
1724
{
1825
public int index;
1926
public string production_name;
2027
public bool isterminal;
2128
public List<ParserProduction> contents = new List<ParserProduction>();
2229
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>();
2332

2433
public static ParserProduction operator +(ParserProduction p1, ParserProduction p2)
2534
{
2635
p1.contents.Add(p2);
2736
return p1;
2837
}
2938

39+
public static ParserProduction operator +(ParserProduction pp, ParserAction ac)
40+
{
41+
pp.temp_actions.Add(ac);
42+
return pp;
43+
}
44+
3045
public static ParserProduction operator |(ParserProduction p1, ParserProduction p2)
3146
{
3247
p2.contents.Insert(0, p2);
3348
p1.sub_productions.Add(new List<ParserProduction>(p2.contents));
49+
p1.actions.AddRange(p2.temp_actions);
50+
p2.temp_actions.Clear();
51+
p2.contents.Clear();
52+
return p1;
53+
}
54+
55+
#if false
56+
public static ParserProduction operator +(ParserProduction p1, string p2)
57+
{
58+
p1.contents.Add(new ParserProduction { isterminal = true, token_specific = p2 });
59+
return p1;
60+
}
61+
62+
public static ParserProduction operator|(ParserProduction p1, string p2)
63+
{
64+
p1.sub_productions.Add(new List<ParserProduction> { p1, new ParserProduction { isterminal = true, token_specific = p2 } });
65+
return p1;
66+
}
67+
#endif
68+
}
69+
70+
public class ParserProduction
71+
{
72+
public int index;
73+
public string production_name;
74+
public bool isterminal;
75+
public List<ParserProduction> contents = new List<ParserProduction>();
76+
public List<List<ParserProduction>> sub_productions = new List<List<ParserProduction>>();
77+
public List<ParserAction> temp_actions = new List<ParserAction>();
78+
public List<ParserAction> actions = new List<ParserAction>();
79+
80+
public static ParserProduction operator +(ParserProduction p1, ParserProduction p2)
81+
{
82+
p1.contents.Add(p2);
83+
return p1;
84+
}
85+
86+
public static ParserProduction operator +(ParserProduction pp, ParserAction ac)
87+
{
88+
pp.temp_actions.Add(ac);
89+
return pp;
90+
}
91+
92+
public static ParserProduction operator |(ParserProduction p1, ParserProduction p2)
93+
{
94+
p2.contents.Insert(0, p2);
95+
p1.sub_productions.Add(new List<ParserProduction>(p2.contents));
96+
p1.actions.AddRange(p2.temp_actions);
97+
p2.temp_actions.Clear();
3498
p2.contents.Clear();
3599
return p1;
36100
}
@@ -86,13 +150,23 @@ public void PushStarts(ParserProduction pp)
86150
production_rules[0].sub_productions.Add(new List<ParserProduction> { pp });
87151
}
88152

153+
/// <summary>
154+
/// 터미널들의 Shift-Reduce Conflict solve 정보를 넣습니다.
155+
/// </summary>
156+
/// <param name="left"></param>
157+
/// <param name="terminals"></param>
89158
public void PushConflictSolver(bool left, params ParserProduction[] terminals)
90159
{
91160
var priority = shift_reduce_conflict_solve.Count + shift_reduce_conflict_solve_with_production_rule.Count;
92161
foreach (var pp in terminals)
93162
shift_reduce_conflict_solve.Add(pp.index, new Tuple<int, bool>(priority, left));
94163
}
95164

165+
/// <summary>
166+
/// 논터미널들의 Shift-Reduce Conflict solve 정보를 넣습니다.
167+
/// </summary>
168+
/// <param name="left"></param>
169+
/// <param name="no"></param>
96170
public void PushConflictSolver(bool left, params Tuple<ParserProduction, int>[] no)
97171
{
98172
var priority = shift_reduce_conflict_solve.Count + shift_reduce_conflict_solve_with_production_rule.Count;
@@ -103,8 +177,11 @@ public void PushConflictSolver(bool left, params Tuple<ParserProduction, int>[]
103177
shift_reduce_conflict_solve_with_production_rule[ppi.Item1.index].Add(ppi.Item2, new Tuple<int, bool>(priority, left));
104178
}
105179
}
106-
180+
107181
#region String Hash Function
182+
// 원래 해시가 아니라 set로 구현해야하는게 일반적임
183+
// 집합끼리의 비교연산, 일치여부 교집합을 구해 좀 더 최적화가능하지만 귀찮으니 string-hash를 쓰도록한다.
184+
108185
private string t2s(Tuple<int, int, int> t)
109186
{
110187
return $"{t.Item1},{t.Item2},{t.Item3}";
@@ -754,6 +831,7 @@ public void GenerateLALR()
754831
set.Add(t2s(psd));
755832
// Find all transitions
756833
var new_trans = new List<Tuple<int, int, int, HashSet<int>>>();
834+
var trans_dic = new Dictionary<string, int>();
757835
foreach (var psd in goto_unit.Value)
758836
{
759837
if (production_rules[psd.Item1].sub_productions[psd.Item2].Count == psd.Item3) continue;
@@ -762,8 +840,17 @@ public void GenerateLALR()
762840
foreach (var nts in first_nt)
763841
if (!set.Contains(t2s(nts)))
764842
{
765-
new_trans.Add(nts);
766-
set.Add(t2s(nts));
843+
var ts = t2s(new Tuple<int, int, int>(nts.Item1, nts.Item2, nts.Item3));
844+
if (trans_dic.ContainsKey(ts))
845+
{
846+
nts.Item4.ToList().ForEach(x => new_trans[trans_dic[ts]].Item4.Add(x));
847+
}
848+
else
849+
{
850+
trans_dic.Add(ts, new_trans.Count);
851+
new_trans.Add(nts);
852+
set.Add(t2s(nts));
853+
}
767854
}
768855
}
769856
goto_unit.Value.AddRange(new_trans);
@@ -773,14 +860,30 @@ public void GenerateLALR()
773860
var index_list = new List<Tuple<int, int>>();
774861
foreach (var pp in gotos)
775862
{
776-
var hash = l2s(pp.Value);
777-
if (!state_index.ContainsKey(hash))
863+
try
778864
{
779-
states.Add(index_count, pp.Value);
780-
state_index.Add(hash, index_count);
781-
q.Enqueue(index_count++);
865+
var hash = l2s(pp.Value);
866+
if (!state_index.ContainsKey(hash))
867+
{
868+
states.Add(index_count, pp.Value);
869+
state_index.Add(hash, index_count);
870+
q.Enqueue(index_count++);
871+
}
872+
index_list.Add(new Tuple<int, int>(pp.Key, state_index[hash]));
873+
}
874+
catch
875+
{
876+
// Now this error is not hit
877+
// For debugging
878+
print_header("GOTO CONFLICT!!");
879+
GlobalPrinter.Append($"Cannot solve lookahead overlapping!\r\n");
880+
GlobalPrinter.Append($"Please uses non-associative option or adds extra token to handle with shift-reduce conflict!\r\n");
881+
print_states(p, states[p]);
882+
print_header("INCOMPLETE STATES");
883+
foreach (var s in states)
884+
print_states(s.Key, s.Value);
885+
return;
782886
}
783-
index_list.Add(new Tuple<int, int>(pp.Key, state_index[hash]));
784887
}
785888

786889
goto_table.Add(new Tuple<int, List<Tuple<int, int>>>(p, index_list));
@@ -887,15 +990,17 @@ public void GenerateLALR()
887990
GlobalPrinter.Append($"Shift-Reduce Conflict! {(tuple.Item1 == -1 ? "$" : production_rules[tuple.Item1].production_name)}\r\n");
888991
GlobalPrinter.Append($"States: {ms.Key} {tuple.Item2}\r\n");
889992
print_states(ms.Key, states[ms.Key]);
890-
print_states(shift_tokens[tuple.Item1], states[shift_tokens[tuple.Item1]]);
993+
print_states(small_shift_info[shift_tokens[tuple.Item1]].Item2, states[small_shift_info[shift_tokens[tuple.Item1]].Item2]);
891994
#endif
892995
var pp = get_first_on_right_terminal(production_rules[tuple.Item2], tuple.Item3);
893996

894-
if (!shift_reduce_conflict_solve.ContainsKey(pp.index) || !shift_reduce_conflict_solve.ContainsKey(tuple.Item1))
895-
throw new Exception($"Specify the rules to resolve Shift-Reduce Conflict! Target: {production_rules[tuple.Item1].production_name} {pp.production_name}");
896-
var p1 = shift_reduce_conflict_solve[pp.index];
897-
var p2 = shift_reduce_conflict_solve[tuple.Item1];
898-
997+
Tuple<int, bool> p1 = null, p2 = null;
998+
999+
if (shift_reduce_conflict_solve.ContainsKey(pp.index))
1000+
p1 = shift_reduce_conflict_solve[pp.index];
1001+
if (shift_reduce_conflict_solve.ContainsKey(tuple.Item1))
1002+
p2 = shift_reduce_conflict_solve[tuple.Item1];
1003+
8991004
if (shift_reduce_conflict_solve_with_production_rule.ContainsKey(tuple.Item2))
9001005
if (shift_reduce_conflict_solve_with_production_rule[tuple.Item2].ContainsKey(tuple.Item3))
9011006
p1 = shift_reduce_conflict_solve_with_production_rule[tuple.Item2][tuple.Item3];
@@ -904,6 +1009,9 @@ public void GenerateLALR()
9041009
if (shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1].ContainsKey(states[tuple.Item1][0].Item2))
9051010
p2 = shift_reduce_conflict_solve_with_production_rule[states[tuple.Item1][0].Item1][states[tuple.Item1][0].Item2];
9061011

1012+
if (p1 == null || p2 == null)
1013+
throw new Exception($"Specify the rules to resolve Shift-Reduce Conflict! Target: {production_rules[tuple.Item1].production_name} {pp.production_name}");
1014+
9071015
if (p1.Item1 < p2.Item1 || (p1.Item1 == p2.Item1 && p1.Item2))
9081016
{
9091017
// Reduce
@@ -947,6 +1055,9 @@ public void GenerateLALR()
9471055
}
9481056
#endregion
9491057

1058+
/// <summary>
1059+
/// 파싱 테이블을 집합형태로 출력합니다.
1060+
/// </summary>
9501061
public void PrintStates()
9511062
{
9521063
print_header("FINAL STATES");
@@ -967,6 +1078,9 @@ public void PrintStates()
9671078
}
9681079
}
9691080

1081+
/// <summary>
1082+
/// 파싱테이블을 테이블 형태로 출력합니다.
1083+
/// </summary>
9701084
public void PrintTable()
9711085
{
9721086
var production_mapping = new List<List<int>>();
@@ -1266,6 +1380,7 @@ public ShiftReduceParser CreateShiftReduceParserInstance()
12661380
var grammar = new List<List<int>>();
12671381
var grammar_group = new List<int>();
12681382
var production_mapping = new List<List<int>>();
1383+
var semantic_rules = new List<ParserAction>();
12691384
var pm_count = 0;
12701385

12711386
foreach (var pr in production_rules)
@@ -1316,10 +1431,10 @@ public ShiftReduceParser CreateShiftReduceParserInstance()
13161431
}
13171432
}
13181433

1319-
return new ShiftReduceParser(symbol_table, jump_table, goto_table, grammar_group.ToArray(), grammar.Select(x => x.ToArray()).ToArray());
1434+
return new ShiftReduceParser(symbol_table, jump_table, goto_table, grammar_group.ToArray(), grammar.Select(x => x.ToArray()).ToArray(),semantic_rules);
13201435
}
13211436
}
1322-
1437+
13231438
public class ParsingTree
13241439
{
13251440
public class ParsingTreeNode
@@ -1346,7 +1461,7 @@ public ParsingTree(ParsingTreeNode root)
13461461
this.root = root;
13471462
}
13481463
}
1349-
1464+
13501465
/// <summary>
13511466
/// Shift-Reduce Parser for LR(1)
13521467
/// </summary>
@@ -1356,6 +1471,7 @@ public class ShiftReduceParser
13561471
List<string> symbol_index_name = new List<string>();
13571472
Stack<int> state_stack = new Stack<int>();
13581473
Stack<ParsingTree.ParsingTreeNode> treenode_stack = new Stack<ParsingTree.ParsingTreeNode>();
1474+
List<ParserAction> actions;
13591475

13601476
// 3 1 2 0
13611477
// Accept? Shift? Reduce? Error?
@@ -1364,13 +1480,14 @@ public class ShiftReduceParser
13641480
int[][] production;
13651481
int[] group_table;
13661482

1367-
public ShiftReduceParser(Dictionary<string, int> symbol_table, int[][] jump_table, int[][] goto_table, int[] group_table, int[][] production)
1483+
public ShiftReduceParser(Dictionary<string, int> symbol_table, int[][] jump_table, int[][] goto_table, int[] group_table, int[][] production,List<ParserAction>actions)
13681484
{
13691485
symbol_name_index = symbol_table;
13701486
this.jump_table = jump_table;
13711487
this.goto_table = goto_table;
13721488
this.production = production;
13731489
this.group_table = group_table;
1490+
this.actions = actions;
13741491
var l = symbol_table.ToList().Select(x => new Tuple<int, string>(x.Value, x.Key)).ToList();
13751492
l.Sort();
13761493
l.ForEach(x => symbol_index_name.Add(x.Item2));
@@ -1451,6 +1568,7 @@ private void reduce(int index)
14511568
reduction_parent.Contents = string.Join("", reduce_treenodes.Select(x => x.Contents));
14521569
reduction_parent.Childs = reduce_treenodes;
14531570
treenode_stack.Push(reduction_parent);
1571+
actions[reduction_parent.ProductionRuleIndex].SemanticAction(reduction_parent);
14541572
}
14551573
}
1456-
}
1574+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /