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 /* Package path to use. */
34 static const char *pkgpath
;
36 /* Package prefix to use. */
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. */
53 sysfatal(char *fmt
, ...)
59 vsnprintf(buf
, sizeof buf
, fmt
, arg
);
62 fprintf(stderr
, "%s: %s\n", argv0
? argv0
: "<prog>", buf
);
70 sysfatal("%s:%ud: unexpected EOF\n", file
, lineno
);
77 sysfatal("%s:%ud: out of memory\n", file
, lineno
);
80 /* Allocate memory without fail. */
82 xmalloc(unsigned int size
)
84 void *ret
= malloc(size
);
90 /* Reallocate memory without fail. */
92 xrealloc(void *buf
, unsigned int size
)
94 void *ret
= realloc(buf
, size
);
100 /* Copy a string into memory without fail. */
102 xstrdup(const char *p
)
104 char *ret
= xmalloc(strlen(p
) + 1);
109 /* Free a list of parameters. */
111 free_params(struct params
*p
)
124 /* Read a character, tracking lineno. */
126 getchar_update_lineno(void)
136 /* Read a character, giving an error on EOF, tracking lineno. */
142 c
= getchar_update_lineno();
148 /* Read a character, skipping comments. */
150 getchar_skipping_comments(void)
155 c
= getchar_update_lineno();
162 c
= getchar_update_lineno();
163 } while (c
!= EOF
&& c
!= '\n');
165 } else if (c
== '*') {
167 c
= getchar_update_lineno();
172 c
= getchar_update_lineno();
186 * Read and return a token. Tokens are string or character literals
187 * or else delimited by whitespace or by [(),{}].
188 * The latter are all returned as single characters.
195 unsigned int alc
, off
;
196 const char* delims
= "(),{}";
199 c
= getchar_skipping_comments();
206 buf
= xmalloc(alc
+ 1);
208 if(c
== '"' || c
== '\'') {
213 if (off
+2 >= alc
) { // room for c and maybe next char
215 buf
= xrealloc(buf
, alc
+ 1);
217 c
= getchar_no_eof();
223 buf
[off
] = getchar_no_eof();
227 } else if (strchr(delims
, c
) != NULL
) {
234 buf
= xrealloc(buf
, alc
+ 1);
238 c
= getchar_skipping_comments();
241 if (isspace(c
) || strchr(delims
, c
) != NULL
) {
253 /* Read a token, giving an error on EOF. */
255 read_token_no_eof(void)
257 char *token
= read_token();
263 /* Read the package clause, and return the package name. */
269 token
= read_token_no_eof();
271 sysfatal("%s:%ud: no token\n", file
, lineno
);
272 if (strcmp(token
, "package") != 0) {
273 sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
274 file
, lineno
, token
);
276 return read_token_no_eof();
279 /* Read and copy preprocessor lines. */
281 read_preprocessor_lines(void)
287 c
= getchar_skipping_comments();
288 } while (isspace(c
));
295 c
= getchar_update_lineno();
302 * Read a type in Go syntax and return a type in C syntax. We only
303 * permit basic types and pointers.
312 p
= read_token_no_eof();
314 /* Convert the Go type "int" to the C type "intgo",
315 and similarly for "uint". */
316 if (strcmp(p
, "int") == 0)
317 return xstrdup("intgo");
318 else if (strcmp(p
, "uint") == 0)
319 return xstrdup("uintgo");
329 /* Convert the Go type "int" to the C type "intgo", and
330 similarly for "uint". */
331 if (strcmp(p
, "int") == 0)
332 p
= (char *) "intgo";
333 else if (strcmp(p
, "uint") == 0)
334 p
= (char *) "uintgo";
337 q
= xmalloc(len
+ pointer_count
+ 1);
339 while (pointer_count
> 0) {
350 * Read a list of parameters. Each parameter is a name and a type.
351 * The list ends with a ')'. We have already read the '('.
353 static struct params
*
357 struct params
*ret
, **pp
, *p
;
361 token
= read_token_no_eof();
362 if (strcmp(token
, ")") != 0) {
364 p
= xmalloc(sizeof(struct params
));
366 p
->type
= read_type();
371 token
= read_token_no_eof();
372 if (strcmp(token
, ",") != 0)
374 token
= read_token_no_eof();
377 if (strcmp(token
, ")") != 0) {
378 sysfatal("%s:%ud: expected '('\n",
385 * Read a function header. This reads up to and including the initial
386 * '{' character. Returns 1 if it read a header, 0 at EOF.
389 read_func_header(char **name
, struct params
**params
, struct params
**rets
)
396 token
= read_token();
399 if (strcmp(token
, "func") == 0) {
404 if (lastline
!= lineno
) {
405 if (lastline
== lineno
-1)
408 printf("\n#line %d \"%s\"\n", lineno
, file
);
411 printf("%s ", token
);
414 *name
= read_token_no_eof();
416 token
= read_token();
417 if (token
== NULL
|| strcmp(token
, "(") != 0) {
418 sysfatal("%s:%ud: expected \"(\"\n",
421 *params
= read_params();
423 token
= read_token();
424 if (token
== NULL
|| strcmp(token
, "(") != 0)
427 *rets
= read_params();
428 token
= read_token();
430 if (token
== NULL
|| strcmp(token
, "{") != 0) {
431 sysfatal("%s:%ud: expected \"{\"\n",
437 /* Write out parameters. */
439 write_params(struct params
*params
, int *first
)
443 for (p
= params
; p
!= NULL
; p
= p
->next
) {
448 printf("%s %s", p
->type
, p
->name
);
452 /* Define the gcc function return type if necessary. */
454 define_gcc_return_type(char *package
, char *name
, struct params
*rets
)
458 if (rets
== NULL
|| rets
->next
== NULL
)
460 printf("struct %s_%s_ret {\n", package
, name
);
461 for (p
= rets
; p
!= NULL
; p
= p
->next
)
462 printf(" %s %s;\n", p
->type
, p
->name
);
466 /* Write out the gcc function return type. */
468 write_gcc_return_type(char *package
, char *name
, struct params
*rets
)
472 else if (rets
->next
== NULL
)
473 printf("%s", rets
->type
);
475 printf("struct %s_%s_ret", package
, name
);
478 /* Write out a gcc function header. */
480 write_gcc_func_header(char *package
, char *name
, struct params
*params
,
486 define_gcc_return_type(package
, name
, rets
);
487 write_gcc_return_type(package
, name
, rets
);
488 printf(" %s_%s(", package
, name
);
490 write_params(params
, &first
);
491 printf(") __asm__ (GOSYM_PREFIX \"");
493 printf("%s", pkgpath
);
494 else if (prefix
!= NULL
)
495 printf("%s.%s", prefix
, package
);
497 printf("%s", package
);
498 printf(".%s\");\n", name
);
499 write_gcc_return_type(package
, name
, rets
);
500 printf(" %s_%s(", package
, name
);
502 write_params(params
, &first
);
504 for (p
= rets
; p
!= NULL
; p
= p
->next
)
505 printf(" %s %s;\n", p
->type
, p
->name
);
508 /* Write out a gcc function trailer. */
510 write_gcc_func_trailer(char *package
, char *name
, struct params
*rets
)
514 else if (rets
->next
== NULL
)
515 printf("return %s;\n", rets
->name
);
519 printf(" {\n struct %s_%s_ret __ret;\n", package
, name
);
520 for (p
= rets
; p
!= NULL
; p
= p
->next
)
521 printf(" __ret.%s = %s;\n", p
->name
, p
->name
);
522 printf(" return __ret;\n }\n");
527 /* Write out a function header. */
529 write_func_header(char *package
, char *name
, struct params
*params
,
532 write_gcc_func_header(package
, name
, params
, rets
);
533 printf("#line %d \"%s\"\n", lineno
, file
);
536 /* Write out a function trailer. */
538 write_func_trailer(char *package
, char *name
,
541 write_gcc_func_trailer(package
, name
, rets
);
545 * Read and write the body of the function, ending in an unnested }
546 * (which is read but not written).
555 c
= getchar_no_eof();
556 if (c
== '}' && nesting
== 0)
569 c
= getchar_update_lineno();
573 c
= getchar_no_eof();
576 } else if (c
== '*') {
578 c
= getchar_no_eof();
582 c
= getchar_no_eof();
596 c
= getchar_no_eof();
599 c
= getchar_no_eof();
603 } while (c
!= delim
);
610 /* Process the entire file. */
614 char *package
, *name
;
615 struct params
*params
, *rets
;
617 package
= read_package();
618 read_preprocessor_lines();
619 while (read_func_header(&name
, ¶ms
, &rets
)) {
620 write_func_header(package
, name
, params
, rets
);
622 write_func_trailer(package
, name
, rets
);
633 sysfatal("Usage: goc2c [--go-pkgpath PKGPATH] [--go-prefix PREFIX] [file]\n");
637 main(int argc
, char **argv
)
642 while(argc
> 1 && argv
[1][0] == '-') {
643 if(strcmp(argv
[1], "-") == 0)
645 if (strcmp(argv
[1], "--go-pkgpath") == 0 && argc
> 2) {
649 } else if (strcmp(argv
[1], "--go-prefix") == 0 && argc
> 2) {
659 if(argc
<= 1 || strcmp(argv
[1], "-") == 0) {
669 if(freopen(file
, "r", stdin
) == 0) {
670 sysfatal("open %s: %r\n", file
);
673 printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");