github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/asm/lexbody.go (about) 1 // Inferno utils/cc/lexbody 2 // http://code.Google.Com/p/inferno-os/source/browse/utils/cc/lexbody 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.Net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.Vitanuova.Com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.Net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package asm 32 33 import ( 34 "bytes" 35 "fmt" 36 "os" 37 "strconv" 38 "strings" 39 "unicode/utf8" 40 41 "cmd/internal/obj" 42 ) 43 44 /* 45 * common code for all the assemblers 46 */ 47 func pragpack() { 48 for getnsc() != '\n' { 49 } 50 } 51 52 func pragvararg() { 53 for getnsc() != '\n' { 54 } 55 } 56 57 func pragcgo(name string) { 58 for getnsc() != '\n' { 59 } 60 } 61 62 func pragfpround() { 63 for getnsc() != '\n' { 64 } 65 } 66 67 func pragtextflag() { 68 for getnsc() != '\n' { 69 } 70 } 71 72 func pragdataflag() { 73 for getnsc() != '\n' { 74 } 75 } 76 77 func pragprofile() { 78 for getnsc() != '\n' { 79 } 80 } 81 82 func pragincomplete() { 83 for getnsc() != '\n' { 84 } 85 } 86 87 func setinclude(p string) { 88 if p == "" { 89 return 90 } 91 for i := 1; i < len(include); i++ { 92 if p == include[i] { 93 return 94 } 95 } 96 97 include = append(include, p) 98 } 99 100 func errorexit() { 101 obj.Bflush(&bstdout) 102 if outfile != "" { 103 os.Remove(outfile) 104 } 105 os.Exit(2) 106 } 107 108 func pushio() { 109 i := iostack 110 if i == nil { 111 Yyerror("botch in pushio") 112 errorexit() 113 } 114 115 i.P = fi.P 116 } 117 118 func newio() { 119 var pushdepth int = 0 120 121 i := iofree 122 if i == nil { 123 pushdepth++ 124 if pushdepth > 1000 { 125 Yyerror("macro/io expansion too deep") 126 errorexit() 127 } 128 i = new(Io) 129 } else { 130 iofree = i.Link 131 } 132 i.F = nil 133 i.P = nil 134 ionext = i 135 } 136 137 func newfile(s string, f *os.File) { 138 i := ionext 139 i.Link = iostack 140 iostack = i 141 i.F = f 142 if f == nil { 143 var err error 144 i.F, err = os.Open(s) 145 if err != nil { 146 Yyerror("%ca: %v", Thechar, err) 147 errorexit() 148 } 149 } 150 151 fi.P = nil 152 obj.Linklinehist(Ctxt, int(Lineno), s, 0) 153 } 154 155 var thetext *obj.LSym 156 157 func Settext(s *obj.LSym) { 158 thetext = s 159 } 160 161 func LabelLookup(s *Sym) *Sym { 162 if thetext == nil { 163 s.Labelname = s.Name 164 return s 165 } 166 167 p := string(fmt.Sprintf("%s.%s", thetext.Name, s.Name)) 168 lab := Lookup(p) 169 170 lab.Labelname = s.Name 171 return lab 172 } 173 174 func Lookup(symb string) *Sym { 175 // turn leading · into ""· 176 if strings.HasPrefix(symb, "·") { 177 symb = `""` + symb 178 } 179 180 // turn · (U+00B7) into . 181 // turn ∕ (U+2215) into / 182 symb = strings.Replace(symb, "·", ".", -1) 183 symb = strings.Replace(symb, "∕", "/", -1) 184 185 s := hash[symb] 186 if s != nil { 187 return s 188 } 189 190 s = new(Sym) 191 s.Name = symb 192 syminit(s) 193 hash[symb] = s 194 return s 195 } 196 197 func isalnum(c int) bool { 198 return isalpha(c) || isdigit(c) 199 } 200 201 func isalpha(c int) bool { 202 return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' 203 } 204 205 func isspace(c int) bool { 206 return c == ' ' || c == '\t' || c == '\r' || c == '\n' 207 } 208 209 func ISALPHA(c int) bool { 210 if isalpha(c) { 211 return true 212 } 213 if c >= utf8.RuneSelf { 214 return true 215 } 216 return false 217 } 218 219 var yybuf bytes.Buffer 220 221 func (yyImpl) Error(s string) { 222 Yyerror("%s", s) 223 } 224 225 type Yylval struct { 226 Sym *Sym 227 Lval int64 228 Sval string 229 Dval float64 230 } 231 232 func Yylex(yylval *Yylval) int { 233 var c1 int 234 var s *Sym 235 236 c := peekc 237 if c != IGN { 238 peekc = IGN 239 goto l1 240 } 241 242 l0: 243 c = GETC() 244 245 l1: 246 if c == EOF { 247 peekc = EOF 248 return -1 249 } 250 251 if isspace(c) { 252 if c == '\n' { 253 Lineno++ 254 return ';' 255 } 256 257 goto l0 258 } 259 260 if ISALPHA(c) { 261 yybuf.Reset() 262 goto aloop 263 } 264 if isdigit(c) { 265 yybuf.Reset() 266 if c != '0' { 267 goto dc 268 } 269 yybuf.WriteByte(byte(c)) 270 c = GETC() 271 c1 = 3 272 if c == 'x' || c == 'X' { 273 c1 = 4 274 c = GETC() 275 } else if c < '0' || c > '7' { 276 goto dc 277 } 278 yylval.Lval = 0 279 for { 280 if c >= '0' && c <= '9' { 281 if c > '7' && c1 == 3 { 282 break 283 } 284 yylval.Lval = int64(uint64(yylval.Lval) << uint(c1)) 285 yylval.Lval += int64(c) - '0' 286 c = GETC() 287 continue 288 } 289 290 if c1 == 3 { 291 break 292 } 293 if c >= 'A' && c <= 'F' { 294 c += 'a' - 'A' 295 } 296 if c >= 'a' && c <= 'f' { 297 yylval.Lval = int64(uint64(yylval.Lval) << uint(c1)) 298 yylval.Lval += int64(c) - 'a' + 10 299 c = GETC() 300 continue 301 } 302 303 break 304 } 305 306 goto ncu 307 } 308 switch c { 309 case '\n': 310 Lineno++ 311 return ';' 312 313 case '#': 314 domacro() 315 goto l0 316 317 case '.': 318 c = GETC() 319 if ISALPHA(c) { 320 yybuf.Reset() 321 yybuf.WriteByte('.') 322 goto aloop 323 } 324 325 if isdigit(c) { 326 yybuf.Reset() 327 yybuf.WriteByte('.') 328 goto casedot 329 } 330 331 peekc = c 332 return '.' 333 334 case '_', 335 '@': 336 yybuf.Reset() 337 goto aloop 338 339 case '"': 340 var buf bytes.Buffer 341 c1 = 0 342 for { 343 c = escchar('"') 344 if c == EOF { 345 break 346 } 347 buf.WriteByte(byte(c)) 348 } 349 yylval.Sval = buf.String() 350 return LSCONST 351 352 case '\'': 353 c = escchar('\'') 354 if c == EOF { 355 c = '\'' 356 } 357 if escchar('\'') != EOF { 358 Yyerror("missing '") 359 } 360 yylval.Lval = int64(c) 361 return LCONST 362 363 case '/': 364 c1 = GETC() 365 if c1 == '/' { 366 for { 367 c = GETC() 368 if c == '\n' { 369 goto l1 370 } 371 if c == EOF { 372 Yyerror("eof in comment") 373 errorexit() 374 } 375 } 376 } 377 378 if c1 == '*' { 379 for { 380 c = GETC() 381 for c == '*' { 382 c = GETC() 383 if c == '/' { 384 goto l0 385 } 386 } 387 388 if c == EOF { 389 Yyerror("eof in comment") 390 errorexit() 391 } 392 393 if c == '\n' { 394 Lineno++ 395 } 396 } 397 } 398 399 default: 400 return int(c) 401 } 402 403 peekc = c1 404 return int(c) 405 406 casedot: 407 for { 408 yybuf.WriteByte(byte(c)) 409 c = GETC() 410 if !(isdigit(c)) { 411 break 412 } 413 } 414 415 if c == 'e' || c == 'E' { 416 goto casee 417 } 418 goto caseout 419 420 casee: 421 yybuf.WriteByte('e') 422 c = GETC() 423 if c == '+' || c == '-' { 424 yybuf.WriteByte(byte(c)) 425 c = GETC() 426 } 427 428 for isdigit(c) { 429 yybuf.WriteByte(byte(c)) 430 c = GETC() 431 } 432 433 caseout: 434 peekc = c 435 if FPCHIP != 0 /*TypeKind(100016)*/ { 436 last = yybuf.String() 437 yylval.Dval = atof(last) 438 return LFCONST 439 } 440 441 Yyerror("assembler cannot interpret fp constants") 442 yylval.Lval = 1 443 return LCONST 444 445 aloop: 446 yybuf.WriteByte(byte(c)) 447 c = GETC() 448 if ISALPHA(c) || isdigit(c) || c == '_' || c == '$' { 449 goto aloop 450 } 451 peekc = c 452 last = yybuf.String() 453 s = Lookup(last) 454 if s.Macro != nil { 455 newio() 456 ionext.P = macexpand(s) 457 pushio() 458 ionext.Link = iostack 459 iostack = ionext 460 fi.P = ionext.P 461 if peekc != IGN { 462 fi.P = append(fi.P, byte(peekc)) 463 peekc = IGN 464 } 465 466 goto l0 467 } 468 469 if s.Type == 0 { 470 s.Type = LNAME 471 } 472 if s.Type == LNAME || s.Type == LVAR || s.Type == LLAB { 473 yylval.Sym = s 474 yylval.Sval = last 475 return int(s.Type) 476 } 477 478 yylval.Lval = s.Value 479 yylval.Sval = last 480 return int(s.Type) 481 482 dc: 483 for { 484 if !(isdigit(c)) { 485 break 486 } 487 yybuf.WriteByte(byte(c)) 488 c = GETC() 489 } 490 491 if c == '.' { 492 goto casedot 493 } 494 if c == 'e' || c == 'E' { 495 goto casee 496 } 497 last = yybuf.String() 498 yylval.Lval = strtoll(last, nil, 10) 499 500 ncu: 501 for c == 'U' || c == 'u' || c == 'l' || c == 'L' { 502 c = GETC() 503 } 504 peekc = c 505 return LCONST 506 } 507 508 func getc() int { 509 c := peekc 510 if c != IGN { 511 peekc = IGN 512 if c == '\n' { 513 Lineno++ 514 } 515 return c 516 } 517 518 c = GETC() 519 if c == '\n' { 520 Lineno++ 521 } 522 if c == EOF { 523 Yyerror("End of file") 524 errorexit() 525 } 526 527 return c 528 } 529 530 func getnsc() int { 531 var c int 532 533 for { 534 c = getc() 535 if !isspace(c) || c == '\n' { 536 return c 537 } 538 } 539 } 540 541 func unget(c int) { 542 peekc = c 543 if c == '\n' { 544 Lineno-- 545 } 546 } 547 548 func escchar(e int) int { 549 var l int 550 551 loop: 552 c := getc() 553 if c == '\n' { 554 Yyerror("newline in string") 555 return EOF 556 } 557 558 if c != '\\' { 559 if c == e { 560 return EOF 561 } 562 return c 563 } 564 565 c = getc() 566 if c >= '0' && c <= '7' { 567 l = c - '0' 568 c = getc() 569 if c >= '0' && c <= '7' { 570 l = l*8 + c - '0' 571 c = getc() 572 if c >= '0' && c <= '7' { 573 l = l*8 + c - '0' 574 return l 575 } 576 } 577 578 peekc = c 579 unget(c) 580 return l 581 } 582 583 switch c { 584 case '\n': 585 goto loop 586 case 'n': 587 return '\n' 588 case 't': 589 return '\t' 590 case 'b': 591 return '\b' 592 case 'r': 593 return '\r' 594 case 'f': 595 return '\f' 596 case 'a': 597 return 0x07 598 case 'v': 599 return 0x0b 600 case 'z': 601 return 0x00 602 } 603 604 return c 605 } 606 607 func pinit(f string) { 608 Lineno = 1 609 newio() 610 newfile(f, nil) 611 PC = 0 612 peekc = IGN 613 sym = 1 614 for _, s := range hash { 615 s.Macro = nil 616 } 617 } 618 619 func filbuf() int { 620 var n int 621 622 loop: 623 i := iostack 624 if i == nil { 625 return EOF 626 } 627 if i.F == nil { 628 goto pop 629 } 630 n, _ = i.F.Read(i.B[:]) 631 if n == 0 { 632 i.F.Close() 633 obj.Linklinehist(Ctxt, int(Lineno), "<pop>", 0) 634 goto pop 635 } 636 fi.P = i.B[1:n] 637 return int(i.B[0]) & 0xff 638 639 pop: 640 iostack = i.Link 641 i.Link = iofree 642 iofree = i 643 i = iostack 644 if i == nil { 645 return EOF 646 } 647 fi.P = i.P 648 if len(fi.P) == 0 { 649 goto loop 650 } 651 tmp8 := fi.P 652 fi.P = fi.P[1:] 653 return int(tmp8[0]) & 0xff 654 } 655 656 var last string 657 658 func Yyerror(a string, args ...interface{}) { 659 /* 660 * hack to intercept message from yaccpar 661 */ 662 if a == "syntax error" || len(args) == 1 && a == "%s" && args[0] == "syntax error" { 663 Yyerror("syntax error, last name: %s", last) 664 return 665 } 666 667 prfile(Lineno) 668 fmt.Printf("%s\n", fmt.Sprintf(a, args...)) 669 nerrors++ 670 if nerrors > 10 { 671 fmt.Printf("too many errors\n") 672 errorexit() 673 } 674 } 675 676 func prfile(l int32) { 677 obj.Linkprfile(Ctxt, int(l)) 678 } 679 680 func GETC() int { 681 if len(fi.P) == 0 { 682 return filbuf() 683 } 684 c := int(fi.P[0]) 685 fi.P = fi.P[1:] 686 return c 687 } 688 689 func isdigit(c int) bool { 690 return '0' <= c && c <= '9' 691 } 692 693 func strtoll(s string, p *byte, base int) int64 { 694 if p != nil { 695 panic("strtoll") 696 } 697 n, err := strconv.ParseInt(s, base, 64) 698 if err != nil { 699 return 0 700 } 701 return n 702 } 703 704 func atof(s string) float64 { 705 f, err := strconv.ParseFloat(s, 64) 706 if err != nil { 707 return 0 708 } 709 return f 710 }