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 }