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