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 prefix to use; only meaningful for gcc */
37 static const char *prefix;
39 /* File and line number */
40 static const char *file;
41 static unsigned int lineno = 1;
43 /* List of names and types. */
50 /* index into type_table */
66 /* variable sized first, for easy replacement */
67 /* order matches enum above */
68 /* default is 32-bit architecture sizes */
94 /* Fixed structure alignment (non-gcc only) */
100 sysfatal(char *fmt, ...)
106 vsnprintf(buf, sizeof buf, fmt, arg);
109 fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
113 /* Unexpected EOF. */
117 sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
124 sysfatal("%s:%ud: out of memory\n", file, lineno);
127 /* Allocate memory without fail. */
129 xmalloc(unsigned int size)
131 void *ret = malloc(size);
137 /* Reallocate memory without fail. */
139 xrealloc(void *buf, unsigned int size)
141 void *ret = realloc(buf, size);
147 /* Free a list of parameters. */
149 free_params(struct params *p)
162 /* Read a character, tracking lineno. */
164 getchar_update_lineno(void)
174 /* Read a character, giving an error on EOF, tracking lineno. */
180 c = getchar_update_lineno();
186 /* Read a character, skipping comments. */
188 getchar_skipping_comments(void)
193 c = getchar_update_lineno();
200 c = getchar_update_lineno();
201 } while (c != EOF && c != '\n');
203 } else if (c == '*') {
205 c = getchar_update_lineno();
210 c = getchar_update_lineno();
224 * Read and return a token. Tokens are string or character literals
225 * or else delimited by whitespace or by [(),{}].
226 * The latter are all returned as single characters.
233 unsigned int alc, off;
234 const char* delims = "(),{}";
237 c = getchar_skipping_comments();
244 buf = xmalloc(alc + 1);
246 if(c == '"' || c == '\'') {
251 if (off+2 >= alc) { // room for c and maybe next char
253 buf = xrealloc(buf, alc + 1);
255 c = getchar_no_eof();
261 buf[off] = getchar_no_eof();
265 } else if (strchr(delims, c) != NULL) {
272 buf = xrealloc(buf, alc + 1);
276 c = getchar_skipping_comments();
279 if (isspace(c) || strchr(delims, c) != NULL) {
291 /* Read a token, giving an error on EOF. */
293 read_token_no_eof(void)
295 char *token = read_token();
301 /* Read the package clause, and return the package name. */
307 token = read_token_no_eof();
309 sysfatal("%s:%ud: no token\n", file, lineno);
310 if (strcmp(token, "package") != 0) {
311 sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
312 file, lineno, token);
314 return read_token_no_eof();
317 /* Read and copy preprocessor lines. */
319 read_preprocessor_lines(void)
325 c = getchar_skipping_comments();
326 } while (isspace(c));
333 c = getchar_update_lineno();
340 * Read a type in Go syntax and return a type in C syntax. We only
341 * permit basic types and pointers.
350 p = read_token_no_eof();
360 q = xmalloc(len + pointer_count + 1);
362 while (pointer_count > 0) {
372 /* Return the size of the given type. */
378 if(p[strlen(p)-1] == '*')
379 return type_table[Uintptr].size;
381 for(i=0; type_table[i].name; i++)
382 if(strcmp(type_table[i].name, p) == 0)
383 return type_table[i].size;
385 sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
391 * Read a list of parameters. Each parameter is a name and a type.
392 * The list ends with a ')'. We have already read the '('.
394 static struct params *
395 read_params(int *poffset)
398 struct params *ret, **pp, *p;
399 int offset, size, rnd;
403 token = read_token_no_eof();
405 if (strcmp(token, ")") != 0) {
407 p = xmalloc(sizeof(struct params));
409 p->type = read_type();
414 size = type_size(p->type);
416 if(rnd > structround)
419 offset += rnd - offset%rnd;
422 token = read_token_no_eof();
423 if (strcmp(token, ",") != 0)
425 token = read_token_no_eof();
428 if (strcmp(token, ")") != 0) {
429 sysfatal("%s:%ud: expected '('\n",
438 * Read a function header. This reads up to and including the initial
439 * '{' character. Returns 1 if it read a header, 0 at EOF.
442 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
449 token = read_token();
452 if (strcmp(token, "func") == 0) {
457 if (lastline != lineno) {
458 if (lastline == lineno-1)
461 printf("\n#line %d \"%s\"\n", lineno, file);
464 printf("%s ", token);
467 *name = read_token_no_eof();
469 token = read_token();
470 if (token == NULL || strcmp(token, "(") != 0) {
471 sysfatal("%s:%ud: expected \"(\"\n",
474 *params = read_params(paramwid);
476 token = read_token();
477 if (token == NULL || strcmp(token, "(") != 0)
480 *rets = read_params(NULL);
481 token = read_token();
483 if (token == NULL || strcmp(token, "{") != 0) {
484 sysfatal("%s:%ud: expected \"{\"\n",
490 /* Write out parameters. */
492 write_params(struct params *params, int *first)
496 for (p = params; p != NULL; p = p->next) {
501 printf("%s %s", p->type, p->name);
505 /* Write a 6g function header. */
507 write_6g_func_header(char *package, char *name, struct params *params,
508 int paramwid, struct params *rets)
512 printf("void\n%s·%s(", package, name);
514 write_params(params, &first);
516 /* insert padding to align output struct */
517 if(rets != NULL && paramwid%structround != 0) {
518 n = structround - paramwid%structround;
527 write_params(rets, &first);
531 /* Write a 6g function trailer. */
533 write_6g_func_trailer(struct params *rets)
537 for (p = rets; p != NULL; p = p->next)
538 printf("\tFLUSH(&%s);\n", p->name);
542 /* Define the gcc function return type if necessary. */
544 define_gcc_return_type(char *package, char *name, struct params *rets)
548 if (rets == NULL || rets->next == NULL)
550 printf("struct %s_%s_ret {\n", package, name);
551 for (p = rets; p != NULL; p = p->next)
552 printf(" %s %s;\n", p->type, p->name);
556 /* Write out the gcc function return type. */
558 write_gcc_return_type(char *package, char *name, struct params *rets)
562 else if (rets->next == NULL)
563 printf("%s", rets->type);
565 printf("struct %s_%s_ret", package, name);
568 /* Write out a gcc function header. */
570 write_gcc_func_header(char *package, char *name, struct params *params,
576 define_gcc_return_type(package, name, rets);
577 write_gcc_return_type(package, name, rets);
578 printf(" %s_%s(", package, name);
580 write_params(params, &first);
583 printf("%s.", prefix);
584 printf("%s.%s\");\n", package, name);
585 write_gcc_return_type(package, name, rets);
586 printf(" %s_%s(", package, name);
588 write_params(params, &first);
590 for (p = rets; p != NULL; p = p->next)
591 printf(" %s %s;\n", p->type, p->name);
594 /* Write out a gcc function trailer. */
596 write_gcc_func_trailer(char *package, char *name, struct params *rets)
600 else if (rets->next == NULL)
601 printf("return %s;\n", rets->name);
605 printf(" {\n struct %s_%s_ret __ret;\n", package, name);
606 for (p = rets; p != NULL; p = p->next)
607 printf(" __ret.%s = %s;\n", p->name, p->name);
608 printf(" return __ret;\n }\n");
613 /* Write out a function header. */
615 write_func_header(char *package, char *name,
616 struct params *params, int paramwid,
620 write_gcc_func_header(package, name, params, rets);
622 write_6g_func_header(package, name, params, paramwid, rets);
623 printf("#line %d \"%s\"\n", lineno, file);
626 /* Write out a function trailer. */
628 write_func_trailer(char *package, char *name,
632 write_gcc_func_trailer(package, name, rets);
634 write_6g_func_trailer(rets);
638 * Read and write the body of the function, ending in an unnested }
639 * (which is read but not written).
648 c = getchar_no_eof();
649 if (c == '}' && nesting == 0)
662 c = getchar_update_lineno();
666 c = getchar_no_eof();
669 } else if (c == '*') {
671 c = getchar_no_eof();
675 c = getchar_no_eof();
689 c = getchar_no_eof();
692 c = getchar_no_eof();
696 } while (c != delim);
703 /* Process the entire file. */
707 char *package, *name;
708 struct params *params, *rets;
711 package = read_package();
712 read_preprocessor_lines();
713 while (read_func_header(&name, ¶ms, ¶mwid, &rets)) {
714 write_func_header(package, name, params, paramwid, rets);
716 write_func_trailer(package, name, rets);
727 sysfatal("Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
731 main(int argc, char **argv)
736 while(argc > 1 && argv[1][0] == '-') {
737 if(strcmp(argv[1], "-") == 0)
739 if(strcmp(argv[1], "--6g") == 0)
741 else if(strcmp(argv[1], "--gcc") == 0)
743 else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
753 if(argc <= 1 || strcmp(argv[1], "-") == 0) {
763 if(freopen(file, "r", stdin) == 0) {
764 sysfatal("open %s: %r\n", file);
768 // 6g etc; update size table
769 goarch = getenv("GOARCH");
770 if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
771 type_table[Uintptr].size = 8;
772 type_table[String].size = 16;
773 type_table[Slice].size = 8+4+4;
774 type_table[Eface].size = 8+8;
779 printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");