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  }