rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/asm/macbody.go (about) 1 // Inferno utils/cc/macbody 2 // http://code.Google.Com/p/inferno-os/source/browse/utils/cc/macbody 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 "cmd/internal/obj" 36 "fmt" 37 "os" 38 "strings" 39 ) 40 41 const ( 42 VARMAC = 0x80 43 ) 44 45 func getnsn() int32 { 46 c := getnsc() 47 if c < '0' || c > '9' { 48 return -1 49 } 50 n := int32(0) 51 for c >= '0' && c <= '9' { 52 n = n*10 + int32(c) - '0' 53 c = getc() 54 } 55 56 unget(c) 57 return n 58 } 59 60 func getsym() *Sym { 61 c := getnsc() 62 if !isalpha(c) && c != '_' && c < 0x80 { 63 unget(c) 64 return nil 65 } 66 67 var buf bytes.Buffer 68 for { 69 buf.WriteByte(byte(c)) 70 c = getc() 71 if isalnum(c) || c == '_' || c >= 0x80 { 72 continue 73 } 74 unget(c) 75 break 76 } 77 last = buf.String() 78 return Lookup(last) 79 } 80 81 func getsymdots(dots *int) *Sym { 82 s := getsym() 83 if s != nil { 84 return s 85 } 86 87 c := getnsc() 88 if c != '.' { 89 unget(c) 90 return nil 91 } 92 93 if getc() != '.' || getc() != '.' { 94 Yyerror("bad dots in macro") 95 } 96 *dots = 1 97 return Lookup("__VA_ARGS__") 98 } 99 100 func getcom() int { 101 var c int 102 103 for { 104 c = getnsc() 105 if c != '/' { 106 break 107 } 108 c = getc() 109 if c == '/' { 110 for c != '\n' { 111 c = getc() 112 } 113 break 114 } 115 116 if c != '*' { 117 break 118 } 119 c = getc() 120 for { 121 if c == '*' { 122 c = getc() 123 if c != '/' { 124 continue 125 } 126 c = getc() 127 break 128 } 129 130 if c == '\n' { 131 Yyerror("comment across newline") 132 break 133 } 134 135 c = getc() 136 } 137 138 if c == '\n' { 139 break 140 } 141 } 142 143 return c 144 } 145 146 func dodefine(cp string) { 147 var s *Sym 148 149 if i := strings.Index(cp, "="); i >= 0 { 150 p := cp[i+1:] 151 cp = cp[:i] 152 s = Lookup(cp) 153 s.Macro = &Macro{Text: p} 154 } else { 155 s = Lookup(cp) 156 s.Macro = &Macro{Text: "1"} 157 } 158 159 if debug['m'] != 0 { 160 fmt.Printf("#define (-D) %s %s\n", s.Name, s.Macro.Text) 161 } 162 } 163 164 var mactab = []struct { 165 Macname string 166 Macf func() 167 }{ 168 {"ifdef", nil}, /* macif(0) */ 169 {"ifndef", nil}, /* macif(1) */ 170 {"else", nil}, /* macif(2) */ 171 {"line", maclin}, 172 {"define", macdef}, 173 {"include", macinc}, 174 {"undef", macund}, 175 {"pragma", macprag}, 176 {"endif", macend}, 177 } 178 179 func domacro() { 180 s := getsym() 181 if s == nil { 182 s = Lookup("endif") 183 } 184 for i := 0; i < len(mactab); i++ { 185 if s.Name == mactab[i].Macname { 186 if mactab[i].Macf != nil { 187 mactab[i].Macf() 188 } else { 189 macif(i) 190 } 191 return 192 } 193 } 194 195 Yyerror("unknown #: %s", s.Name) 196 macend() 197 } 198 199 func macund() { 200 s := getsym() 201 macend() 202 if s == nil { 203 Yyerror("syntax in #undef") 204 return 205 } 206 207 s.Macro = nil 208 } 209 210 const ( 211 NARG = 25 212 ) 213 214 func macdef() { 215 var args [NARG]string 216 var n int 217 var i int 218 var c int 219 var dots int 220 var ischr int 221 var base bytes.Buffer 222 223 s := getsym() 224 if s == nil { 225 goto bad 226 } 227 if s.Macro != nil { 228 Yyerror("macro redefined: %s", s.Name) 229 } 230 c = getc() 231 n = -1 232 dots = 0 233 if c == '(' { 234 n++ 235 c = getnsc() 236 if c != ')' { 237 unget(c) 238 var a *Sym 239 var c int 240 for { 241 a = getsymdots(&dots) 242 if a == nil { 243 goto bad 244 } 245 if n >= NARG { 246 Yyerror("too many arguments in #define: %s", s.Name) 247 goto bad 248 } 249 250 args[n] = a.Name 251 n++ 252 c = getnsc() 253 if c == ')' { 254 break 255 } 256 if c != ',' || dots != 0 { 257 goto bad 258 } 259 } 260 } 261 262 c = getc() 263 } 264 265 if isspace(c) { 266 if c != '\n' { 267 c = getnsc() 268 } 269 } 270 ischr = 0 271 for { 272 if isalpha(c) || c == '_' { 273 var buf bytes.Buffer 274 buf.WriteByte(byte(c)) 275 c = getc() 276 for isalnum(c) || c == '_' { 277 buf.WriteByte(byte(c)) 278 c = getc() 279 } 280 281 symb := buf.String() 282 for i = 0; i < n; i++ { 283 if symb == args[i] { 284 break 285 } 286 } 287 if i >= n { 288 base.WriteString(symb) 289 continue 290 } 291 292 base.WriteByte('#') 293 base.WriteByte(byte('a' + i)) 294 continue 295 } 296 297 if ischr != 0 { 298 if c == '\\' { 299 base.WriteByte(byte(c)) 300 c = getc() 301 } else if c == ischr { 302 ischr = 0 303 } 304 } else { 305 if c == '"' || c == '\'' { 306 base.WriteByte(byte(c)) 307 ischr = c 308 c = getc() 309 continue 310 } 311 312 if c == '/' { 313 c = getc() 314 if c == '/' { 315 c = getc() 316 for { 317 if c == '\n' { 318 break 319 } 320 c = getc() 321 } 322 323 continue 324 } 325 326 if c == '*' { 327 c = getc() 328 for { 329 if c == '*' { 330 c = getc() 331 if c != '/' { 332 continue 333 } 334 c = getc() 335 break 336 } 337 338 if c == '\n' { 339 Yyerror("comment and newline in define: %s", s.Name) 340 break 341 } 342 343 c = getc() 344 } 345 346 continue 347 } 348 349 base.WriteByte('/') 350 continue 351 } 352 } 353 354 if c == '\\' { 355 c = getc() 356 if c == '\n' { 357 c = getc() 358 continue 359 } else if c == '\r' { 360 c = getc() 361 if c == '\n' { 362 c = getc() 363 continue 364 } 365 } 366 367 base.WriteByte('\\') 368 continue 369 } 370 371 if c == '\n' { 372 break 373 } 374 if c == '#' { 375 if n > 0 { 376 base.WriteByte(byte(c)) 377 } 378 } 379 380 base.WriteByte(byte(c)) 381 c = GETC() 382 if c == '\n' { 383 Lineno++ 384 } 385 if c == -1 { 386 Yyerror("eof in a macro: %s", s.Name) 387 break 388 } 389 } 390 391 s.Macro = &Macro{ 392 Text: base.String(), 393 Narg: n + 1, 394 Dots: dots != 0, 395 } 396 if debug['m'] != 0 { 397 fmt.Printf("#define %s %s\n", s.Name, s.Macro.Text) 398 } 399 return 400 401 bad: 402 if s == nil { 403 Yyerror("syntax in #define") 404 } else { 405 Yyerror("syntax in #define: %s", s.Name) 406 } 407 macend() 408 } 409 410 func macexpand(s *Sym) []byte { 411 if s.Macro.Narg == 0 { 412 if debug['m'] != 0 { 413 fmt.Printf("#expand %s %s\n", s.Name, s.Macro.Text) 414 } 415 return []byte(s.Macro.Text) 416 } 417 418 nargs := s.Macro.Narg - 1 419 dots := s.Macro.Dots 420 421 c := getnsc() 422 var arg []string 423 var cp string 424 var out bytes.Buffer 425 if c != '(' { 426 goto bad 427 } 428 c = getc() 429 if c != ')' { 430 unget(c) 431 l := 0 432 var buf bytes.Buffer 433 var c int 434 for { 435 c = getc() 436 if c == '"' { 437 for { 438 buf.WriteByte(byte(c)) 439 c = getc() 440 if c == '\\' { 441 buf.WriteByte(byte(c)) 442 c = getc() 443 continue 444 } 445 446 if c == '\n' { 447 goto bad 448 } 449 if c == '"' { 450 break 451 } 452 } 453 } 454 455 if c == '\'' { 456 for { 457 buf.WriteByte(byte(c)) 458 c = getc() 459 if c == '\\' { 460 buf.WriteByte(byte(c)) 461 c = getc() 462 continue 463 } 464 465 if c == '\n' { 466 goto bad 467 } 468 if c == '\'' { 469 break 470 } 471 } 472 } 473 474 if c == '/' { 475 c = getc() 476 switch c { 477 case '*': 478 for { 479 c = getc() 480 if c == '*' { 481 c = getc() 482 if c == '/' { 483 break 484 } 485 } 486 } 487 488 buf.WriteByte(' ') 489 continue 490 491 case '/': 492 for { 493 c = getc() 494 if !(c != '\n') { 495 break 496 } 497 } 498 499 default: 500 unget(c) 501 c = '/' 502 } 503 } 504 505 if l == 0 { 506 if c == ',' { 507 if len(arg) == nargs-1 && dots { 508 buf.WriteByte(',') 509 continue 510 } 511 512 arg = append(arg, buf.String()) 513 buf.Reset() 514 continue 515 } 516 517 if c == ')' { 518 arg = append(arg, buf.String()) 519 break 520 } 521 } 522 523 if c == '\n' { 524 c = ' ' 525 } 526 buf.WriteByte(byte(c)) 527 if c == '(' { 528 l++ 529 } 530 if c == ')' { 531 l-- 532 } 533 } 534 } 535 536 if len(arg) != nargs { 537 Yyerror("argument mismatch expanding: %s", s.Name) 538 return nil 539 } 540 541 cp = s.Macro.Text 542 for i := 0; i < len(cp); i++ { 543 c = int(cp[i]) 544 if c == '\n' { 545 c = ' ' 546 } 547 if c != '#' { 548 out.WriteByte(byte(c)) 549 continue 550 } 551 552 i++ 553 if i >= len(cp) { 554 goto bad 555 } 556 c = int(cp[i]) 557 if c == '#' { 558 out.WriteByte(byte(c)) 559 continue 560 } 561 562 c -= 'a' 563 if c < 0 || c >= len(arg) { 564 continue 565 } 566 out.WriteString(arg[c]) 567 } 568 569 if debug['m'] != 0 { 570 fmt.Printf("#expand %s %s\n", s.Name, out.String()) 571 } 572 return out.Bytes() 573 574 bad: 575 Yyerror("syntax in macro expansion: %s", s.Name) 576 return nil 577 } 578 579 func macinc() { 580 var c int 581 var buf bytes.Buffer 582 var f *os.File 583 var hp string 584 var str string 585 var symb string 586 587 c0 := getnsc() 588 if c0 != '"' { 589 c = c0 590 if c0 != '<' { 591 goto bad 592 } 593 c0 = '>' 594 } 595 596 for { 597 c = getc() 598 if c == c0 { 599 break 600 } 601 if c == '\n' { 602 goto bad 603 } 604 buf.WriteByte(byte(c)) 605 } 606 str = buf.String() 607 608 c = getcom() 609 if c != '\n' { 610 goto bad 611 } 612 613 for i := 0; i < len(include); i++ { 614 if i == 0 && c0 == '>' { 615 continue 616 } 617 symb = include[i] 618 symb += "/" 619 if symb == "./" { 620 symb = "" 621 } 622 symb += str 623 var err error 624 f, err = os.Open(symb) 625 if err == nil { 626 break 627 } 628 } 629 630 if f == nil { 631 symb = str 632 } 633 hp = symb 634 newio() 635 pushio() 636 newfile(hp, f) 637 return 638 639 bad: 640 unget(c) 641 Yyerror("syntax in #include") 642 macend() 643 } 644 645 func maclin() { 646 var buf bytes.Buffer 647 var symb string 648 649 n := getnsn() 650 c := getc() 651 if n < 0 { 652 goto bad 653 } 654 for { 655 if c == ' ' || c == '\t' { 656 c = getc() 657 continue 658 } 659 660 if c == '"' { 661 break 662 } 663 if c == '\n' { 664 symb = "<noname>" 665 goto nn 666 } 667 668 goto bad 669 } 670 671 for { 672 c = getc() 673 if c == '"' { 674 break 675 } 676 buf.WriteByte(byte(c)) 677 } 678 symb = buf.String() 679 680 c = getcom() 681 if c != '\n' { 682 goto bad 683 } 684 685 nn: 686 obj.Linklinehist(Ctxt, int(Lineno), symb, int(n)) 687 return 688 689 bad: 690 unget(c) 691 Yyerror("syntax in #line") 692 macend() 693 } 694 695 func macif(f int) { 696 var c int 697 var l int 698 var bol int 699 var s *Sym 700 701 if f == 2 { 702 goto skip 703 } 704 s = getsym() 705 if s == nil { 706 goto bad 707 } 708 if getcom() != '\n' { 709 goto bad 710 } 711 if (s.Macro != nil) != (f != 0) { 712 return 713 } 714 715 skip: 716 bol = 1 717 l = 0 718 for { 719 c = getc() 720 if c != '#' { 721 if !isspace(c) { 722 bol = 0 723 } 724 if c == '\n' { 725 bol = 1 726 } 727 continue 728 } 729 730 if !(bol != 0) { 731 continue 732 } 733 s = getsym() 734 if s == nil { 735 continue 736 } 737 if s.Name == "endif" { 738 if l != 0 { 739 l-- 740 continue 741 } 742 743 macend() 744 return 745 } 746 747 if s.Name == "ifdef" || s.Name == "ifndef" { 748 l++ 749 continue 750 } 751 752 if l == 0 && f != 2 && s.Name == "else" { 753 macend() 754 return 755 } 756 } 757 758 bad: 759 Yyerror("syntax in #if(n)def") 760 macend() 761 } 762 763 func macprag() { 764 var c int 765 766 s := getsym() 767 768 if s != nil && s.Name == "lib" { 769 c0 := getnsc() 770 if c0 != '"' { 771 c = c0 772 if c0 != '<' { 773 goto bad 774 } 775 c0 = '>' 776 } 777 778 var buf bytes.Buffer 779 for { 780 c = getc() 781 if c == c0 { 782 break 783 } 784 if c == '\n' { 785 goto bad 786 } 787 buf.WriteByte(byte(c)) 788 } 789 symb := buf.String() 790 791 c = getcom() 792 if c != '\n' { 793 goto bad 794 } 795 796 /* 797 * put pragma-line in as a funny history 798 */ 799 obj.Linklinehist(Ctxt, int(Lineno), symb, -1) 800 return 801 } 802 if s != nil && s.Name == "pack" { 803 pragpack() 804 return 805 } 806 807 if s != nil && s.Name == "fpround" { 808 pragfpround() 809 return 810 } 811 812 if s != nil && s.Name == "textflag" { 813 pragtextflag() 814 return 815 } 816 817 if s != nil && s.Name == "dataflag" { 818 pragdataflag() 819 return 820 } 821 822 if s != nil && s.Name == "varargck" { 823 pragvararg() 824 return 825 } 826 827 if s != nil && s.Name == "incomplete" { 828 pragincomplete() 829 return 830 } 831 832 if s != nil && (strings.HasPrefix(s.Name, "cgo_") || strings.HasPrefix(s.Name, "dyn")) { 833 pragcgo(s.Name) 834 return 835 } 836 837 for getnsc() != '\n' { 838 } 839 return 840 841 bad: 842 unget(c) 843 Yyerror("syntax in #pragma lib") 844 macend() 845 } 846 847 func macend() { 848 var c int 849 850 for { 851 c = getnsc() 852 if c < 0 || c == '\n' { 853 return 854 } 855 } 856 }