modernc.org/qbe@v0.0.9/scanner.go (about)

     1  // Copyright 2021 The QBE 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 qbe // import "modernc.org/qbe"
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/token"
    11  	"strconv"
    12  	"strings"
    13  	"unicode"
    14  	"unicode/utf8"
    15  
    16  	mtoken "modernc.org/token"
    17  )
    18  
    19  const eof = -1
    20  
    21  var (
    22  	_ Node = (*CSTToken)(nil)
    23  )
    24  
    25  type errItem struct {
    26  	off int32
    27  	err error
    28  }
    29  
    30  func (n errItem) position(s *source) token.Position {
    31  	return position(s.file, mtoken.Pos(n.off+1))
    32  }
    33  
    34  type msgList []errItem
    35  
    36  func (e msgList) Err(s *source) error {
    37  	if len(e) == 0 {
    38  		return nil
    39  	}
    40  
    41  	w := 0
    42  	prev := errItem{off: -1}
    43  	for _, v := range e {
    44  		if v.off != prev.off || v.err.Error() != prev.err.Error() {
    45  			e[w] = v
    46  			w++
    47  			prev = v
    48  		}
    49  	}
    50  
    51  	var a []string
    52  	for _, v := range e {
    53  		a = append(a, fmt.Sprintf("%v: %v", position(s.file, mtoken.Pos(v.off+1)), v.err))
    54  	}
    55  	return fmt.Errorf("%s", strings.Join(a, "\n"))
    56  }
    57  
    58  func (e *msgList) err(off int32, skip int, msg string, args ...interface{}) {
    59  	errs := *e
    60  	msg = fmt.Sprintf(msg, args...)
    61  	*e = append(errs, errItem{off, fmt.Errorf("%s (%v:)", msg, origin(skip+2))})
    62  }
    63  
    64  // Ch represents the lexical value of a CSTToken.
    65  type Ch rune
    66  
    67  // Node is an item of a CST/AST tree.
    68  type Node interface {
    69  	Position() token.Position
    70  }
    71  
    72  // CSTToken is the product of Scanner.Scan and a terminal node of the complete
    73  // syntax tree.
    74  type CSTToken struct { // 24 bytes on 64 bit arch
    75  	source *source
    76  
    77  	Ch
    78  	next   int32
    79  	off    int32
    80  	sepOff int32
    81  }
    82  
    83  func (n *CSTToken) sepPosition() (r token.Position) {
    84  	if n == nil {
    85  		return r
    86  	}
    87  
    88  	return position(n.source.file, mtoken.Pos(n.sepOff+1))
    89  }
    90  
    91  func rawPosition(f *mtoken.File, off mtoken.Pos) (r token.Position) {
    92  	return token.Position(f.PositionFor(off, false))
    93  }
    94  
    95  func position(f *mtoken.File, off mtoken.Pos) (r token.Position) {
    96  	p0 := token.Position(f.Position(off))
    97  	p1 := token.Position(f.PositionFor(off, false))
    98  	if p0 != p1 {
    99  		p0.Column = 1
   100  	}
   101  	return p0
   102  }
   103  
   104  // Position implements Node.
   105  func (n CSTToken) Position() (r token.Position) {
   106  	if n.IsValid() {
   107  		return position(n.source.file, mtoken.Pos(n.off+1))
   108  	}
   109  
   110  	return r
   111  }
   112  
   113  func (n CSTToken) pos() pos { return pos{n.source, n.off} }
   114  
   115  type pos struct {
   116  	source *source
   117  	off    int32
   118  }
   119  
   120  func (n pos) Position() (r token.Position) {
   121  	if n.source != nil {
   122  		return position(n.source.file, mtoken.Pos(n.off+1))
   123  	}
   124  
   125  	return r
   126  }
   127  
   128  // Offset reports the offset of n, in bytes, within the source buffer.
   129  func (n *CSTToken) Offset() int { return int(n.off) }
   130  
   131  // SepOffset reports the offset of n's preceding white space, if any, in bytes,
   132  // within the source buffer.
   133  func (n *CSTToken) SepOffset() int { return int(n.sepOff) }
   134  
   135  // String pretty formats n.
   136  func (n *CSTToken) String() string {
   137  	if n.Ch < ADD || n.Ch > Z {
   138  		return fmt.Sprintf("%v: %q %#U", n.Position(), n.Src(), rune(n.Ch))
   139  	}
   140  
   141  	return fmt.Sprintf("%v: %q %s", n.Position(), n.Src(), n.Ch)
   142  }
   143  
   144  // IsValid reports the validity of n. Tokens not present in some nodes will
   145  // report false.
   146  func (n *CSTToken) IsValid() bool { return n.source != nil }
   147  
   148  // Sep reports the whitespace preceding n, if any. The result is read only.
   149  func (n *CSTToken) Sep() []byte { return n.source.buf[n.sepOff:n.off] }
   150  
   151  // Src reports the original textual form of n. The result is read only.
   152  func (n *CSTToken) Src() []byte { return n.source.buf[n.off:n.next] }
   153  
   154  type source struct {
   155  	buf  []byte
   156  	file *mtoken.File
   157  	name string
   158  }
   159  
   160  // Scanner provides lexical analysis of its buffer.
   161  type Scanner struct {
   162  	*source
   163  	// Tok is the current CST token. It is valid after first call to Scan. The
   164  	// value is read only.
   165  	Tok              CSTToken
   166  	directiveHandler func([]byte) bool
   167  	errs             msgList
   168  	attrs            []string
   169  
   170  	cnt int32
   171  	off int32 // Index into source.buf.
   172  
   173  	c byte // Lookahead.
   174  
   175  	allErrros bool
   176  	isClosed  bool
   177  }
   178  
   179  // NewScanner returns a newly created scanner that will tokenize buf. Positions
   180  // are reported as if buf is coming from a file named name. The buffer becomes
   181  // owned by the scanner and must not be modified after calling NewScanner.
   182  //
   183  // The scanner normally stops scanning after some number of errors. Passing
   184  // allErrros == true overides that.
   185  func NewScanner(buf []byte, name string, allErrros bool) (*Scanner, error) {
   186  	r := &Scanner{
   187  		source: &source{
   188  			buf:  buf,
   189  			file: mtoken.NewFile(name, len(buf)),
   190  			name: name,
   191  		},
   192  		allErrros: allErrros,
   193  	}
   194  	if len(buf) != 0 {
   195  		r.c = buf[0]
   196  		if r.c == '\n' {
   197  			r.file.AddLine(int(r.off) + 1)
   198  		}
   199  	}
   200  	return r, nil
   201  }
   202  
   203  // Err reports any errors the scanner encountered. For typical use please see
   204  // the .Scan() documentation.
   205  func (s *Scanner) Err() error { return s.errs.Err(s.source) }
   206  
   207  func (s *Scanner) err(off int32, skip int, msg string, args ...interface{}) {
   208  	if len(s.errs) == 10 && !s.allErrros {
   209  		s.close()
   210  		return
   211  	}
   212  
   213  	s.errs.err(off, skip+1, msg, args...)
   214  }
   215  
   216  func (s *Scanner) close() {
   217  	if s.isClosed {
   218  		return
   219  	}
   220  
   221  	if s.cnt == 1 {
   222  		s.err(s.off, 1, "empty input")
   223  	}
   224  	s.Tok.Ch = eof
   225  	s.Tok.next = s.off
   226  	s.Tok.off = s.off
   227  	s.Tok.source = s.source
   228  	s.isClosed = true
   229  }
   230  
   231  func isIDFirst(c byte) bool {
   232  	return c >= 'a' && c <= 'z' ||
   233  		c >= 'A' && c <= 'Z' ||
   234  		c == '_' || c == '.'
   235  }
   236  
   237  func isDigit(c byte) bool      { return c >= '0' && c <= '9' }
   238  func isHexDigit(c byte) bool   { return isDigit(c) || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F' }
   239  func isIDNext(c byte) bool     { return isIDFirst(c) || isDigit(c) }
   240  func isOctalDigit(c byte) bool { return c >= '0' && c <= '7' }
   241  
   242  func (s *Scanner) next() {
   243  	if int(s.off) == len(s.buf)-1 {
   244  		s.Tok.next = s.off + 1
   245  		s.c = 0
   246  		return
   247  	}
   248  
   249  	s.off++
   250  	s.Tok.next = s.off
   251  	s.c = s.buf[s.off]
   252  	if s.c == '\n' {
   253  		s.file.AddLine(int(s.off) + 1)
   254  	}
   255  	return
   256  }
   257  
   258  func (s *Scanner) nextN(n int) {
   259  	if int(s.off) == len(s.buf)-n {
   260  		s.c = 0
   261  		return
   262  	}
   263  
   264  	s.off += int32(n)
   265  	s.Tok.next = s.off
   266  	s.c = s.buf[s.off]
   267  }
   268  
   269  // Scan moves to the next token and returns true if not at end of file. Usage
   270  // example:
   271  //
   272  //	s, _ = NewScanner(buf, name, false)
   273  //	for s.Scan() {
   274  //		...
   275  //	}
   276  //	if err := s.Err() {
   277  //		...
   278  //	}
   279  func (s *Scanner) Scan() (r bool) {
   280  	if s.isClosed {
   281  		return false
   282  	}
   283  
   284  	s.cnt++
   285  	s.Tok.sepOff = s.off
   286  	s.Tok.source = s.source
   287  	s.Tok.Ch = -1
   288  	for {
   289  		if r = s.scan(); !r || s.Tok.Ch >= 0 {
   290  			return r
   291  		}
   292  	}
   293  }
   294  
   295  func (s *Scanner) scan() (r bool) {
   296  	s.Tok.off = s.off
   297  	s.Tok.next = s.off
   298  	switch s.c {
   299  	case '$':
   300  		s.next()
   301  		switch s.c {
   302  		case '"':
   303  			s.next()
   304  			for s.c != '"' {
   305  				s.next()
   306  			}
   307  			s.next()
   308  			s.Tok.Ch = GLOBAL
   309  			return true
   310  		default:
   311  			s.ident()
   312  			s.Tok.Ch = GLOBAL
   313  			return true
   314  		}
   315  	case '%':
   316  		s.next()
   317  		s.ident()
   318  		s.Tok.Ch = LOCAL
   319  		return true
   320  	case '.':
   321  		s.next()
   322  		if s.c != '.' {
   323  			s.err(s.off, 0, "expected '.'")
   324  			s.Tok.Ch = ELLIPSIS
   325  			return true
   326  		}
   327  
   328  		s.next()
   329  		if s.c != '.' {
   330  			s.err(s.off, 0, "expected '.'")
   331  			s.Tok.Ch = ELLIPSIS
   332  			return true
   333  		}
   334  
   335  		s.next()
   336  		s.Tok.Ch = ELLIPSIS
   337  		return true
   338  	case ':':
   339  		s.next()
   340  		s.ident()
   341  		s.Tok.Ch = TYPENAME
   342  		return true
   343  	case '@':
   344  		s.next()
   345  		s.ident()
   346  		s.Tok.Ch = LABEL
   347  		return true
   348  	case '#':
   349  		s.lineComment()
   350  		return true
   351  	case ' ', '\t', '\n', '\r':
   352  		s.next()
   353  		for {
   354  			switch s.c {
   355  			case ' ', '\t', '\n', '\r':
   356  				s.next()
   357  			default:
   358  				return true
   359  			}
   360  		}
   361  	case '(', ')', '{', '}', ',', '+', '-', '=':
   362  		s.Tok.Ch = Ch(s.c)
   363  		s.next()
   364  		return true
   365  	case 's':
   366  		s.next()
   367  		switch s.c {
   368  		case '_':
   369  			s.next()
   370  			s.floatLiteral(FLOAT32_LIT)
   371  			return true
   372  		case 0:
   373  			s.Tok.Ch = S
   374  			return true
   375  		default:
   376  			s.off--
   377  			s.c = 's'
   378  		}
   379  	case 'p':
   380  		s.next()
   381  		switch s.c {
   382  		case 'h': // phi
   383  			s.off--
   384  			s.c = 'p'
   385  		default:
   386  			s.Tok.Ch = P
   387  			return true
   388  		}
   389  	case 'd':
   390  		s.next()
   391  		switch s.c {
   392  		case '_':
   393  			s.next()
   394  			s.floatLiteral(FLOAT64_LIT)
   395  			return true
   396  		case 0:
   397  			s.Tok.Ch = D
   398  			return true
   399  		default:
   400  			s.off--
   401  			s.c = 'd'
   402  		}
   403  	case 'l':
   404  		off := s.off
   405  		s.next()
   406  		switch s.c {
   407  		case 'd':
   408  			s.next()
   409  			switch s.c {
   410  			case '_':
   411  				s.next()
   412  				s.floatLiteral(LONG_DOUBLE_LIT)
   413  				return true
   414  			case 0:
   415  				s.Tok.Ch = LD
   416  				return true
   417  			}
   418  		case 0:
   419  			s.Tok.Ch = L
   420  			return true
   421  		}
   422  
   423  		s.off = off
   424  		s.c = 'l'
   425  	case '"':
   426  		s.next()
   427  		s.stringLiteral()
   428  		return true
   429  	case 0:
   430  		s.close()
   431  		return false
   432  	}
   433  
   434  	switch {
   435  	case s.c >= 'a' && s.c <= 'z':
   436  		s.keyword()
   437  		return true
   438  	case isDigit(s.c):
   439  		s.decimals()
   440  		s.Tok.Ch = INT_LIT
   441  		return true
   442  	default:
   443  		s.err(s.off, 0, "unexpected %#U", s.c)
   444  		s.next()
   445  		return true
   446  	}
   447  }
   448  
   449  func (s *Scanner) stringLiteral() {
   450  	// leading '"' already consumed.
   451  	s.Tok.Ch = STRING_LIT
   452  	for {
   453  		switch s.c {
   454  		case '"':
   455  			s.next()
   456  			return
   457  		case '\\':
   458  			s.next()
   459  			switch s.c {
   460  			case '\'', '"', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v':
   461  				s.next()
   462  				continue
   463  			case 'x', 'X':
   464  				s.next() // consume x|X
   465  				if !isHexDigit(s.c) {
   466  					s.err(s.off, 0, "expected hex digit: %#U", s.c)
   467  					continue
   468  				}
   469  
   470  				s.next() // consume the first hex digit
   471  				if !isHexDigit(s.c) {
   472  					s.err(s.off, 0, "expected hex digit: %#U", s.c)
   473  				}
   474  
   475  				s.next() // consume the second hex digit
   476  				continue
   477  			case 'u':
   478  				s.next()
   479  				s.u4()
   480  				continue
   481  			case 'U':
   482  				s.next()
   483  				s.u8()
   484  				continue
   485  			}
   486  
   487  			switch {
   488  			case isOctalDigit(s.c):
   489  				s.next() // 1st
   490  				if isOctalDigit(s.c) {
   491  					s.next() // 2nd
   492  				} else {
   493  					continue
   494  				}
   495  
   496  				if isOctalDigit(s.c) {
   497  					s.next() // 3rd
   498  				}
   499  				continue
   500  			default:
   501  				s.err(s.off, 0, "unknown escape sequence: %#U", s.c)
   502  				s.next()
   503  				continue
   504  			}
   505  		case 0:
   506  			s.err(s.off, 0, "unexpected EOF")
   507  			s.next()
   508  			return
   509  		case '\t':
   510  			s.next()
   511  		}
   512  
   513  		switch {
   514  		case s.c < ' ':
   515  			s.err(s.off, 0, "non-printable character: %#U", s.c)
   516  			s.next()
   517  		default:
   518  			s.next()
   519  		}
   520  	}
   521  }
   522  
   523  func (s *Scanner) u4() {
   524  	// Leading u consumed.
   525  	for i := 0; i < 4; i++ {
   526  		if !isHexDigit(s.c) {
   527  			panic(todo("%v: %#U", s.Tok.Position(), s.c))
   528  		}
   529  
   530  		s.next()
   531  	}
   532  }
   533  
   534  func (s *Scanner) u8() {
   535  	// Leading U consumed.
   536  	for i := 0; i < 8; i++ {
   537  		if !isHexDigit(s.c) {
   538  			panic(todo("%v: %#U", s.Tok.Position(), s.c))
   539  		}
   540  
   541  		s.next()
   542  	}
   543  }
   544  
   545  func (s *Scanner) decimals() {
   546  	if !isDigit(s.c) {
   547  		s.err(s.off, 0, "expected decimal digit")
   548  		s.next()
   549  		return
   550  	}
   551  
   552  	for {
   553  		switch {
   554  		case isDigit(s.c):
   555  			s.next()
   556  		default:
   557  			return
   558  		}
   559  	}
   560  }
   561  
   562  func (s *Scanner) floatLiteral(ch Ch) {
   563  	s.Tok.Ch = ch
   564  	off0 := s.off
   565  	switch s.c {
   566  	case '+', '-':
   567  		s.next()
   568  	}
   569  	for {
   570  		switch s.c {
   571  		case 'x', 'X':
   572  			if s.off-off0 == 1 && s.source.buf[off0] == '0' {
   573  				s.next()
   574  				s.hexDigits(true)
   575  				switch s.c {
   576  				case 'p', 'P':
   577  					s.next()
   578  					s.exponent()
   579  					return
   580  				default:
   581  					s.err(s.off, 0, "expected 'p' or 'P'")
   582  					s.next()
   583  					return
   584  				}
   585  			}
   586  
   587  			if s.off != off0 {
   588  				return
   589  			}
   590  
   591  			s.err(s.off, 0, "unexpected 'x' or 'X'")
   592  			s.next()
   593  			return
   594  		case '.':
   595  			s.next()
   596  			if isDigit(s.c) {
   597  				s.decimals()
   598  			}
   599  			switch s.c {
   600  			case 'e', 'E':
   601  				s.next()
   602  				s.exponent()
   603  			}
   604  			return
   605  		case 'e', 'E':
   606  			s.next()
   607  			s.exponent()
   608  			return
   609  		case 0:
   610  			if s.off == off0 {
   611  				s.err(s.off, 0, "expected floating point literal")
   612  				return
   613  			}
   614  		}
   615  
   616  		switch {
   617  		case s.c >= '0' && s.c <= '9':
   618  			s.next()
   619  		default:
   620  			return
   621  		}
   622  	}
   623  }
   624  
   625  func (s *Scanner) exponent() {
   626  	switch s.c {
   627  	case '+', '-':
   628  		s.next()
   629  	}
   630  
   631  	s.decimals()
   632  }
   633  
   634  func (s *Scanner) hexDigits(accept1dot bool) {
   635  	switch {
   636  	case accept1dot && s.c == '.':
   637  		// ok
   638  	default:
   639  		if !isHexDigit(s.c) {
   640  			s.err(s.off, 0, "expected hex digit")
   641  		}
   642  	}
   643  
   644  	for {
   645  		switch {
   646  		case isHexDigit(s.c):
   647  			s.next()
   648  		case accept1dot && s.c == '.':
   649  			s.next()
   650  			accept1dot = false
   651  		default:
   652  			return
   653  		}
   654  	}
   655  }
   656  
   657  func (s *Scanner) keyword() {
   658  out:
   659  	for {
   660  		switch {
   661  		case s.c >= 'a' && s.c <= 'z' || s.c >= '0' && s.c <= '9':
   662  			s.next()
   663  		case s.c == 0:
   664  			break out
   665  		default:
   666  			break out
   667  		}
   668  	}
   669  	s.Tok.Ch = Keywords[string(s.Tok.Src())]
   670  	if s.Tok.Ch == 0 {
   671  		s.err(s.Tok.off, 0, "expected keyword: %s", s.Tok.Src())
   672  	}
   673  	return
   674  }
   675  
   676  func (s *Scanner) ident() {
   677  	ok := false
   678  	off := s.off
   679  out:
   680  	for {
   681  		switch {
   682  		case isIDNext(s.c):
   683  			s.next()
   684  			ok = true
   685  		case s.c >= 0x80:
   686  			switch r := s.rune(); {
   687  			case unicode.IsLetter(r) || unicode.IsDigit(r):
   688  				ok = true
   689  				// already consumed
   690  			default:
   691  				panic(todo("%v: %#U", s.Tok.Position(), r))
   692  			}
   693  		case s.c == 0:
   694  			break out
   695  		default:
   696  			break out
   697  		}
   698  	}
   699  	if !ok {
   700  		s.err(off, 0, "expected identifier")
   701  		return
   702  	}
   703  
   704  	s.Tok.Ch = Keywords[string(s.Tok.Src())]
   705  	return
   706  }
   707  
   708  func (s *Scanner) rune() rune {
   709  	switch r, sz := utf8.DecodeRune(s.buf[s.off:]); {
   710  	case r == utf8.RuneError && sz == 0:
   711  		panic(todo("%v: %#U", s.Tok.Position(), s.c))
   712  	case r == utf8.RuneError && sz == 1:
   713  		panic(todo("%v: %#U", s.Tok.Position(), s.c))
   714  	default:
   715  		s.nextN(sz)
   716  		return r
   717  	}
   718  }
   719  
   720  var (
   721  	linePrefix      = []byte("#line")
   722  	directivePrefix = []byte("#qbec:")
   723  )
   724  
   725  func (s *Scanner) lineComment() {
   726  	p := s.Tok.Position()
   727  	off := s.off
   728  out:
   729  	for {
   730  		s.next()
   731  		switch s.c {
   732  		case '\n':
   733  			s.next()
   734  			break out
   735  		case 0:
   736  			break out
   737  		}
   738  	}
   739  	if p.Column != 1 {
   740  		return
   741  	}
   742  
   743  	b := s.buf[off:s.off]
   744  	switch {
   745  	case bytes.HasPrefix(b, linePrefix):
   746  		// https://gcc.gnu.org/onlinedocs/cpp/Line-Control.html
   747  		name := s.name
   748  		switch fields := strings.Fields(string(s.buf[off:s.off])); {
   749  		case len(fields) >= 3: // #line 42 "foo.c"
   750  			name = fields[2]
   751  			name, _ = strconv.Unquote(name)
   752  			fallthrough
   753  		case len(fields) == 2: // #line 42
   754  			n, err := strconv.ParseUint(fields[1], 10, 31)
   755  			if err != nil {
   756  				return
   757  			}
   758  
   759  			s.file.AddLineInfo(int(s.off), name, int(n))
   760  		}
   761  	case bytes.HasPrefix(b, directivePrefix):
   762  		x := b[len(directivePrefix):]
   763  		if f := s.directiveHandler; f != nil && f(x) {
   764  			break
   765  		}
   766  
   767  		if bytes.HasPrefix(x, attributePrefix) {
   768  			x = x[len(attributePrefix) : len(x)-1]
   769  			s.attrs = append(s.attrs, string(x))
   770  		}
   771  	}
   772  }
   773  
   774  // Named values of Ch.
   775  const (
   776  	ADD             Ch = iota + 0xe000 // add
   777  	ALIGN                              // align
   778  	ALLOC16                            // alloc16
   779  	ALLOC4                             // alloc4
   780  	ALLOC8                             // alloc8
   781  	AND                                // and
   782  	B                                  // b
   783  	C                                  // c
   784  	CALL                               // call
   785  	CAST                               // cast
   786  	CEQD                               // ceqd
   787  	CEQL                               // ceql
   788  	CEQLD                              // ceqld
   789  	CEQS                               // ceqs
   790  	CEQW                               // ceqw
   791  	CGED                               // cged
   792  	CGELD                              // cgeld
   793  	CGES                               // cges
   794  	CGTD                               // cgtd
   795  	CGTLD                              // cgtld
   796  	CGTS                               // cgts
   797  	CLED                               // cled
   798  	CLELD                              // cleld
   799  	CLES                               // cles
   800  	CLTD                               // cltd
   801  	CLTLD                              // cltld
   802  	CLTS                               // clts
   803  	CNED                               // cned
   804  	CNEL                               // cnel
   805  	CNELD                              // cneld
   806  	CNES                               // cnes
   807  	CNEW                               // cnew
   808  	COD                                // cod
   809  	COPY                               // copy
   810  	COS                                // cos
   811  	CSGEL                              // csgel
   812  	CSGEW                              // csgew
   813  	CSGTL                              // csgtl
   814  	CSGTW                              // csgtw
   815  	CSLEL                              // cslel
   816  	CSLEW                              // cslew
   817  	CSLTL                              // csltl
   818  	CSLTW                              // csltw
   819  	CUGEL                              // cugel
   820  	CUGEW                              // cugew
   821  	CUGTL                              // cugtl
   822  	CUGTW                              // cugtw
   823  	CULEL                              // culel
   824  	CULEW                              // culew
   825  	CULTL                              // cultl
   826  	CULTW                              // cultw
   827  	CUOD                               // cuod
   828  	CUOS                               // cuos
   829  	D                                  // d
   830  	DATA                               // data
   831  	DECLARE                            // declare
   832  	DIV                                // div
   833  	DTOSI                              // dtosi
   834  	DTOUI                              // dtoui
   835  	ELLIPSIS                           // ...
   836  	ENV                                // env
   837  	EXPORT                             // export
   838  	EXTD                               // exts
   839  	EXTS                               // exts
   840  	EXTSB                              // extsb
   841  	EXTSH                              // extsh
   842  	EXTSW                              // extsw
   843  	EXTUB                              // extub
   844  	EXTUH                              // extuh
   845  	EXTUW                              // extuw
   846  	FLOAT32_LIT                        // float32 literal
   847  	FLOAT64_LIT                        // float64 literal
   848  	FUNCTION                           // function
   849  	GLOBAL                             // global name
   850  	H                                  // h
   851  	INT_LIT                            // integer literal
   852  	JMP                                // jmp
   853  	JNZ                                // jnz
   854  	L                                  // l
   855  	LABEL                              // label name
   856  	LD                                 // ld
   857  	LDTOSI                             // ldtosi
   858  	LDTOUI                             // ldtoui
   859  	LOAD                               // load
   860  	LOADD                              // loadd
   861  	LOADL                              // loadl
   862  	LOADLD                             // loadld
   863  	LOADS                              // loads
   864  	LOADSB                             // loadsb
   865  	LOADSH                             // loadsh
   866  	LOADSW                             // loadsw
   867  	LOADUB                             // loadub
   868  	LOADUH                             // loaduh
   869  	LOADUW                             // loaduw
   870  	LOADW                              // loadw
   871  	LOCAL                              // local name
   872  	LONG_DOUBLE_LIT                    // long double literal
   873  	MUL                                // mul
   874  	OR                                 // or
   875  	P                                  // p
   876  	PHI                                // phi
   877  	REM                                // rem
   878  	RET                                // ret
   879  	RO                                 // ro
   880  	S                                  // s
   881  	SAR                                // sar
   882  	SHL                                // shl
   883  	SHR                                // shr
   884  	SLTOF                              // sltof
   885  	STOREB                             // storeb
   886  	STORED                             // stored
   887  	STOREH                             // storeh
   888  	STOREL                             // storel
   889  	STORELD                            // storeld
   890  	STORES                             // stores
   891  	STOREW                             // storew
   892  	STOSI                              // stosi
   893  	STOUI                              // stoui
   894  	STRING_LIT                         // string literal
   895  	SUB                                // sub
   896  	SWTOF                              // swtof
   897  	TRUNCD                             // truncd
   898  	TRUNCLD                            // truncld
   899  	TYPE                               // type
   900  	TYPENAME                           // type name
   901  	UDIV                               // udiv
   902  	ULTOF                              // ultof
   903  	UREM                               // urem
   904  	UWTOF                              // uwtof
   905  	VAARG                              // vaarg
   906  	VASTART                            // vastart
   907  	W                                  // w
   908  	XOR                                // xor
   909  	Z                                  // z
   910  )
   911  
   912  // Keywords represents the mapping of identifiers to QBE's reserved names.
   913  var Keywords = map[string]Ch{
   914  	"add":      ADD,
   915  	"align":    ALIGN,
   916  	"alloc16":  ALLOC16,
   917  	"alloc4":   ALLOC4,
   918  	"alloc8":   ALLOC8,
   919  	"and":      AND,
   920  	"b":        B,
   921  	"c":        C,
   922  	"call":     CALL,
   923  	"cast":     CAST,
   924  	"ceqd":     CEQD,
   925  	"ceql":     CEQL,
   926  	"ceqld":    CEQLD,
   927  	"ceqs":     CEQS,
   928  	"ceqw":     CEQW,
   929  	"cged":     CGED,
   930  	"cgeld":    CGELD,
   931  	"cges":     CGES,
   932  	"cgtd":     CGTD,
   933  	"cgtld":    CGTLD,
   934  	"cgts":     CGTS,
   935  	"cled":     CLED,
   936  	"cleld":    CLELD,
   937  	"cles":     CLES,
   938  	"cltd":     CLTD,
   939  	"cltld":    CLTLD,
   940  	"clts":     CLTS,
   941  	"cned":     CNED,
   942  	"cnel":     CNEL,
   943  	"cneld":    CNELD,
   944  	"cnes":     CNES,
   945  	"cnew":     CNEW,
   946  	"cod":      COD,
   947  	"copy":     COPY,
   948  	"cos":      COS,
   949  	"csgel":    CSGEL,
   950  	"csgew":    CSGEW,
   951  	"csgtl":    CSGTL,
   952  	"csgtw":    CSGTW,
   953  	"cslel":    CSLEL,
   954  	"cslew":    CSLEW,
   955  	"csltl":    CSLTL,
   956  	"csltw":    CSLTW,
   957  	"cugel":    CUGEL,
   958  	"cugew":    CUGEW,
   959  	"cugtl":    CUGTL,
   960  	"cugtw":    CUGTW,
   961  	"culel":    CULEL,
   962  	"culew":    CULEW,
   963  	"cultl":    CULTL,
   964  	"cultw":    CULTW,
   965  	"cuod":     CUOD,
   966  	"cuos":     CUOS,
   967  	"d":        D,
   968  	"data":     DATA,
   969  	"declare":  DECLARE,
   970  	"div":      DIV,
   971  	"dtosi":    DTOSI,
   972  	"dtoui":    DTOUI,
   973  	"env":      ENV,
   974  	"export":   EXPORT,
   975  	"extd":     EXTD,
   976  	"exts":     EXTS,
   977  	"extsb":    EXTSB,
   978  	"extsh":    EXTSH,
   979  	"extsw":    EXTSW,
   980  	"extub":    EXTUB,
   981  	"extuh":    EXTUH,
   982  	"extuw":    EXTUW,
   983  	"function": FUNCTION,
   984  	"h":        H,
   985  	"jmp":      JMP,
   986  	"jnz":      JNZ,
   987  	"l":        L,
   988  	"ld":       LD,
   989  	"ldtosi":   LDTOSI,
   990  	"ldtoui":   LDTOUI,
   991  	"load":     LOAD,
   992  	"loadd":    LOADD,
   993  	"loadl":    LOADL,
   994  	"loadld":   LOADLD,
   995  	"loads":    LOADS,
   996  	"loadsb":   LOADSB,
   997  	"loadsh":   LOADSH,
   998  	"loadsw":   LOADSW,
   999  	"loadub":   LOADUB,
  1000  	"loaduh":   LOADUH,
  1001  	"loaduw":   LOADUW,
  1002  	"loadw":    LOADW,
  1003  	"mul":      MUL,
  1004  	"or":       OR,
  1005  	"p":        P,
  1006  	"phi":      PHI,
  1007  	"rem":      REM,
  1008  	"ret":      RET,
  1009  	"ro":       RO,
  1010  	"s":        S,
  1011  	"sar":      SAR,
  1012  	"shl":      SHL,
  1013  	"shr":      SHR,
  1014  	"sltof":    SLTOF,
  1015  	"storeb":   STOREB,
  1016  	"stored":   STORED,
  1017  	"storeh":   STOREH,
  1018  	"storel":   STOREL,
  1019  	"storeld":  STORELD,
  1020  	"stores":   STORES,
  1021  	"storew":   STOREW,
  1022  	"stosi":    STOSI,
  1023  	"stoui":    STOUI,
  1024  	"sub":      SUB,
  1025  	"swtof":    SWTOF,
  1026  	"truncd":   TRUNCD,
  1027  	"truncld":  TRUNCLD,
  1028  	"type":     TYPE,
  1029  	"udiv":     UDIV,
  1030  	"ultof":    ULTOF,
  1031  	"urem":     UREM,
  1032  	"uwtof":    UWTOF,
  1033  	"vaarg":    VAARG,
  1034  	"vastart":  VASTART,
  1035  	"w":        W,
  1036  	"xor":      XOR,
  1037  	"z":        Z,
  1038  }
  1039  
  1040  func (c Ch) str() string {
  1041  	if c < ADD || c > Z {
  1042  		return fmt.Sprintf("%#U", c)
  1043  	}
  1044  
  1045  	return c.String()
  1046  }