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.
8 * Translate a .goc file into a .c file. A .goc file is a combination
9 * of a limited form of Go with C.
15 func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
16 C code with proper brace nesting
21 * We generate C code which implements the function such that it can
22 * be called from Go and executes the C code.
33 /* Whether we're emitting for gcc */
36 /* Package path to use; only meaningful for gcc */
37 static const char *pkgpath;
39 /* Package prefix to use; only meaningful for gcc */
40 static const char *prefix;
42 /* File and line number */
43 static const char *file;
44 static unsigned int lineno = 1;
46 /* List of names and types. */
53 /* index into type_table */
69 /* variable sized first, for easy replacement */
70 /* order matches enum above */
71 /* default is 32-bit architecture sizes */
97 /* Fixed structure alignment (non-gcc only) */
103 sysfatal(char *fmt, ...)
109 vsnprintf(buf, sizeof buf, fmt, arg);
112 fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
116 /* Unexpected EOF. */
120 sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
127 sysfatal("%s:%ud: out of memory\n", file, lineno);
130 /* Allocate memory without fail. */
132 xmalloc(unsigned int size)
134 void *ret = malloc(size);
140 /* Reallocate memory without fail. */
142 xrealloc(void *buf, unsigned int size)
144 void *ret = realloc(buf, size);
150 /* Free a list of parameters. */
152 free_params(struct params *p)
165 /* Read a character, tracking lineno. */
167 getchar_update_lineno(void)
177 /* Read a character, giving an error on EOF, tracking lineno. */
183 c = getchar_update_lineno();
189 /* Read a character, skipping comments. */
191 getchar_skipping_comments(void)
196 c = getchar_update_lineno();
203 c = getchar_update_lineno();
204 } while (c != EOF && c != '\n');
206 } else if (c == '*') {
208 c = getchar_update_lineno();
213 c = getchar_update_lineno();
227 * Read and return a token. Tokens are string or character literals
228 * or else delimited by whitespace or by [(),{}].
229 * The latter are all returned as single characters.
236 unsigned int alc, off;
237 const char* delims = "(),{}";
240 c = getchar_skipping_comments();
247 buf = xmalloc(alc + 1);
249 if(c == '"' || c == '\'') {
254 if (off+2 >= alc) { // room for c and maybe next char
256 buf = xrealloc(buf, alc + 1);
258 c = getchar_no_eof();
264 buf[off] = getchar_no_eof();
268 } else if (strchr(delims, c) != NULL) {
275 buf = xrealloc(buf, alc + 1);
279 c = getchar_skipping_comments();
282 if (isspace(c) || strchr(delims, c) != NULL) {
294 /* Read a token, giving an error on EOF. */
296 read_token_no_eof(void)
298 char *token = read_token();
304 /* Read the package clause, and return the package name. */
310 token = read_token_no_eof();
312 sysfatal("%s:%ud: no token\n", file, lineno);
313 if (strcmp(token, "package") != 0) {
314 sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
315 file, lineno, token);
317 return read_token_no_eof();
320 /* Read and copy preprocessor lines. */
322 read_preprocessor_lines(void)
328 c = getchar_skipping_comments();
329 } while (isspace(c));
336 c = getchar_update_lineno();
343 * Read a type in Go syntax and return a type in C syntax. We only
344 * permit basic types and pointers.
353 p = read_token_no_eof();
363 q = xmalloc(len + pointer_count + 1);
365 while (pointer_count > 0) {
375 /* Return the size of the given type. */
381 if(p[strlen(p)-1] == '*')
382 return type_table[Uintptr].size;
384 for(i=0; type_table[i].name; i++)
385 if(strcmp(type_table[i].name, p) == 0)
386 return type_table[i].size;
388 sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
394 * Read a list of parameters. Each parameter is a name and a type.
395 * The list ends with a ')'. We have already read the '('.
397 static struct params *
398 read_params(int *poffset)
401 struct params *ret, **pp, *p;
402 int offset, size, rnd;
406 token = read_token_no_eof();
408 if (strcmp(token, ")") != 0) {
410 p = xmalloc(sizeof(struct params));
412 p->type = read_type();
417 size = type_size(p->type);
419 if(rnd > structround)
422 offset += rnd - offset%rnd;
425 token = read_token_no_eof();
426 if (strcmp(token, ",") != 0)
428 token = read_token_no_eof();
431 if (strcmp(token, ")") != 0) {
432 sysfatal("%s:%ud: expected '('\n",
441 * Read a function header. This reads up to and including the initial
442 * '{' character. Returns 1 if it read a header, 0 at EOF.
445 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
452 token = read_token();
455 if (strcmp(token, "func") == 0) {
460 if (lastline != lineno) {
461 if (lastline == lineno-1)
464 printf("\n#line %d \"%s\"\n", lineno, file);
467 printf("%s ", token);
470 *name = read_token_no_eof();
472 token = read_token();
473 if (token == NULL || strcmp(token, "(") != 0) {
474 sysfatal("%s:%ud: expected \"(\"\n",
477 *params = read_params(paramwid);
479 token = read_token();
480 if (token == NULL || strcmp(token, "(") != 0)
483 *rets = read_params(NULL);
484 token = read_token();
486 if (token == NULL || strcmp(token, "{") != 0) {
487 sysfatal("%s:%ud: expected \"{\"\n",
493 /* Write out parameters. */
495 write_params(struct params *params, int *first)
499 for (p = params; p != NULL; p = p->next) {
504 printf("%s %s", p->type, p->name);
508 /* Write a 6g function header. */
510 write_6g_func_header(char *package, char *name, struct params *params,
511 int paramwid, struct params *rets)
515 printf("void\n%s·%s(", package, name);
517 write_params(params, &first);
519 /* insert padding to align output struct */
520 if(rets != NULL && paramwid%structround != 0) {
521 n = structround - paramwid%structround;
530 write_params(rets, &first);
534 /* Write a 6g function trailer. */
536 write_6g_func_trailer(struct params *rets)
540 for (p = rets; p != NULL; p = p->next)
541 printf("\tFLUSH(&%s);\n", p->name);
545 /* Define the gcc function return type if necessary. */
547 define_gcc_return_type(char *package, char *name, struct params *rets)
551 if (rets == NULL || rets->next == NULL)
553 printf("struct %s_%s_ret {\n", package, name);
554 for (p = rets; p != NULL; p = p->next)
555 printf(" %s %s;\n", p->type, p->name);
559 /* Write out the gcc function return type. */
561 write_gcc_return_type(char *package, char *name, struct params *rets)
565 else if (rets->next == NULL)
566 printf("%s", rets->type);
568 printf("struct %s_%s_ret", package, name);
571 /* Write out a gcc function header. */
573 write_gcc_func_header(char *package, char *name, struct params *params,
579 define_gcc_return_type(package, name, rets);
580 write_gcc_return_type(package, name, rets);
581 printf(" %s_%s(", package, name);
583 write_params(params, &first);
586 printf("%s", pkgpath);
587 else if (prefix != NULL)
588 printf("%s.%s", prefix, package);
590 printf("%s", package);
591 printf(".%s\");\n", name);
592 write_gcc_return_type(package, name, rets);
593 printf(" %s_%s(", package, name);
595 write_params(params, &first);
597 for (p = rets; p != NULL; p = p->next)
598 printf(" %s %s;\n", p->type, p->name);
601 /* Write out a gcc function trailer. */
603 write_gcc_func_trailer(char *package, char *name, struct params *rets)
607 else if (rets->next == NULL)
608 printf("return %s;\n", rets->name);
612 printf(" {\n struct %s_%s_ret __ret;\n", package, name);
613 for (p = rets; p != NULL; p = p->next)
614 printf(" __ret.%s = %s;\n", p->name, p->name);
615 printf(" return __ret;\n }\n");
620 /* Write out a function header. */
622 write_func_header(char *package, char *name,
623 struct params *params, int paramwid,
627 write_gcc_func_header(package, name, params, rets);
629 write_6g_func_header(package, name, params, paramwid, rets);
630 printf("#line %d \"%s\"\n", lineno, file);
633 /* Write out a function trailer. */
635 write_func_trailer(char *package, char *name,
639 write_gcc_func_trailer(package, name, rets);
641 write_6g_func_trailer(rets);
645 * Read and write the body of the function, ending in an unnested }
646 * (which is read but not written).
655 c = getchar_no_eof();
656 if (c == '}' && nesting == 0)
669 c = getchar_update_lineno();
673 c = getchar_no_eof();
676 } else if (c == '*') {
678 c = getchar_no_eof();
682 c = getchar_no_eof();
696 c = getchar_no_eof();
699 c = getchar_no_eof();
703 } while (c != delim);
710 /* Process the entire file. */
714 char *package, *name;
715 struct params *params, *rets;
718 package = read_package();
719 read_preprocessor_lines();
720 while (read_func_header(&name, ¶ms, ¶mwid, &rets)) {
721 write_func_header(package, name, params, paramwid, rets);
723 write_func_trailer(package, name, rets);
734 sysfatal("Usage: goc2c [--6g | --gc] [--go-pkgpath PKGPATH] [--go-prefix PREFIX] [file]\n");
738 main(int argc, char **argv)
743 while(argc > 1 && argv[1][0] == '-') {
744 if(strcmp(argv[1], "-") == 0)
746 if(strcmp(argv[1], "--6g") == 0)
748 else if(strcmp(argv[1], "--gcc") == 0)
750 else if (strcmp(argv[1], "--go-pkgpath") == 0 && argc > 2) {
754 } else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
764 if(argc <= 1 || strcmp(argv[1], "-") == 0) {
774 if(freopen(file, "r", stdin) == 0) {
775 sysfatal("open %s: %r\n", file);
779 // 6g etc; update size table
780 goarch = getenv("GOARCH");
781 if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
782 type_table[Uintptr].size = 8;
783 type_table[String].size = 16;
784 type_table[Slice].size = 8+4+4;
785 type_table[Eface].size = 8+8;
790 printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");