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