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");