1313
1414namespace 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