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