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.
6 * Translate a .goc file into a .c file. A .goc file is a combination
7 * of a limited form of Go with C.
13 func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
14 C code with proper brace nesting
19 * We generate C code which implements the function such that it can
20 * be called from Go and executes the C code.
31 /* Whether we're emitting for gcc */
34 /* Package prefix to use; only meaningful for gcc */
35 static const char *prefix
;
37 /* File and line number */
38 static const char *file
;
39 static unsigned int lineno
= 1;
41 /* List of names and types. */
48 /* index into type_table */
64 /* variable sized first, for easy replacement */
65 /* order matches enum above */
66 /* default is 32-bit architecture sizes */
92 /* Fixed structure alignment (non-gcc only) */
98 sysfatal(char *fmt
, ...)
104 vsnprintf(buf
, sizeof buf
, fmt
, arg
);
107 fprintf(stderr
, "%s: %s\n", argv0
? argv0
: "<prog>", buf
);
111 /* Unexpected EOF. */
115 sysfatal("%s:%ud: unexpected EOF\n", file
, lineno
);
122 sysfatal("%s:%ud: out of memory\n", file
, lineno
);
125 /* Allocate memory without fail. */
127 xmalloc(unsigned int size
)
129 void *ret
= malloc(size
);
135 /* Reallocate memory without fail. */
137 xrealloc(void *buf
, unsigned int size
)
139 void *ret
= realloc(buf
, size
);
145 /* Free a list of parameters. */
147 free_params(struct params
*p
)
160 /* Read a character, tracking lineno. */
162 getchar_update_lineno(void)
172 /* Read a character, giving an error on EOF, tracking lineno. */
178 c
= getchar_update_lineno();
184 /* Read a character, skipping comments. */
186 getchar_skipping_comments(void)
191 c
= getchar_update_lineno();
198 c
= getchar_update_lineno();
199 } while (c
!= EOF
&& c
!= '\n');
201 } else if (c
== '*') {
203 c
= getchar_update_lineno();
208 c
= getchar_update_lineno();
222 * Read and return a token. Tokens are string or character literals
223 * or else delimited by whitespace or by [(),{}].
224 * The latter are all returned as single characters.
231 unsigned int alc
, off
;
232 const char* delims
= "(),{}";
235 c
= getchar_skipping_comments();
242 buf
= xmalloc(alc
+ 1);
244 if(c
== '"' || c
== '\'') {
249 if (off
+2 >= alc
) { // room for c and maybe next char
251 buf
= xrealloc(buf
, alc
+ 1);
253 c
= getchar_no_eof();
259 buf
[off
] = getchar_no_eof();
263 } else if (strchr(delims
, c
) != NULL
) {
270 buf
= xrealloc(buf
, alc
+ 1);
274 c
= getchar_skipping_comments();
277 if (isspace(c
) || strchr(delims
, c
) != NULL
) {
289 /* Read a token, giving an error on EOF. */
291 read_token_no_eof(void)
293 char *token
= read_token();
299 /* Read the package clause, and return the package name. */
305 token
= read_token_no_eof();
307 sysfatal("%s:%ud: no token\n", file
, lineno
);
308 if (strcmp(token
, "package") != 0) {
309 sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
310 file
, lineno
, token
);
312 return read_token_no_eof();
315 /* Read and copy preprocessor lines. */
317 read_preprocessor_lines(void)
323 c
= getchar_skipping_comments();
324 } while (isspace(c
));
331 c
= getchar_update_lineno();
338 * Read a type in Go syntax and return a type in C syntax. We only
339 * permit basic types and pointers.
348 p
= read_token_no_eof();
358 q
= xmalloc(len
+ pointer_count
+ 1);
360 while (pointer_count
> 0) {
370 /* Return the size of the given type. */
376 if(p
[strlen(p
)-1] == '*')
377 return type_table
[Uintptr
].size
;
379 for(i
=0; type_table
[i
].name
; i
++)
380 if(strcmp(type_table
[i
].name
, p
) == 0)
381 return type_table
[i
].size
;
383 sysfatal("%s:%ud: unknown type %s\n", file
, lineno
, p
);
389 * Read a list of parameters. Each parameter is a name and a type.
390 * The list ends with a ')'. We have already read the '('.
392 static struct params
*
393 read_params(int *poffset
)
396 struct params
*ret
, **pp
, *p
;
397 int offset
, size
, rnd
;
401 token
= read_token_no_eof();
403 if (strcmp(token
, ")") != 0) {
405 p
= xmalloc(sizeof(struct params
));
407 p
->type
= read_type();
412 size
= type_size(p
->type
);
414 if(rnd
> structround
)
417 offset
+= rnd
- offset
%rnd
;
420 token
= read_token_no_eof();
421 if (strcmp(token
, ",") != 0)
423 token
= read_token_no_eof();
426 if (strcmp(token
, ")") != 0) {
427 sysfatal("%s:%ud: expected '('\n",
436 * Read a function header. This reads up to and including the initial
437 * '{' character. Returns 1 if it read a header, 0 at EOF.
440 read_func_header(char **name
, struct params
**params
, int *paramwid
, struct params
**rets
)
447 token
= read_token();
450 if (strcmp(token
, "func") == 0) {
455 if (lastline
!= lineno
) {
456 if (lastline
== lineno
-1)
459 printf("\n#line %d \"%s\"\n", lineno
, file
);
462 printf("%s ", token
);
465 *name
= read_token_no_eof();
467 token
= read_token();
468 if (token
== NULL
|| strcmp(token
, "(") != 0) {
469 sysfatal("%s:%ud: expected \"(\"\n",
472 *params
= read_params(paramwid
);
474 token
= read_token();
475 if (token
== NULL
|| strcmp(token
, "(") != 0)
478 *rets
= read_params(NULL
);
479 token
= read_token();
481 if (token
== NULL
|| strcmp(token
, "{") != 0) {
482 sysfatal("%s:%ud: expected \"{\"\n",
488 /* Write out parameters. */
490 write_params(struct params
*params
, int *first
)
494 for (p
= params
; p
!= NULL
; p
= p
->next
) {
499 printf("%s %s", p
->type
, p
->name
);
503 /* Write a 6g function header. */
505 write_6g_func_header(char *package
, char *name
, struct params
*params
,
506 int paramwid
, struct params
*rets
)
510 printf("void\n%s·%s(", package
, name
);
512 write_params(params
, &first
);
514 /* insert padding to align output struct */
515 if(rets
!= NULL
&& paramwid
%structround
!= 0) {
516 n
= structround
- paramwid
%structround
;
525 write_params(rets
, &first
);
529 /* Write a 6g function trailer. */
531 write_6g_func_trailer(struct params
*rets
)
535 for (p
= rets
; p
!= NULL
; p
= p
->next
)
536 printf("\tFLUSH(&%s);\n", p
->name
);
540 /* Define the gcc function return type if necessary. */
542 define_gcc_return_type(char *package
, char *name
, struct params
*rets
)
546 if (rets
== NULL
|| rets
->next
== NULL
)
548 printf("struct %s_%s_ret {\n", package
, name
);
549 for (p
= rets
; p
!= NULL
; p
= p
->next
)
550 printf(" %s %s;\n", p
->type
, p
->name
);
554 /* Write out the gcc function return type. */
556 write_gcc_return_type(char *package
, char *name
, struct params
*rets
)
560 else if (rets
->next
== NULL
)
561 printf("%s", rets
->type
);
563 printf("struct %s_%s_ret", package
, name
);
566 /* Write out a gcc function header. */
568 write_gcc_func_header(char *package
, char *name
, struct params
*params
,
574 define_gcc_return_type(package
, name
, rets
);
575 write_gcc_return_type(package
, name
, rets
);
576 printf(" %s_%s(", package
, name
);
578 write_params(params
, &first
);
581 printf("%s.", prefix
);
582 printf("%s.%s\");\n", package
, name
);
583 write_gcc_return_type(package
, name
, rets
);
584 printf(" %s_%s(", package
, name
);
586 write_params(params
, &first
);
588 for (p
= rets
; p
!= NULL
; p
= p
->next
)
589 printf(" %s %s;\n", p
->type
, p
->name
);
592 /* Write out a gcc function trailer. */
594 write_gcc_func_trailer(char *package
, char *name
, struct params
*rets
)
598 else if (rets
->next
== NULL
)
599 printf("return %s;\n", rets
->name
);
603 printf(" {\n struct %s_%s_ret __ret;\n", package
, name
);
604 for (p
= rets
; p
!= NULL
; p
= p
->next
)
605 printf(" __ret.%s = %s;\n", p
->name
, p
->name
);
606 printf(" return __ret;\n }\n");
611 /* Write out a function header. */
613 write_func_header(char *package
, char *name
,
614 struct params
*params
, int paramwid
,
618 write_gcc_func_header(package
, name
, params
, rets
);
620 write_6g_func_header(package
, name
, params
, paramwid
, rets
);
621 printf("#line %d \"%s\"\n", lineno
, file
);
624 /* Write out a function trailer. */
626 write_func_trailer(char *package
, char *name
,
630 write_gcc_func_trailer(package
, name
, rets
);
632 write_6g_func_trailer(rets
);
636 * Read and write the body of the function, ending in an unnested }
637 * (which is read but not written).
646 c
= getchar_no_eof();
647 if (c
== '}' && nesting
== 0)
660 c
= getchar_update_lineno();
664 c
= getchar_no_eof();
667 } else if (c
== '*') {
669 c
= getchar_no_eof();
673 c
= getchar_no_eof();
687 c
= getchar_no_eof();
690 c
= getchar_no_eof();
694 } while (c
!= delim
);
701 /* Process the entire file. */
705 char *package
, *name
;
706 struct params
*params
, *rets
;
709 package
= read_package();
710 read_preprocessor_lines();
711 while (read_func_header(&name
, ¶ms
, ¶mwid
, &rets
)) {
712 write_func_header(package
, name
, params
, paramwid
, rets
);
714 write_func_trailer(package
, name
, rets
);
725 sysfatal("Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
729 main(int argc
, char **argv
)
734 while(argc
> 1 && argv
[1][0] == '-') {
735 if(strcmp(argv
[1], "-") == 0)
737 if(strcmp(argv
[1], "--6g") == 0)
739 else if(strcmp(argv
[1], "--gcc") == 0)
741 else if (strcmp(argv
[1], "--go-prefix") == 0 && argc
> 2) {
751 if(argc
<= 1 || strcmp(argv
[1], "-") == 0) {
761 if(freopen(file
, "r", stdin
) == 0) {
762 sysfatal("open %s: %r\n", file
);
766 // 6g etc; update size table
767 goarch
= getenv("GOARCH");
768 if(goarch
!= NULL
&& strcmp(goarch
, "amd64") == 0) {
769 type_table
[Uintptr
].size
= 8;
770 type_table
[String
].size
= 16;
771 type_table
[Slice
].size
= 8+4+4;
772 type_table
[Eface
].size
= 8+8;