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.
5 /* Translate a .goc file into a .c file. A .goc file is a combination
6 of a limited form of Go with C. */
11 func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
12 C code with proper brace nesting
16 /* We generate C code which implements the function such that it can
17 be called from Go and executes the C code. */
26 /* Whether we're emitting for gcc */
29 /* Package prefix to use; only meaningful for gcc */
30 static const char *prefix;
32 /* File and line number */
33 static const char *file;
34 static unsigned int lineno = 1;
36 /* List of names and types. */
43 /* index into type_table */
59 /* variable sized first, for easy replacement */
60 /* order matches enum above */
61 /* default is 32-bit architecture sizes */
87 /* Fixed structure alignment (non-gcc only) */
94 fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno);
102 fprintf(stderr, "%s:%u: out of memory\n", file, lineno);
106 /* Allocate memory without fail. */
108 xmalloc(unsigned int size)
110 void *ret = malloc(size);
116 /* Reallocate memory without fail. */
118 xrealloc(void *buf, unsigned int size)
120 void *ret = realloc(buf, size);
126 /* Free a list of parameters. */
128 free_params(struct params *p)
141 /* Read a character, tracking lineno. */
143 getchar_update_lineno(void)
153 /* Read a character, giving an error on EOF, tracking lineno. */
159 c = getchar_update_lineno();
165 /* Read a character, skipping comments. */
167 getchar_skipping_comments(void)
172 c = getchar_update_lineno();
179 c = getchar_update_lineno();
180 } while (c != EOF && c != '\n');
182 } else if (c == '*') {
184 c = getchar_update_lineno();
189 c = getchar_update_lineno();
202 /* Read and return a token. Tokens are delimited by whitespace or by
203 [(),{}]. The latter are all returned as single characters. */
209 unsigned int alc, off;
210 const char* delims = "(),{}";
213 c = getchar_skipping_comments();
220 buf = xmalloc(alc + 1);
222 if (strchr(delims, c) != NULL) {
229 buf = xrealloc(buf, alc + 1);
233 c = getchar_skipping_comments();
236 if (isspace(c) || strchr(delims, c) != NULL) {
248 /* Read a token, giving an error on EOF. */
250 read_token_no_eof(void)
252 char *token = read_token();
258 /* Read the package clause, and return the package name. */
264 token = read_token_no_eof();
265 if (strcmp(token, "package") != 0) {
267 "%s:%u: expected \"package\", got \"%s\"\n",
268 file, lineno, token);
271 return read_token_no_eof();
274 /* Read and copy preprocessor lines. */
276 read_preprocessor_lines(void)
282 c = getchar_skipping_comments();
283 } while (isspace(c));
290 c = getchar_update_lineno();
296 /* Read a type in Go syntax and return a type in C syntax. We only
297 permit basic types and pointers. */
305 p = read_token_no_eof();
315 q = xmalloc(len + pointer_count + 1);
317 while (pointer_count > 0) {
327 /* Return the size of the given type. */
333 if(p[strlen(p)-1] == '*')
334 return type_table[Uintptr].size;
336 for(i=0; type_table[i].name; i++)
337 if(strcmp(type_table[i].name, p) == 0)
338 return type_table[i].size;
340 fprintf(stderr, "%s:%u: unknown type %s\n", file, lineno, p);
346 /* Read a list of parameters. Each parameter is a name and a type.
347 The list ends with a ')'. We have already read the '('. */
348 static struct params *
349 read_params(int *poffset)
352 struct params *ret, **pp, *p;
353 int offset, size, rnd;
357 token = read_token_no_eof();
359 if (strcmp(token, ")") != 0) {
361 p = xmalloc(sizeof(struct params));
363 p->type = read_type();
368 size = type_size(p->type);
370 if(rnd > structround)
373 offset += rnd - offset%rnd;
376 token = read_token_no_eof();
377 if (strcmp(token, ",") != 0)
379 token = read_token_no_eof();
382 if (strcmp(token, ")") != 0) {
383 fprintf(stderr, "%s:%u: expected '('\n",
392 /* Read a function header. This reads up to and including the initial
393 '{' character. Returns 1 if it read a header, 0 at EOF. */
395 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
402 token = read_token();
405 if (strcmp(token, "func") == 0) {
410 if (lastline != lineno) {
411 if (lastline == lineno-1)
414 printf("\n#line %d \"%s\"\n", lineno, file);
417 printf("%s ", token);
420 *name = read_token_no_eof();
422 token = read_token();
423 if (token == NULL || strcmp(token, "(") != 0) {
424 fprintf(stderr, "%s:%u: expected \"(\"\n",
428 *params = read_params(paramwid);
430 token = read_token();
431 if (token == NULL || strcmp(token, "(") != 0)
434 *rets = read_params(NULL);
435 token = read_token();
437 if (token == NULL || strcmp(token, "{") != 0) {
438 fprintf(stderr, "%s:%u: expected \"{\"\n",
445 /* Write out parameters. */
447 write_params(struct params *params, int *first)
451 for (p = params; p != NULL; p = p->next) {
456 printf("%s %s", p->type, p->name);
460 /* Write a 6g function header. */
462 write_6g_func_header(char *package, char *name, struct params *params,
463 int paramwid, struct params *rets)
467 printf("void\n%s·%s(", package, name);
469 write_params(params, &first);
471 /* insert padding to align output struct */
472 if(rets != NULL && paramwid%structround != 0) {
473 n = structround - paramwid%structround;
482 write_params(rets, &first);
486 /* Write a 6g function trailer. */
488 write_6g_func_trailer(struct params *rets)
492 for (p = rets; p != NULL; p = p->next)
493 printf("\tFLUSH(&%s);\n", p->name);
497 /* Define the gcc function return type if necessary. */
499 define_gcc_return_type(char *package, char *name, struct params *rets)
503 if (rets == NULL || rets->next == NULL)
505 printf("struct %s_%s_ret {\n", package, name);
506 for (p = rets; p != NULL; p = p->next)
507 printf(" %s %s;\n", p->type, p->name);
511 /* Write out the gcc function return type. */
513 write_gcc_return_type(char *package, char *name, struct params *rets)
517 else if (rets->next == NULL)
518 printf("%s", rets->type);
520 printf("struct %s_%s_ret", package, name);
523 /* Write out a gcc function header. */
525 write_gcc_func_header(char *package, char *name, struct params *params,
531 define_gcc_return_type(package, name, rets);
532 write_gcc_return_type(package, name, rets);
533 printf(" %s_%s(", package, name);
535 write_params(params, &first);
538 printf("%s.", prefix);
539 printf("%s.%s\");\n", package, name);
540 write_gcc_return_type(package, name, rets);
541 printf(" %s_%s(", package, name);
543 write_params(params, &first);
545 for (p = rets; p != NULL; p = p->next)
546 printf(" %s %s;\n", p->type, p->name);
549 /* Write out a gcc function trailer. */
551 write_gcc_func_trailer(char *package, char *name, struct params *rets)
555 else if (rets->next == NULL)
556 printf("return %s;\n", rets->name);
560 printf(" {\n struct %s_%s_ret __ret;\n", package, name);
561 for (p = rets; p != NULL; p = p->next)
562 printf(" __ret.%s = %s;\n", p->name, p->name);
563 printf(" return __ret;\n }\n");
568 /* Write out a function header. */
570 write_func_header(char *package, char *name,
571 struct params *params, int paramwid,
575 write_gcc_func_header(package, name, params, rets);
577 write_6g_func_header(package, name, params, paramwid, rets);
578 printf("#line %d \"%s\"\n", lineno, file);
581 /* Write out a function trailer. */
583 write_func_trailer(char *package, char *name,
587 write_gcc_func_trailer(package, name, rets);
589 write_6g_func_trailer(rets);
592 /* Read and write the body of the function, ending in an unnested }
593 (which is read but not written). */
601 c = getchar_no_eof();
602 if (c == '}' && nesting == 0)
615 c = getchar_update_lineno();
619 c = getchar_no_eof();
622 } else if (c == '*') {
624 c = getchar_no_eof();
628 c = getchar_no_eof();
642 c = getchar_no_eof();
645 c = getchar_no_eof();
649 } while (c != delim);
656 /* Process the entire file. */
660 char *package, *name;
661 struct params *params, *rets;
664 package = read_package();
665 read_preprocessor_lines();
666 while (read_func_header(&name, ¶ms, ¶mwid, &rets)) {
667 write_func_header(package, name, params, paramwid, rets);
669 write_func_trailer(package, name, rets);
680 fprintf(stderr, "Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
685 main(int argc, char **argv)
689 while(argc > 1 && argv[1][0] == '-') {
690 if(strcmp(argv[1], "-") == 0)
692 if(strcmp(argv[1], "--6g") == 0)
694 else if(strcmp(argv[1], "--gcc") == 0)
696 else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
706 if(argc <= 1 || strcmp(argv[1], "-") == 0) {
716 if(freopen(file, "r", stdin) == 0) {
717 fprintf(stderr, "open %s: %s\n", file, strerror(errno));
722 // 6g etc; update size table
723 goarch = getenv("GOARCH");
724 if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
725 type_table[Uintptr].size = 8;
726 type_table[String].size = 16;
727 type_table[Slice].size = 8+4+4;
728 type_table[Eface].size = 8+8;