github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/qiuyesuifeng/golex/render.go (about) 1 // Copyright (c) 2014 The golex Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "log" 10 "sort" 11 "strings" 12 13 "github.com/insionng/yougam/libraries/qiuyesuifeng/golex/Godeps/_workspace/src/yougam/libraries/cznic/lex" 14 "github.com/insionng/yougam/libraries/qiuyesuifeng/golex/Godeps/_workspace/src/yougam/libraries/cznic/lexer" 15 ) 16 17 type renderGo struct { 18 noRender 19 scStates map[int]bool 20 } 21 22 func (r *renderGo) prolog(l *lex.L) { 23 for _, state := range l.StartConditionsStates { 24 r.scStates[int(state.Index)] = true 25 } 26 for _, state := range l.StartConditionsBolStates { 27 r.scStates[int(state.Index)] = true 28 } 29 r.w.Write([]byte("// CAUTION: Generated file - DO NOT EDIT.\n\n")) 30 for _, line := range l.DefCode { 31 r.w.Write([]byte(line)) 32 } 33 r.wprintf("\nyystate0:\n") 34 if l.YYM != "yym" { 35 r.wprintf("yyrule := -1\n_ = yyrule") 36 } 37 if action0 := l.Rules[0].Action; action0 != "" { 38 r.w.Write([]byte(action0)) 39 } 40 scNames := map[int]string{} 41 for name, i := range l.StartConditions { 42 scNames[i] = name 43 } 44 if len(l.StartConditionsStates) > 1 || len(l.StartConditionsBolStates) != 0 { 45 if len(l.StartConditionsBolStates) == 0 { 46 r.wprintf("\n\nswitch yyt := %s; yyt {\n", l.YYT) 47 } else { 48 r.wprintf("\n\nswitch yyt, yyb := %s, %s; yyt {\n", l.YYT, l.YYB) 49 } 50 r.wprintf("default:\npanic(fmt.Errorf(`invalid start condition %%d`, yyt))\n") 51 52 // Stabilize map ranging 53 x := []int{} 54 for sc := range l.StartConditionsStates { 55 x = append(x, sc) 56 } 57 sort.Ints(x) 58 59 for _, sc := range x { 60 state := l.StartConditionsStates[sc] 61 r.wprintf("case %d: // start condition: %s\n", sc, scNames[sc]) 62 if state, ok := l.StartConditionsBolStates[sc]; ok { 63 r.wprintf("if yyb { goto yystart%d }\n", state.Index) 64 } 65 r.wprintf("goto yystart%d\n", state.Index) 66 } 67 r.wprintf("}\n\n") 68 } else { 69 r.wprintf("\n\ngoto yystart%d\n\n", l.StartConditionsStates[0].Index) 70 } 71 } 72 73 func isReturn(code string) bool { 74 const ret = "return" 75 lenret := len(ret) 76 lines := strings.Split(code, "\n") 77 for { 78 l := len(lines) 79 if l == 0 { 80 break 81 } 82 83 line := strings.TrimSpace(lines[l-1]) 84 if line == "" { 85 lines = lines[:l-1] 86 continue 87 } 88 89 if len(line) >= lenret && line[:lenret] == ret { 90 if len(line) == lenret { 91 return true 92 } 93 94 if c := line[lenret]; c == ' ' || c == '\t' { 95 return true 96 } 97 } 98 99 break 100 101 } 102 return false 103 } 104 105 func (r *renderGo) rules(l *lex.L) { 106 for i := 1; i < len(l.Rules); i++ { 107 rule := l.Rules[i] 108 r.wprintf("yyrule%d: // %s\n", i, rule.Pattern) 109 act := strings.TrimSpace(rule.Action) 110 if act != "" && act != "|" { 111 r.wprintf("{\n") 112 r.w.Write([]byte(rule.Action)) 113 } 114 if act != "|" { 115 r.wprintf("\n") 116 if !isReturn(rule.Action) { 117 r.wprintf("goto yystate0\n") 118 } 119 } 120 if act != "" && act != "|" { 121 r.wprintf("}\n") 122 } 123 } 124 r.wprintf(`panic("unreachable")` + "\n") 125 } 126 127 func (r *renderGo) scanFail(l *lex.L) { 128 r.wprintf("\ngoto yyabort // silence unused label error\n") 129 r.wprintf("\nyyabort: // no lexem recognized\n") 130 } 131 132 func (r *renderGo) userCode(l *lex.L) { 133 if userCode := l.UserCode; userCode != "" { 134 r.w.Write([]byte(userCode)) 135 } 136 } 137 138 func (r *renderGo) defaultTransition(l *lex.L, state *lexer.NfaState) (defaultEdge *lexer.RangesEdge) { 139 r.wprintf("default:\n") 140 if rule, ok := l.Accepts[state]; ok { 141 r.wprintf("goto yyrule%d\n", rule) 142 return 143 } 144 145 cases := map[rune]bool{} 146 for i := 0; i < 256; i++ { 147 cases[rune(i)] = true 148 } 149 for _, edge0 := range state.Consuming { 150 switch edge := edge0.(type) { 151 default: 152 log.Fatalf("unexpected type %T", edge0) 153 case *lexer.RuneEdge: 154 delete(cases, edge.Rune) 155 case *lexer.RangesEdge: 156 if defaultEdge == nil || len(edge.Ranges.R32) > len(defaultEdge.Ranges.R32) { 157 defaultEdge = edge 158 } 159 for _, rng := range edge.Ranges.R32 { 160 for c := rng.Lo; c <= rng.Hi; c += rng.Stride { 161 delete(cases, rune(c)) 162 } 163 } 164 } 165 } 166 if len(cases) != 0 { 167 r.wprintf("goto yyabort\n") 168 return nil 169 } 170 171 if defaultEdge != nil { 172 r.wprintf("goto yystate%d // %s\n", defaultEdge.Target().Index, r.rangesEdgeString(defaultEdge, l)) 173 return 174 } 175 176 panic("internal error") 177 } 178 179 func (r *renderGo) rangesEdgeString(edge *lexer.RangesEdge, l *lex.L) string { 180 a := []string{} 181 for _, rng := range edge.Ranges.R32 { 182 if rng.Stride != 1 { 183 panic("internal error") 184 } 185 186 if rng.Hi-rng.Lo == 1 { 187 a = append(a, fmt.Sprintf("%s == %s || %s == %s", l.YYC, q(rng.Lo), l.YYC, q(rng.Hi))) 188 continue 189 } 190 191 if rng.Hi-rng.Lo > 0 { 192 a = append(a, fmt.Sprintf("%s >= %s && %s <= %s", l.YYC, q(rng.Lo), l.YYC, q(rng.Hi))) 193 continue 194 } 195 196 // rng.Hi == rng.Lo 197 a = append(a, fmt.Sprintf("%s == %s", l.YYC, q(rng.Lo))) 198 } 199 return strings.Replace(strings.Join(a, " || "), "%", "%%", -1) 200 } 201 202 func (r *renderGo) transitions(l *lex.L, state *lexer.NfaState) { 203 r.wprintf("switch {\n") 204 var defaultEdge lexer.Edger = r.defaultTransition(l, state) 205 206 // Stabilize case order 207 a := []string{} 208 m := map[string]uint{} 209 for _, edge0 := range state.Consuming { 210 if edge0 == defaultEdge { 211 continue 212 } 213 214 s := "" 215 switch edge := edge0.(type) { 216 default: 217 log.Fatalf("unexpected type %T", edge0) 218 case *lexer.RuneEdge: 219 s = fmt.Sprintf("%s == %s", l.YYC, q(uint32(edge.Rune))) 220 case *lexer.RangesEdge: 221 s = fmt.Sprintf(r.rangesEdgeString(edge, l)) 222 } 223 a = append(a, s) 224 m[s] = edge0.Target().Index 225 } 226 sort.Strings(a) 227 for _, s := range a { 228 r.wprintf("case %s:\ngoto yystate%d\n", s, m[s]) 229 } 230 231 r.wprintf("}\n\n") 232 } 233 234 func (r *renderGo) states(l *lex.L) { 235 yym := l.YYM != "yym" 236 r.wprintf("goto yystate%d // silence unused label error\n", 0) 237 if yym { 238 r.wprintf("goto yyAction // silence unused label error\n") 239 r.wprintf("yyAction:\n") 240 r.wprintf("switch yyrule {\n") 241 for i := range l.Rules[1:] { 242 r.wprintf("case %d:\ngoto yyrule%d\n", i+1, i+1) 243 } 244 r.wprintf("}\n") 245 } 246 for _, state := range l.Dfa { 247 iState := int(state.Index) 248 if _, ok := r.scStates[iState]; ok { 249 r.wprintf("goto yystate%d // silence unused label error\n", iState) 250 } 251 r.wprintf("yystate%d:\n", iState) 252 rule, ok := l.Accepts[state] 253 if !ok || !l.Rules[rule].EOL { 254 r.wprintf("%s\n", l.YYN) 255 } 256 if ok && l.YYM != "yym" { 257 r.wprintf("yyrule = %d\n", rule) 258 r.wprintf("%s\n", l.YYM) 259 } 260 if _, ok := r.scStates[iState]; ok { 261 r.wprintf("yystart%d:\n", iState) 262 } 263 if len(state.Consuming) != 0 { 264 r.transitions(l, state) 265 } else { 266 if rule, ok := l.Accepts[state]; ok { 267 r.wprintf("goto yyrule%d\n\n", rule) 268 } else { 269 panic("internal error") 270 } 271 } 272 } 273 } 274 275 func (r renderGo) render(srcname string, l *lex.L) { 276 r.prolog(l) 277 r.states(l) 278 r.rules(l) 279 r.scanFail(l) 280 r.userCode(l) 281 }