github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/cc/dpchk.c (about) 1 // Inferno utils/cc/dpchk.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c 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 #include <u.h> 32 #include "cc.h" 33 #include "y.tab.h" 34 35 enum 36 { 37 Fnone = 0, 38 Fl, 39 Fvl, 40 Fignor, 41 Fstar, 42 Fadj, 43 44 Fverb = 10, 45 }; 46 47 typedef struct Tprot Tprot; 48 struct Tprot 49 { 50 Type* type; 51 Bits flag; 52 Tprot* link; 53 }; 54 55 typedef struct Tname Tname; 56 struct Tname 57 { 58 char* name; 59 int param; 60 int count; 61 Tname* link; 62 Tprot* prot; 63 }; 64 65 static Type* indchar; 66 static uchar flagbits[512]; 67 static char* lastfmt; 68 static int lastadj; 69 static int lastverb; 70 static int nstar; 71 static Tprot* tprot; 72 static Tname* tname; 73 74 void 75 argflag(int c, int v) 76 { 77 78 switch(v) { 79 case Fignor: 80 case Fstar: 81 case Fl: 82 case Fvl: 83 flagbits[c] = v; 84 break; 85 case Fverb: 86 flagbits[c] = lastverb; 87 /*print("flag-v %c %d\n", c, lastadj);*/ 88 lastverb++; 89 break; 90 case Fadj: 91 flagbits[c] = lastadj; 92 /*print("flag-l %c %d\n", c, lastadj);*/ 93 lastadj++; 94 break; 95 } 96 } 97 98 Bits 99 getflag(char *s) 100 { 101 Bits flag; 102 int f; 103 Fmt fmt; 104 Rune c; 105 106 flag = zbits; 107 nstar = 0; 108 fmtstrinit(&fmt); 109 for(;;) { 110 s += chartorune(&c, s); 111 if(c == 0 || c >= nelem(flagbits)) 112 break; 113 fmtrune(&fmt, c); 114 f = flagbits[c]; 115 switch(f) { 116 case Fnone: 117 argflag(c, Fverb); 118 f = flagbits[c]; 119 break; 120 case Fstar: 121 nstar++; 122 case Fignor: 123 continue; 124 case Fl: 125 if(bset(flag, Fl)) 126 flag = bor(flag, blsh(Fvl)); 127 } 128 flag = bor(flag, blsh(f)); 129 if(f >= Fverb) 130 break; 131 } 132 free(lastfmt); 133 lastfmt = fmtstrflush(&fmt); 134 return flag; 135 } 136 137 static void 138 newprot(Sym *m, Type *t, char *s, Tprot **prot) 139 { 140 Bits flag; 141 Tprot *l; 142 143 if(t == T) { 144 warn(Z, "%s: newprot: type not defined", m->name); 145 return; 146 } 147 flag = getflag(s); 148 for(l=*prot; l; l=l->link) 149 if(beq(flag, l->flag) && sametype(t, l->type)) 150 return; 151 l = alloc(sizeof(*l)); 152 l->type = t; 153 l->flag = flag; 154 l->link = *prot; 155 *prot = l; 156 } 157 158 static Tname* 159 newname(char *s, int p, int count) 160 { 161 Tname *l; 162 163 for(l=tname; l; l=l->link) 164 if(strcmp(l->name, s) == 0) { 165 if(p >= 0 && l->param != p) 166 yyerror("vargck %s already defined\n", s); 167 return l; 168 } 169 if(p < 0) 170 return nil; 171 172 l = alloc(sizeof(*l)); 173 l->name = s; 174 l->param = p; 175 l->link = tname; 176 l->count = count; 177 tname = l; 178 return l; 179 } 180 181 void 182 arginit(void) 183 { 184 int i; 185 186 /* debug['F'] = 1;*/ 187 /* debug['w'] = 1;*/ 188 189 lastadj = Fadj; 190 lastverb = Fverb; 191 indchar = typ(TIND, types[TCHAR]); 192 193 memset(flagbits, Fnone, sizeof(flagbits)); 194 195 for(i='0'; i<='9'; i++) 196 argflag(i, Fignor); 197 argflag('.', Fignor); 198 argflag('#', Fignor); 199 argflag('u', Fignor); 200 argflag('h', Fignor); 201 argflag('+', Fignor); 202 argflag('-', Fignor); 203 204 argflag('*', Fstar); 205 argflag('l', Fl); 206 207 argflag('o', Fverb); 208 flagbits['x'] = flagbits['o']; 209 flagbits['X'] = flagbits['o']; 210 } 211 212 static char* 213 getquoted(void) 214 { 215 int c; 216 Rune r; 217 Fmt fmt; 218 219 c = getnsc(); 220 if(c != '"') 221 return nil; 222 fmtstrinit(&fmt); 223 for(;;) { 224 r = getr(); 225 if(r == '\n') { 226 free(fmtstrflush(&fmt)); 227 return nil; 228 } 229 if(r == '"') 230 break; 231 fmtrune(&fmt, r); 232 } 233 free(lastfmt); 234 lastfmt = fmtstrflush(&fmt); 235 return strdup(lastfmt); 236 } 237 238 void 239 pragvararg(void) 240 { 241 Sym *s; 242 int n, c; 243 char *t; 244 Type *ty; 245 Tname *l; 246 247 if(!debug['F']) 248 goto out; 249 s = getsym(); 250 if(s && strcmp(s->name, "argpos") == 0) 251 goto ckpos; 252 if(s && strcmp(s->name, "type") == 0) 253 goto cktype; 254 if(s && strcmp(s->name, "flag") == 0) 255 goto ckflag; 256 if(s && strcmp(s->name, "countpos") == 0) 257 goto ckcount; 258 yyerror("syntax in #pragma varargck"); 259 goto out; 260 261 ckpos: 262 /*#pragma varargck argpos warn 2*/ 263 s = getsym(); 264 if(s == S) 265 goto bad; 266 n = getnsn(); 267 if(n < 0) 268 goto bad; 269 newname(s->name, n, 0); 270 goto out; 271 272 ckcount: 273 /*#pragma varargck countpos name 2*/ 274 s = getsym(); 275 if(s == S) 276 goto bad; 277 n = getnsn(); 278 if(n < 0) 279 goto bad; 280 newname(s->name, 0, n); 281 goto out; 282 283 ckflag: 284 /*#pragma varargck flag 'c'*/ 285 c = getnsc(); 286 if(c != '\'') 287 goto bad; 288 c = getr(); 289 if(c == '\\') 290 c = getr(); 291 else if(c == '\'') 292 goto bad; 293 if(c == '\n') 294 goto bad; 295 if(getc() != '\'') 296 goto bad; 297 argflag(c, Fignor); 298 goto out; 299 300 cktype: 301 c = getnsc(); 302 unget(c); 303 if(c != '"') { 304 /*#pragma varargck type name int*/ 305 s = getsym(); 306 if(s == S) 307 goto bad; 308 l = newname(s->name, -1, -1); 309 s = getsym(); 310 if(s == S) 311 goto bad; 312 ty = s->type; 313 while((c = getnsc()) == '*') 314 ty = typ(TIND, ty); 315 unget(c); 316 newprot(s, ty, "a", &l->prot); 317 goto out; 318 } 319 320 /*#pragma varargck type O int*/ 321 t = getquoted(); 322 if(t == nil) 323 goto bad; 324 s = getsym(); 325 if(s == S) 326 goto bad; 327 ty = s->type; 328 while((c = getnsc()) == '*') 329 ty = typ(TIND, ty); 330 unget(c); 331 newprot(s, ty, t, &tprot); 332 goto out; 333 334 bad: 335 yyerror("syntax in #pragma varargck"); 336 337 out: 338 while(getnsc() != '\n') 339 ; 340 } 341 342 Node* 343 nextarg(Node *n, Node **a) 344 { 345 if(n == Z) { 346 *a = Z; 347 return Z; 348 } 349 if(n->op == OLIST) { 350 *a = n->left; 351 return n->right; 352 } 353 *a = n; 354 return Z; 355 } 356 357 void 358 checkargs(Node *nn, char *s, int pos) 359 { 360 Node *a, *n; 361 Bits flag; 362 Tprot *l; 363 364 if(!debug['F']) 365 return; 366 n = nn; 367 for(;;) { 368 s = strchr(s, '%'); 369 if(s == 0) { 370 nextarg(n, &a); 371 if(a != Z) 372 warn(nn, "more arguments than format %T", 373 a->type); 374 return; 375 } 376 s++; 377 flag = getflag(s); 378 while(nstar > 0) { 379 n = nextarg(n, &a); 380 pos++; 381 nstar--; 382 if(a == Z) { 383 warn(nn, "more format than arguments %s", 384 lastfmt); 385 return; 386 } 387 if(a->type == T) 388 continue; 389 if(!sametype(types[TINT], a->type) && 390 !sametype(types[TUINT], a->type)) 391 warn(nn, "format mismatch '*' in %s %T, arg %d", 392 lastfmt, a->type, pos); 393 } 394 for(l=tprot; l; l=l->link) 395 if(sametype(types[TVOID], l->type)) { 396 if(beq(flag, l->flag)) { 397 s++; 398 goto loop; 399 } 400 } 401 402 n = nextarg(n, &a); 403 pos++; 404 if(a == Z) { 405 warn(nn, "more format than arguments %s", 406 lastfmt); 407 return; 408 } 409 if(a->type == 0) 410 continue; 411 for(l=tprot; l; l=l->link) 412 if(sametype(a->type, l->type)) { 413 /*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/ 414 if(beq(flag, l->flag)) 415 goto loop; 416 } 417 warn(nn, "format mismatch %s %T, arg %d", lastfmt, a->type, pos); 418 loop:; 419 } 420 } 421 422 void 423 dpcheck(Node *n) 424 { 425 char *s; 426 Node *a, *b; 427 Tname *l; 428 Tprot *tl; 429 int i, j; 430 431 if(n == Z) 432 return; 433 b = n->left; 434 if(b == Z || b->op != ONAME) 435 return; 436 s = b->sym->name; 437 for(l=tname; l; l=l->link) 438 if(strcmp(s, l->name) == 0) 439 break; 440 if(l == 0) 441 return; 442 443 if(l->count > 0) { 444 // fetch count, then check remaining length 445 i = l->count; 446 a = nil; 447 b = n->right; 448 while(i > 0) { 449 b = nextarg(b, &a); 450 i--; 451 } 452 if(a == Z) { 453 diag(n, "can't find count arg"); 454 return; 455 } 456 if(a->op != OCONST || !typechl[a->type->etype]) { 457 diag(n, "count is invalid constant"); 458 return; 459 } 460 j = a->vconst; 461 i = 0; 462 while(b != Z) { 463 b = nextarg(b, &a); 464 i++; 465 } 466 if(i != j) 467 diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j); 468 } 469 470 if(l->prot != nil) { 471 // check that all arguments after param or count 472 // are listed in type list. 473 i = l->count; 474 if(i == 0) 475 i = l->param; 476 if(i == 0) 477 return; 478 a = nil; 479 b = n->right; 480 while(i > 0) { 481 b = nextarg(b, &a); 482 i--; 483 } 484 if(a == Z) { 485 diag(n, "can't find count/param arg"); 486 return; 487 } 488 while(b != Z) { 489 b = nextarg(b, &a); 490 for(tl=l->prot; tl; tl=tl->link) 491 if(sametype(a->type, tl->type)) 492 break; 493 if(tl == nil) 494 diag(a, "invalid type %T in call to %s", a->type, s); 495 } 496 } 497 498 if(l->param <= 0) 499 return; 500 i = l->param; 501 a = nil; 502 b = n->right; 503 while(i > 0) { 504 b = nextarg(b, &a); 505 i--; 506 } 507 if(a == Z) { 508 diag(n, "can't find format arg"); 509 return; 510 } 511 if(!sametype(indchar, a->type)) { 512 diag(n, "format arg type %T", a->type); 513 return; 514 } 515 if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { 516 /* warn(n, "format arg not constant string");*/ 517 return; 518 } 519 s = a->left->cstring; 520 checkargs(b, s, l->param); 521 } 522 523 void 524 pragpack(void) 525 { 526 Sym *s; 527 528 packflg = 0; 529 s = getsym(); 530 if(s) { 531 packflg = atoi(s->name+1); 532 if(strcmp(s->name, "on") == 0 || 533 strcmp(s->name, "yes") == 0) 534 packflg = 1; 535 } 536 while(getnsc() != '\n') 537 ; 538 if(debug['f']) 539 if(packflg) 540 print("%4d: pack %d\n", lineno, packflg); 541 else 542 print("%4d: pack off\n", lineno); 543 } 544 545 void 546 pragfpround(void) 547 { 548 Sym *s; 549 550 fproundflg = 0; 551 s = getsym(); 552 if(s) { 553 fproundflg = atoi(s->name+1); 554 if(strcmp(s->name, "on") == 0 || 555 strcmp(s->name, "yes") == 0) 556 fproundflg = 1; 557 } 558 while(getnsc() != '\n') 559 ; 560 if(debug['f']) 561 if(fproundflg) 562 print("%4d: fproundflg %d\n", lineno, fproundflg); 563 else 564 print("%4d: fproundflg off\n", lineno); 565 } 566 567 void 568 pragtextflag(void) 569 { 570 textflag = getnsn(); 571 while(getnsc() != '\n') 572 ; 573 if(debug['f']) 574 print("%4d: textflag %d\n", lineno, textflag); 575 } 576 577 void 578 pragdataflag(void) 579 { 580 dataflag = getnsn(); 581 while(getnsc() != '\n') 582 ; 583 if(debug['f']) 584 print("%4d: dataflag %d\n", lineno, dataflag); 585 } 586 587 void 588 pragincomplete(void) 589 { 590 Sym *s; 591 Type *t; 592 int istag, w, et; 593 594 istag = 0; 595 s = getsym(); 596 if(s == nil) 597 goto out; 598 et = 0; 599 w = s->lexical; 600 if(w == LSTRUCT) 601 et = TSTRUCT; 602 else if(w == LUNION) 603 et = TUNION; 604 if(et != 0){ 605 s = getsym(); 606 if(s == nil){ 607 yyerror("missing struct/union tag in pragma incomplete"); 608 goto out; 609 } 610 if(s->lexical != LNAME && s->lexical != LTYPE){ 611 yyerror("invalid struct/union tag: %s", s->name); 612 goto out; 613 } 614 dotag(s, et, 0); 615 istag = 1; 616 }else if(strcmp(s->name, "_off_") == 0){ 617 debug['T'] = 0; 618 goto out; 619 }else if(strcmp(s->name, "_on_") == 0){ 620 debug['T'] = 1; 621 goto out; 622 } 623 t = s->type; 624 if(istag) 625 t = s->suetag; 626 if(t == T) 627 yyerror("unknown type %s in pragma incomplete", s->name); 628 else if(!typesu[t->etype]) 629 yyerror("not struct/union type in pragma incomplete: %s", s->name); 630 else 631 t->garb |= GINCOMPLETE; 632 out: 633 while(getnsc() != '\n') 634 ; 635 if(debug['f']) 636 print("%s incomplete\n", s->name); 637 } 638 639 Sym* 640 getimpsym(void) 641 { 642 int c; 643 char *cp; 644 645 c = getnsc(); 646 if(isspace(c) || c == '"') { 647 unget(c); 648 return S; 649 } 650 for(cp = symb;;) { 651 if(cp <= symb+NSYMB-4) 652 *cp++ = c; 653 c = getc(); 654 if(c > 0 && !isspace(c) && c != '"') 655 continue; 656 unget(c); 657 break; 658 } 659 *cp = 0; 660 if(cp > symb+NSYMB-4) 661 yyerror("symbol too large: %s", symb); 662 return lookup(); 663 } 664 665 static int 666 more(void) 667 { 668 int c; 669 670 do 671 c = getnsc(); 672 while(c == ' ' || c == '\t'); 673 unget(c); 674 return c != '\n'; 675 } 676 677 void 678 pragcgo(char *verb) 679 { 680 Sym *local, *remote; 681 char *p; 682 683 if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) { 684 p = getquoted(); 685 if(p == nil) 686 goto err1; 687 fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p); 688 goto out; 689 690 err1: 691 yyerror("usage: #pragma cgo_dynamic_linker \"path\""); 692 goto out; 693 } 694 695 if(strcmp(verb, "dynexport") == 0) 696 verb = "cgo_export_dynamic"; 697 if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) { 698 local = getimpsym(); 699 if(local == nil) 700 goto err2; 701 if(!more()) { 702 fmtprint(&pragcgobuf, "%s %q\n", verb, local->name); 703 goto out; 704 } 705 remote = getimpsym(); 706 if(remote == nil) 707 goto err2; 708 fmtprint(&pragcgobuf, "%s %q %q\n", verb, local->name, remote->name); 709 goto out; 710 711 err2: 712 yyerror("usage: #pragma %s local [remote]", verb); 713 goto out; 714 } 715 716 if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) { 717 local = getimpsym(); 718 if(local == nil) 719 goto err3; 720 if(!more()) { 721 fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local->name); 722 goto out; 723 } 724 remote = getimpsym(); 725 if(remote == nil) 726 goto err3; 727 if(!more()) { 728 fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local->name, remote->name); 729 goto out; 730 } 731 p = getquoted(); 732 if(p == nil) 733 goto err3; 734 fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local->name, remote->name, p); 735 goto out; 736 737 err3: 738 yyerror("usage: #pragma cgo_import_dynamic local [remote [\"library\"]]"); 739 goto out; 740 } 741 742 if(strcmp(verb, "cgo_import_static") == 0) { 743 local = getimpsym(); 744 if(local == nil) 745 goto err4; 746 fmtprint(&pragcgobuf, "cgo_import_static %q\n", local->name); 747 goto out; 748 749 err4: 750 yyerror("usage: #pragma cgo_import_static local [remote]"); 751 goto out; 752 } 753 754 if(strcmp(verb, "cgo_ldflag") == 0) { 755 p = getquoted(); 756 if(p == nil) 757 goto err5; 758 fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p); 759 goto out; 760 761 err5: 762 yyerror("usage: #pragma cgo_ldflag \"arg\""); 763 goto out; 764 } 765 766 out: 767 while(getnsc() != '\n') 768 ; 769 }