github.com/jmigpin/editor@v1.6.0/util/parseutil/lrparser/rulefirst.go (about) 1 package lrparser 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // rules first terminals 9 type RuleFirstT struct { 10 ri *RuleIndex 11 cache map[Rule]RuleSet 12 seen map[Rule]int 13 reverse bool 14 } 15 16 func newRuleFirstT(ri *RuleIndex, reverse bool) *RuleFirstT { 17 rf := &RuleFirstT{ri: ri, reverse: reverse} 18 rf.cache = map[Rule]RuleSet{} 19 rf.seen = map[Rule]int{} 20 return rf 21 } 22 23 //---------- 24 25 func (rf *RuleFirstT) first(r Rule) RuleSet { 26 rset, ok := rf.cache[r] 27 if ok { 28 return rset 29 } 30 31 rf.seen[r]++ 32 defer func() { rf.seen[r]-- }() 33 if rf.seen[r] > 2 { // extra loop to allow proper solve 34 return nil 35 } 36 37 rset = RuleSet{} 38 if r.isTerminal() { 39 rset.set(r) 40 } else { 41 inReverse := rf.reverse && ruleProdCanReverse(r) 42 for _, r2 := range ruleProductions(r) { // r->a0|...|an 43 w2 := ruleSequence(r2, inReverse) // r->a0 ... an 44 rset2 := rf.sequenceFirst(w2) 45 rset.add(rset2) 46 } 47 } 48 rf.cache[r] = rset 49 return rset 50 } 51 func (rf *RuleFirstT) sequenceFirst(w []Rule) RuleSet { 52 rset := RuleSet{} 53 allHaveNil := true 54 for _, r := range w { // w -> r1 ... rk 55 rset2 := rf.first(r) 56 rset.add(rset2) 57 if !rset2.has(nilRule) { 58 allHaveNil = false 59 break 60 } 61 } 62 if !allHaveNil { 63 rset.unset(nilRule) 64 } 65 return rset 66 } 67 68 //---------- 69 70 func (rf *RuleFirstT) String() string { 71 u := []string{} 72 for _, r := range rf.ri.sorted() { 73 if r.isTerminal() { // no need to show terminals 74 continue 75 } 76 u = append(u, fmt.Sprintf("%v:%v", r.id(), rf.first(r))) 77 } 78 return fmt.Sprintf("rulefirst[rev=%v]{\n\t%v\n}", rf.reverse, strings.Join(u, "\n\t")) 79 } 80 81 //---------- 82 //---------- 83 //---------- 84 85 //type RuleFollow struct { 86 // ri *RuleIndex 87 // rFirst *RulesFirst 88 // cache map[Rule]RuleSet 89 //} 90 91 //func newRuleFollow(ri *RuleIndex, rFirst *RulesFirst, r Rule) *RuleFollow { 92 // rf := &RuleFollow{ri: ri, rFirst: rFirst} 93 // rf.cache = map[Rule]RuleSet{} 94 // rf.calc(r) 95 // return rf 96 //} 97 //func (rf *RuleFollow) get(r Rule) RuleSet { 98 // return rf.cache[r] 99 //} 100 //func (rf *RuleFollow) calc(r Rule) { 101 // AFollow := RuleSet{} 102 // AFollow.set(rf.ri.endRule()) 103 // rf.cache[r] = AFollow 104 105 // seen := map[Rule]int{} 106 // rf.calc2(r, AFollow, seen) 107 //} 108 //func (rf *RuleFollow) calc2(A Rule, AFollow RuleSet, seen map[Rule]int) { 109 // if seen[A] >= 2 { // need to visit 2nd time to allow afollow to be used in nested rules 110 // return 111 // } 112 // seen[A]++ 113 // defer func() { seen[A]-- }() 114 115 // //rset := RuleSet{} 116 // w, ok := ruleProductions(A) 117 // if !ok { // terminal 118 // return 119 // } 120 // nilr := rf.ri.nilRule() 121 // for _, r2 := range w { 122 // // A->r2 123 // w2 := ruleRhs(r2) // sequence 124 // for i, B := range w2 { 125 // // A->αBβ 126 127 // if ruleIsTerminal(B) { 128 // continue 129 // } 130 131 // BFollow, ok := rf.cache[B] 132 // if !ok { 133 // BFollow = RuleSet{} 134 // rf.cache[B] = BFollow 135 // } 136 137 // haveβ := i < len(w2)-1 138 // βFirstHasNil := false 139 // if haveβ { 140 // β := w2[i+1] 141 // βFirst := RuleSet{} 142 // βFirst.add(rf.rFirst.get(β)) 143 // βFirstHasNil = βFirst.isSet(nilr) 144 // βFirst.unset(nilr) 145 // BFollow.add(βFirst) 146 // } 147 // if !haveβ || βFirstHasNil { 148 // BFollow.add(AFollow) 149 // } 150 151 // rf.calc2(B, BFollow, seen) 152 // } 153 // } 154 //} 155 //func (rf *RuleFollow) String() string { 156 // u := []string{} 157 // for _, r := range rf.ri.sorted() { 158 // u = append(u, fmt.Sprintf("%v:%v", r.id(), rf.get(r))) 159 // } 160 // return fmt.Sprintf("{\n\t%v\n}", strings.Join(u, ",\n\t")) 161 //}