github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/dist/goc2c.c (about) 1 // Copyright 2009 The Go 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 #include "a.h" 6 7 /* 8 * Translate a .goc file into a .c file. A .goc file is a combination 9 * of a limited form of Go with C. 10 */ 11 12 /* 13 package PACKAGENAME 14 {# line} 15 func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{ 16 C code with proper brace nesting 17 \} 18 */ 19 20 /* 21 * We generate C code which implements the function such that it can 22 * be called from Go and executes the C code. 23 */ 24 25 static char *input; 26 static Buf *output; 27 #define EOF -1 28 29 enum 30 { 31 use64bitint = 1, 32 }; 33 34 static int 35 xgetchar(void) 36 { 37 int c; 38 39 c = *input; 40 if(c == 0) 41 return EOF; 42 input++; 43 return c; 44 } 45 46 static void 47 xungetc(void) 48 { 49 input--; 50 } 51 52 static void 53 xputchar(char c) 54 { 55 bwrite(output, &c, 1); 56 } 57 58 static int 59 xisspace(int c) 60 { 61 return c == ' ' || c == '\t' || c == '\r' || c == '\n'; 62 } 63 64 /* Whether we're emitting for gcc */ 65 static int gcc; 66 67 /* File and line number */ 68 static const char *file; 69 static unsigned int lineno; 70 71 /* List of names and types. */ 72 struct params { 73 struct params *next; 74 char *name; 75 char *type; 76 }; 77 78 /* index into type_table */ 79 enum { 80 Bool, 81 Float, 82 Int, 83 Uint, 84 Uintptr, 85 String, 86 Slice, 87 Eface, 88 Complex128, 89 Float32, 90 Float64, 91 }; 92 93 static struct { 94 char *name; 95 int size; 96 int rnd; // alignment 97 } type_table[] = { 98 /* 99 * variable sized first, for easy replacement. 100 * order matches enum above. 101 * default is 32-bit architecture sizes. 102 * spelling as in package runtime, so intgo/uintgo not int/uint. 103 */ 104 {"bool", 1}, 105 {"float", 4}, 106 {"intgo", 4}, 107 {"uintgo", 4}, 108 {"uintptr", 4}, 109 {"String", 8}, 110 {"Slice", 12}, 111 {"Eface", 8}, 112 {"Complex128", 16}, 113 114 /* fixed size */ 115 {"float32", 4}, 116 {"float64", 8}, 117 {"byte", 1}, 118 {"int8", 1}, 119 {"uint8", 1}, 120 {"int16", 2}, 121 {"uint16", 2}, 122 {"int32", 4}, 123 {"rune", 4}, 124 {"uint32", 4}, 125 {"int64", 8}, 126 {"uint64", 8}, 127 128 {nil, 0}, 129 }; 130 131 /* Fixed structure alignment (non-gcc only) */ 132 int structround = 4; 133 134 /* Unexpected EOF. */ 135 static void 136 bad_eof(void) 137 { 138 fatal("%s:%d: unexpected EOF\n", file, lineno); 139 } 140 141 /* Free a list of parameters. */ 142 static void 143 free_params(struct params *p) 144 { 145 while (p != nil) { 146 struct params *next; 147 148 next = p->next; 149 xfree(p->name); 150 xfree(p->type); 151 xfree(p); 152 p = next; 153 } 154 } 155 156 /* Read a character, tracking lineno. */ 157 static int 158 getchar_update_lineno(void) 159 { 160 int c; 161 162 c = xgetchar(); 163 if (c == '\n') 164 ++lineno; 165 return c; 166 } 167 168 /* Read a character, giving an error on EOF, tracking lineno. */ 169 static int 170 getchar_no_eof(void) 171 { 172 int c; 173 174 c = getchar_update_lineno(); 175 if (c == EOF) 176 bad_eof(); 177 return c; 178 } 179 180 /* Read a character, skipping comments. */ 181 static int 182 getchar_skipping_comments(void) 183 { 184 int c; 185 186 while (1) { 187 c = getchar_update_lineno(); 188 if (c != '/') 189 return c; 190 191 c = xgetchar(); 192 if (c == '/') { 193 do { 194 c = getchar_update_lineno(); 195 } while (c != EOF && c != '\n'); 196 return c; 197 } else if (c == '*') { 198 while (1) { 199 c = getchar_update_lineno(); 200 if (c == EOF) 201 return EOF; 202 if (c == '*') { 203 do { 204 c = getchar_update_lineno(); 205 } while (c == '*'); 206 if (c == '/') 207 break; 208 } 209 } 210 } else { 211 xungetc(); 212 return '/'; 213 } 214 } 215 } 216 217 /* 218 * Read and return a token. Tokens are string or character literals 219 * or else delimited by whitespace or by [(),{}]. 220 * The latter are all returned as single characters. 221 */ 222 static char * 223 read_token(void) 224 { 225 int c, q; 226 char *buf; 227 unsigned int alc, off; 228 char* delims = "(),{}"; 229 230 while (1) { 231 c = getchar_skipping_comments(); 232 if (c == EOF) 233 return nil; 234 if (!xisspace(c)) 235 break; 236 } 237 alc = 16; 238 buf = xmalloc(alc + 1); 239 off = 0; 240 if(c == '"' || c == '\'') { 241 q = c; 242 buf[off] = c; 243 ++off; 244 while (1) { 245 if (off+2 >= alc) { // room for c and maybe next char 246 alc *= 2; 247 buf = xrealloc(buf, alc + 1); 248 } 249 c = getchar_no_eof(); 250 buf[off] = c; 251 ++off; 252 if(c == q) 253 break; 254 if(c == '\\') { 255 buf[off] = getchar_no_eof(); 256 ++off; 257 } 258 } 259 } else if (xstrrchr(delims, c) != nil) { 260 buf[off] = c; 261 ++off; 262 } else { 263 while (1) { 264 if (off >= alc) { 265 alc *= 2; 266 buf = xrealloc(buf, alc + 1); 267 } 268 buf[off] = c; 269 ++off; 270 c = getchar_skipping_comments(); 271 if (c == EOF) 272 break; 273 if (xisspace(c) || xstrrchr(delims, c) != nil) { 274 if (c == '\n') 275 lineno--; 276 xungetc(); 277 break; 278 } 279 } 280 } 281 buf[off] = '\0'; 282 return buf; 283 } 284 285 /* Read a token, giving an error on EOF. */ 286 static char * 287 read_token_no_eof(void) 288 { 289 char *token = read_token(); 290 if (token == nil) 291 bad_eof(); 292 return token; 293 } 294 295 /* Read the package clause, and return the package name. */ 296 static char * 297 read_package(void) 298 { 299 char *token; 300 301 token = read_token_no_eof(); 302 if (token == nil) 303 fatal("%s:%d: no token\n", file, lineno); 304 if (!streq(token, "package")) { 305 fatal("%s:%d: expected \"package\", got \"%s\"\n", 306 file, lineno, token); 307 } 308 return read_token_no_eof(); 309 } 310 311 /* Read and copy preprocessor lines. */ 312 static void 313 read_preprocessor_lines(void) 314 { 315 int first; 316 317 first = 1; 318 while (1) { 319 int c; 320 321 do { 322 c = getchar_skipping_comments(); 323 } while (xisspace(c)); 324 if (c != '#') { 325 xungetc(); 326 break; 327 } 328 if(first) { 329 first = 0; 330 xputchar('\n'); 331 } 332 xputchar(c); 333 do { 334 c = getchar_update_lineno(); 335 xputchar(c); 336 } while (c != '\n'); 337 } 338 } 339 340 /* 341 * Read a type in Go syntax and return a type in C syntax. We only 342 * permit basic types and pointers. 343 */ 344 static char * 345 read_type(void) 346 { 347 char *p, *op, *q; 348 int pointer_count; 349 unsigned int len; 350 351 p = read_token_no_eof(); 352 if (*p != '*' && !streq(p, "int") && !streq(p, "uint")) 353 return p; 354 op = p; 355 pointer_count = 0; 356 while (*p == '*') { 357 ++pointer_count; 358 ++p; 359 } 360 len = xstrlen(p); 361 q = xmalloc(len + 2 + pointer_count + 1); 362 xmemmove(q, p, len); 363 364 // Turn int/uint into intgo/uintgo. 365 if((len == 3 && xmemcmp(q, "int", 3) == 0) || (len == 4 && xmemcmp(q, "uint", 4) == 0)) { 366 q[len++] = 'g'; 367 q[len++] = 'o'; 368 } 369 370 while (pointer_count-- > 0) 371 q[len++] = '*'; 372 373 q[len] = '\0'; 374 xfree(op); 375 return q; 376 } 377 378 /* Return the size of the given type. */ 379 static int 380 type_size(char *p, int *rnd) 381 { 382 int i; 383 384 if(p[xstrlen(p)-1] == '*') { 385 *rnd = type_table[Uintptr].rnd; 386 return type_table[Uintptr].size; 387 } 388 389 if(streq(p, "Iface")) 390 p = "Eface"; 391 392 for(i=0; type_table[i].name; i++) 393 if(streq(type_table[i].name, p)) { 394 *rnd = type_table[i].rnd; 395 return type_table[i].size; 396 } 397 fatal("%s:%d: unknown type %s\n", file, lineno, p); 398 return 0; 399 } 400 401 /* 402 * Read a list of parameters. Each parameter is a name and a type. 403 * The list ends with a ')'. We have already read the '('. 404 */ 405 static struct params * 406 read_params(int *poffset) 407 { 408 char *token; 409 struct params *ret, **pp, *p; 410 int offset, size, rnd; 411 412 ret = nil; 413 pp = &ret; 414 token = read_token_no_eof(); 415 offset = 0; 416 if (!streq(token, ")")) { 417 while (1) { 418 p = xmalloc(sizeof(struct params)); 419 p->name = token; 420 p->next = nil; 421 *pp = p; 422 pp = &p->next; 423 424 if(streq(token, "...")) { 425 p->type = xstrdup(""); 426 } else { 427 p->type = read_type(); 428 rnd = 0; 429 size = type_size(p->type, &rnd); 430 if(rnd > structround) 431 rnd = structround; 432 if(offset%rnd) 433 offset += rnd - offset%rnd; 434 offset += size; 435 } 436 437 token = read_token_no_eof(); 438 if (!streq(token, ",")) 439 break; 440 token = read_token_no_eof(); 441 } 442 } 443 if (!streq(token, ")")) { 444 fatal("%s:%d: expected '('\n", 445 file, lineno); 446 } 447 if (poffset != nil) 448 *poffset = offset; 449 return ret; 450 } 451 452 /* 453 * Read a function header. This reads up to and including the initial 454 * '{' character. Returns 1 if it read a header, 0 at EOF. 455 */ 456 static int 457 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets) 458 { 459 int lastline; 460 char *token; 461 462 lastline = -1; 463 while (1) { 464 read_preprocessor_lines(); 465 token = read_token(); 466 if (token == nil) 467 return 0; 468 if (streq(token, "func")) { 469 if(lastline != -1) 470 bwritef(output, "\n"); 471 break; 472 } 473 if (lastline != lineno) { 474 if (lastline == lineno-1) 475 bwritef(output, "\n"); 476 else 477 bwritef(output, "\n#line %d \"%s\"\n", lineno, file); 478 lastline = lineno; 479 } 480 bwritef(output, "%s ", token); 481 } 482 483 *name = read_token_no_eof(); 484 485 token = read_token(); 486 if (token == nil || !streq(token, "(")) { 487 fatal("%s:%d: expected \"(\"\n", 488 file, lineno); 489 } 490 *params = read_params(paramwid); 491 492 token = read_token(); 493 if (token == nil || !streq(token, "(")) 494 *rets = nil; 495 else { 496 *rets = read_params(nil); 497 token = read_token(); 498 } 499 if (token == nil || !streq(token, "{")) { 500 fatal("%s:%d: expected \"{\"\n", 501 file, lineno); 502 } 503 return 1; 504 } 505 506 /* Write out parameters. */ 507 static void 508 write_params(struct params *params, int *first) 509 { 510 struct params *p; 511 512 for (p = params; p != nil; p = p->next) { 513 if (*first) 514 *first = 0; 515 else 516 bwritef(output, ", "); 517 bwritef(output, "%s %s", p->type, p->name); 518 } 519 } 520 521 /* Write a 6g function header. */ 522 static void 523 write_6g_func_header(char *package, char *name, struct params *params, 524 int paramwid, struct params *rets) 525 { 526 int first, n; 527 struct params *p; 528 529 bwritef(output, "void\n"); 530 if(!contains(name, "·")) 531 bwritef(output, "%s·", package); 532 bwritef(output, "%s(", name); 533 534 first = 1; 535 write_params(params, &first); 536 537 /* insert padding to align output struct */ 538 if(rets != nil && paramwid%structround != 0) { 539 n = structround - paramwid%structround; 540 if(n & 1) 541 bwritef(output, ", uint8"); 542 if(n & 2) 543 bwritef(output, ", uint16"); 544 if(n & 4) 545 bwritef(output, ", uint32"); 546 } 547 548 write_params(rets, &first); 549 bwritef(output, ")\n{\n"); 550 551 for (p = rets; p != nil; p = p->next) { 552 if(streq(p->name, "...")) 553 continue; 554 if(streq(p->type, "Slice")) 555 bwritef(output, "\t%s.array = 0;\n\t%s.len = 0;\n\t%s.cap = 0;\n", p->name, p->name, p->name); 556 else if(streq(p->type, "String")) 557 bwritef(output, "\t%s.str = 0;\n\t%s.len = 0;\n", p->name, p->name); 558 else if(streq(p->type, "Eface")) 559 bwritef(output, "\t%s.type = 0;\n\t%s.data = 0;\n", p->name, p->name); 560 else if(streq(p->type, "Iface")) 561 bwritef(output, "\t%s.tab = 0;\n\t%s.data = 0;\n", p->name, p->name); 562 else if(streq(p->type, "Complex128")) 563 bwritef(output, "\t%s.real = 0;\n\t%s.imag = 0;\n", p->name, p->name); 564 else 565 bwritef(output, "\t%s = 0;\n", p->name); 566 bwritef(output, "\tFLUSH(&%s);\n", p->name); 567 } 568 } 569 570 /* Write a 6g function trailer. */ 571 static void 572 write_6g_func_trailer(struct params *rets) 573 { 574 struct params *p; 575 576 for (p = rets; p != nil; p = p->next) 577 if(!streq(p->name, "...")) 578 bwritef(output, "\tFLUSH(&%s);\n", p->name); 579 bwritef(output, "}\n"); 580 } 581 582 /* Define the gcc function return type if necessary. */ 583 static void 584 define_gcc_return_type(char *package, char *name, struct params *rets) 585 { 586 struct params *p; 587 588 if (rets == nil || rets->next == nil) 589 return; 590 bwritef(output, "struct %s_%s_ret {\n", package, name); 591 for (p = rets; p != nil; p = p->next) 592 bwritef(output, " %s %s;\n", p->type, p->name); 593 bwritef(output, "};\n"); 594 } 595 596 /* Write out the gcc function return type. */ 597 static void 598 write_gcc_return_type(char *package, char *name, struct params *rets) 599 { 600 if (rets == nil) 601 bwritef(output, "void"); 602 else if (rets->next == nil) 603 bwritef(output, "%s", rets->type); 604 else 605 bwritef(output, "struct %s_%s_ret", package, name); 606 } 607 608 /* Write out a gcc function header. */ 609 static void 610 write_gcc_func_header(char *package, char *name, struct params *params, 611 struct params *rets) 612 { 613 int first; 614 struct params *p; 615 616 define_gcc_return_type(package, name, rets); 617 write_gcc_return_type(package, name, rets); 618 bwritef(output, " %s_%s(", package, name); 619 first = 1; 620 write_params(params, &first); 621 bwritef(output, ") asm (\"%s.%s\");\n", package, name); 622 write_gcc_return_type(package, name, rets); 623 bwritef(output, " %s_%s(", package, name); 624 first = 1; 625 write_params(params, &first); 626 bwritef(output, ")\n{\n"); 627 for (p = rets; p != nil; p = p->next) 628 bwritef(output, " %s %s;\n", p->type, p->name); 629 } 630 631 /* Write out a gcc function trailer. */ 632 static void 633 write_gcc_func_trailer(char *package, char *name, struct params *rets) 634 { 635 if (rets == nil) { 636 // nothing to do 637 } 638 else if (rets->next == nil) 639 bwritef(output, "return %s;\n", rets->name); 640 else { 641 struct params *p; 642 643 bwritef(output, " {\n struct %s_%s_ret __ret;\n", package, name); 644 for (p = rets; p != nil; p = p->next) 645 bwritef(output, " __ret.%s = %s;\n", p->name, p->name); 646 bwritef(output, " return __ret;\n }\n"); 647 } 648 bwritef(output, "}\n"); 649 } 650 651 /* Write out a function header. */ 652 static void 653 write_func_header(char *package, char *name, 654 struct params *params, int paramwid, 655 struct params *rets) 656 { 657 if (gcc) 658 write_gcc_func_header(package, name, params, rets); 659 else 660 write_6g_func_header(package, name, params, paramwid, rets); 661 bwritef(output, "#line %d \"%s\"\n", lineno, file); 662 } 663 664 /* Write out a function trailer. */ 665 static void 666 write_func_trailer(char *package, char *name, 667 struct params *rets) 668 { 669 if (gcc) 670 write_gcc_func_trailer(package, name, rets); 671 else 672 write_6g_func_trailer(rets); 673 } 674 675 /* 676 * Read and write the body of the function, ending in an unnested } 677 * (which is read but not written). 678 */ 679 static void 680 copy_body(void) 681 { 682 int nesting = 0; 683 while (1) { 684 int c; 685 686 c = getchar_no_eof(); 687 if (c == '}' && nesting == 0) 688 return; 689 xputchar(c); 690 switch (c) { 691 default: 692 break; 693 case '{': 694 ++nesting; 695 break; 696 case '}': 697 --nesting; 698 break; 699 case '/': 700 c = getchar_update_lineno(); 701 xputchar(c); 702 if (c == '/') { 703 do { 704 c = getchar_no_eof(); 705 xputchar(c); 706 } while (c != '\n'); 707 } else if (c == '*') { 708 while (1) { 709 c = getchar_no_eof(); 710 xputchar(c); 711 if (c == '*') { 712 do { 713 c = getchar_no_eof(); 714 xputchar(c); 715 } while (c == '*'); 716 if (c == '/') 717 break; 718 } 719 } 720 } 721 break; 722 case '"': 723 case '\'': 724 { 725 int delim = c; 726 do { 727 c = getchar_no_eof(); 728 xputchar(c); 729 if (c == '\\') { 730 c = getchar_no_eof(); 731 xputchar(c); 732 c = '\0'; 733 } 734 } while (c != delim); 735 } 736 break; 737 } 738 } 739 } 740 741 /* Process the entire file. */ 742 static void 743 process_file(void) 744 { 745 char *package, *name, *p, *n; 746 struct params *params, *rets; 747 int paramwid; 748 749 package = read_package(); 750 read_preprocessor_lines(); 751 while (read_func_header(&name, ¶ms, ¶mwid, &rets)) { 752 // name may have a package override already 753 n = xstrstr(name, "·"); 754 if(n != nil) { 755 p = xmalloc(n - name + 1); 756 xmemmove(p, name, n - name); 757 p[n - name] = 0; 758 n += xstrlen("·"); 759 } else { 760 p = package; 761 n = name; 762 } 763 write_func_header(p, n, params, paramwid, rets); 764 copy_body(); 765 write_func_trailer(p, n, rets); 766 xfree(name); 767 if(p != package) xfree(p); 768 free_params(params); 769 free_params(rets); 770 } 771 xfree(package); 772 } 773 774 void 775 goc2c(char *goc, char *c) 776 { 777 int i; 778 Buf in, out; 779 780 binit(&in); 781 binit(&out); 782 783 file = goc; 784 readfile(&in, goc); 785 786 // TODO: set gcc=1 when using gcc 787 788 if(!gcc) { 789 if(streq(goarch, "amd64")) { 790 type_table[Uintptr].size = 8; 791 if(use64bitint) { 792 type_table[Int].size = 8; 793 } else { 794 type_table[Int].size = 4; 795 } 796 structround = 8; 797 } else if(streq(goarch, "amd64p32")) { 798 type_table[Uintptr].size = 4; 799 type_table[Int].size = 4; 800 structround = 8; 801 } else { 802 // NOTE: These are set in the initializer, 803 // but they might have been changed by a 804 // previous invocation of goc2c, so we have 805 // to restore them. 806 type_table[Uintptr].size = 4; 807 type_table[Int].size = 4; 808 structround = 4; 809 } 810 811 type_table[Uint].size = type_table[Int].size; 812 type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size; 813 type_table[Eface].size = 2*type_table[Uintptr].size; 814 type_table[String].size = 2*type_table[Uintptr].size; 815 816 for(i=0; i<nelem(type_table); i++) 817 type_table[i].rnd = type_table[i].size; 818 819 type_table[String].rnd = type_table[Uintptr].rnd; 820 type_table[Slice].rnd = type_table[Uintptr].rnd; 821 type_table[Eface].rnd = type_table[Uintptr].rnd; 822 type_table[Complex128].rnd = type_table[Float64].rnd; 823 } 824 825 bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch); 826 input = bstr(&in); 827 output = &out; 828 829 lineno = 1; 830 process_file(); 831 832 writefile(&out, c, 0); 833 }