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