123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // +build ignore
- /*
- * Translate a .goc file into a .c file. A .goc file is a combination
- * of a limited form of Go with C.
- */
- /*
- package PACKAGENAME
- {# line}
- func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
- C code with proper brace nesting
- \}
- */
- /*
- * We generate C code which implements the function such that it can
- * be called from Go and executes the C code.
- */
- #include <assert.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- /* Package path to use. */
- static const char *pkgpath;
- /* Package prefix to use. */
- static const char *prefix;
- /* File and line number */
- static const char *file;
- static unsigned int lineno = 1;
- /* List of names and types. */
- struct params {
- struct params *next;
- char *name;
- char *type;
- };
- char *argv0;
- static void
- sysfatal(char *fmt, ...)
- {
- char buf[256];
- va_list arg;
- va_start(arg, fmt);
- vsnprintf(buf, sizeof buf, fmt, arg);
- va_end(arg);
- fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
- exit(1);
- }
- /* Unexpected EOF. */
- static void
- bad_eof(void)
- {
- sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
- }
- /* Out of memory. */
- static void
- bad_mem(void)
- {
- sysfatal("%s:%ud: out of memory\n", file, lineno);
- }
- /* Allocate memory without fail. */
- static void *
- xmalloc(unsigned int size)
- {
- void *ret = malloc(size);
- if (ret == NULL)
- bad_mem();
- return ret;
- }
- /* Reallocate memory without fail. */
- static void*
- xrealloc(void *buf, unsigned int size)
- {
- void *ret = realloc(buf, size);
- if (ret == NULL)
- bad_mem();
- return ret;
- }
- /* Copy a string into memory without fail. */
- static char *
- xstrdup(const char *p)
- {
- char *ret = xmalloc(strlen(p) + 1);
- strcpy(ret, p);
- return ret;
- }
- /* Free a list of parameters. */
- static void
- free_params(struct params *p)
- {
- while (p != NULL) {
- struct params *next;
- next = p->next;
- free(p->name);
- free(p->type);
- free(p);
- p = next;
- }
- }
- /* Read a character, tracking lineno. */
- static int
- getchar_update_lineno(void)
- {
- int c;
- c = getchar();
- if (c == '\n')
- ++lineno;
- return c;
- }
- /* Read a character, giving an error on EOF, tracking lineno. */
- static int
- getchar_no_eof(void)
- {
- int c;
- c = getchar_update_lineno();
- if (c == EOF)
- bad_eof();
- return c;
- }
- /* Read a character, skipping comments. */
- static int
- getchar_skipping_comments(void)
- {
- int c;
- while (1) {
- c = getchar_update_lineno();
- if (c != '/')
- return c;
- c = getchar();
- if (c == '/') {
- do {
- c = getchar_update_lineno();
- } while (c != EOF && c != '\n');
- return c;
- } else if (c == '*') {
- while (1) {
- c = getchar_update_lineno();
- if (c == EOF)
- return EOF;
- if (c == '*') {
- do {
- c = getchar_update_lineno();
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- } else {
- ungetc(c, stdin);
- return '/';
- }
- }
- }
- /*
- * Read and return a token. Tokens are string or character literals
- * or else delimited by whitespace or by [(),{}].
- * The latter are all returned as single characters.
- */
- static char *
- read_token(void)
- {
- int c, q;
- char *buf;
- unsigned int alc, off;
- const char* delims = "(),{}";
- while (1) {
- c = getchar_skipping_comments();
- if (c == EOF)
- return NULL;
- if (!isspace(c))
- break;
- }
- alc = 16;
- buf = xmalloc(alc + 1);
- off = 0;
- if(c == '"' || c == '\'') {
- q = c;
- buf[off] = c;
- ++off;
- while (1) {
- if (off+2 >= alc) { // room for c and maybe next char
- alc *= 2;
- buf = xrealloc(buf, alc + 1);
- }
- c = getchar_no_eof();
- buf[off] = c;
- ++off;
- if(c == q)
- break;
- if(c == '\\') {
- buf[off] = getchar_no_eof();
- ++off;
- }
- }
- } else if (strchr(delims, c) != NULL) {
- buf[off] = c;
- ++off;
- } else {
- while (1) {
- if (off >= alc) {
- alc *= 2;
- buf = xrealloc(buf, alc + 1);
- }
- buf[off] = c;
- ++off;
- c = getchar_skipping_comments();
- if (c == EOF)
- break;
- if (isspace(c) || strchr(delims, c) != NULL) {
- if (c == '\n')
- lineno--;
- ungetc(c, stdin);
- break;
- }
- }
- }
- buf[off] = '\0';
- return buf;
- }
- /* Read a token, giving an error on EOF. */
- static char *
- read_token_no_eof(void)
- {
- char *token = read_token();
- if (token == NULL)
- bad_eof();
- return token;
- }
- /* Read the package clause, and return the package name. */
- static char *
- read_package(void)
- {
- char *token;
- token = read_token_no_eof();
- if (token == NULL)
- sysfatal("%s:%ud: no token\n", file, lineno);
- if (strcmp(token, "package") != 0) {
- sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
- file, lineno, token);
- }
- return read_token_no_eof();
- }
- /* Read and copy preprocessor lines. */
- static void
- read_preprocessor_lines(void)
- {
- while (1) {
- int c;
- do {
- c = getchar_skipping_comments();
- } while (isspace(c));
- if (c != '#') {
- ungetc(c, stdin);
- break;
- }
- putchar(c);
- do {
- c = getchar_update_lineno();
- putchar(c);
- } while (c != '\n');
- }
- }
- /*
- * Read a type in Go syntax and return a type in C syntax. We only
- * permit basic types and pointers.
- */
- static char *
- read_type(void)
- {
- char *p, *op, *q;
- int pointer_count;
- unsigned int len;
- p = read_token_no_eof();
- if (*p != '*') {
- /* Convert the Go type "int" to the C type "intgo",
- and similarly for "uint". */
- if (strcmp(p, "int") == 0)
- return xstrdup("intgo");
- else if (strcmp(p, "uint") == 0)
- return xstrdup("uintgo");
- return p;
- }
- op = p;
- pointer_count = 0;
- while (*p == '*') {
- ++pointer_count;
- ++p;
- }
- /* Convert the Go type "int" to the C type "intgo", and
- similarly for "uint". */
- if (strcmp(p, "int") == 0)
- p = (char *) "intgo";
- else if (strcmp(p, "uint") == 0)
- p = (char *) "uintgo";
- len = strlen(p);
- q = xmalloc(len + pointer_count + 1);
- memcpy(q, p, len);
- while (pointer_count > 0) {
- q[len] = '*';
- ++len;
- --pointer_count;
- }
- q[len] = '\0';
- free(op);
- return q;
- }
- /*
- * Read a list of parameters. Each parameter is a name and a type.
- * The list ends with a ')'. We have already read the '('.
- */
- static struct params *
- read_params()
- {
- char *token;
- struct params *ret, **pp, *p;
- ret = NULL;
- pp = &ret;
- token = read_token_no_eof();
- if (strcmp(token, ")") != 0) {
- while (1) {
- p = xmalloc(sizeof(struct params));
- p->name = token;
- p->type = read_type();
- p->next = NULL;
- *pp = p;
- pp = &p->next;
- token = read_token_no_eof();
- if (strcmp(token, ",") != 0)
- break;
- token = read_token_no_eof();
- }
- }
- if (strcmp(token, ")") != 0) {
- sysfatal("%s:%ud: expected '('\n",
- file, lineno);
- }
- return ret;
- }
- /*
- * Read a function header. This reads up to and including the initial
- * '{' character. Returns 1 if it read a header, 0 at EOF.
- */
- static int
- read_func_header(char **name, struct params **params, struct params **rets)
- {
- int lastline;
- char *token;
- lastline = -1;
- while (1) {
- token = read_token();
- if (token == NULL)
- return 0;
- if (strcmp(token, "func") == 0) {
- if(lastline != -1)
- printf("\n");
- break;
- }
- if (lastline != lineno) {
- if (lastline == lineno-1)
- printf("\n");
- else
- printf("\n#line %d \"%s\"\n", lineno, file);
- lastline = lineno;
- }
- printf("%s ", token);
- }
- *name = read_token_no_eof();
- token = read_token();
- if (token == NULL || strcmp(token, "(") != 0) {
- sysfatal("%s:%ud: expected \"(\"\n",
- file, lineno);
- }
- *params = read_params();
- token = read_token();
- if (token == NULL || strcmp(token, "(") != 0)
- *rets = NULL;
- else {
- *rets = read_params();
- token = read_token();
- }
- if (token == NULL || strcmp(token, "{") != 0) {
- sysfatal("%s:%ud: expected \"{\"\n",
- file, lineno);
- }
- return 1;
- }
- /* Write out parameters. */
- static void
- write_params(struct params *params, int *first)
- {
- struct params *p;
- for (p = params; p != NULL; p = p->next) {
- if (*first)
- *first = 0;
- else
- printf(", ");
- printf("%s %s", p->type, p->name);
- }
- }
- /* Define the gcc function return type if necessary. */
- static void
- define_gcc_return_type(char *package, char *name, struct params *rets)
- {
- struct params *p;
- if (rets == NULL || rets->next == NULL)
- return;
- printf("struct %s_%s_ret {\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
- printf("};\n");
- }
- /* Write out the gcc function return type. */
- static void
- write_gcc_return_type(char *package, char *name, struct params *rets)
- {
- if (rets == NULL)
- printf("void");
- else if (rets->next == NULL)
- printf("%s", rets->type);
- else
- printf("struct %s_%s_ret", package, name);
- }
- /* Write out a gcc function header. */
- static void
- write_gcc_func_header(char *package, char *name, struct params *params,
- struct params *rets)
- {
- int first;
- struct params *p;
- define_gcc_return_type(package, name, rets);
- write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- printf(") __asm__ (GOSYM_PREFIX \"");
- if (pkgpath != NULL)
- printf("%s", pkgpath);
- else if (prefix != NULL)
- printf("%s.%s", prefix, package);
- else
- printf("%s", package);
- printf(".%s\");\n", name);
- write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- printf(")\n{\n");
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
- }
- /* Write out a gcc function trailer. */
- static void
- write_gcc_func_trailer(char *package, char *name, struct params *rets)
- {
- if (rets == NULL)
- ;
- else if (rets->next == NULL)
- printf("return %s;\n", rets->name);
- else {
- struct params *p;
- printf(" {\n struct %s_%s_ret __ret;\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" __ret.%s = %s;\n", p->name, p->name);
- printf(" return __ret;\n }\n");
- }
- printf("}\n");
- }
- /* Write out a function header. */
- static void
- write_func_header(char *package, char *name, struct params *params,
- struct params *rets)
- {
- write_gcc_func_header(package, name, params, rets);
- printf("#line %d \"%s\"\n", lineno, file);
- }
- /* Write out a function trailer. */
- static void
- write_func_trailer(char *package, char *name,
- struct params *rets)
- {
- write_gcc_func_trailer(package, name, rets);
- }
- /*
- * Read and write the body of the function, ending in an unnested }
- * (which is read but not written).
- */
- static void
- copy_body(void)
- {
- int nesting = 0;
- while (1) {
- int c;
- c = getchar_no_eof();
- if (c == '}' && nesting == 0)
- return;
- putchar(c);
- switch (c) {
- default:
- break;
- case '{':
- ++nesting;
- break;
- case '}':
- --nesting;
- break;
- case '/':
- c = getchar_update_lineno();
- putchar(c);
- if (c == '/') {
- do {
- c = getchar_no_eof();
- putchar(c);
- } while (c != '\n');
- } else if (c == '*') {
- while (1) {
- c = getchar_no_eof();
- putchar(c);
- if (c == '*') {
- do {
- c = getchar_no_eof();
- putchar(c);
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- }
- break;
- case '"':
- case '\'':
- {
- int delim = c;
- do {
- c = getchar_no_eof();
- putchar(c);
- if (c == '\\') {
- c = getchar_no_eof();
- putchar(c);
- c = '\0';
- }
- } while (c != delim);
- }
- break;
- }
- }
- }
- /* Process the entire file. */
- static void
- process_file(void)
- {
- char *package, *name;
- struct params *params, *rets;
- package = read_package();
- read_preprocessor_lines();
- while (read_func_header(&name, ¶ms, &rets)) {
- char *p;
- char *pkg;
- char *nm;
- p = strchr(name, '.');
- if (p == NULL) {
- pkg = package;
- nm = name;
- } else {
- pkg = name;
- nm = p + 1;
- *p = '\0';
- }
- write_func_header(pkg, nm, params, rets);
- copy_body();
- write_func_trailer(pkg, nm, rets);
- free(name);
- free_params(params);
- free_params(rets);
- }
- free(package);
- }
- static void
- usage(void)
- {
- sysfatal("Usage: goc2c [--go-pkgpath PKGPATH] [--go-prefix PREFIX] [file]\n");
- }
- int
- main(int argc, char **argv)
- {
- char *goarch;
- argv0 = argv[0];
- while(argc > 1 && argv[1][0] == '-') {
- if(strcmp(argv[1], "-") == 0)
- break;
- if (strcmp(argv[1], "--go-pkgpath") == 0 && argc > 2) {
- pkgpath = argv[2];
- argc--;
- argv++;
- } else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
- prefix = argv[2];
- argc--;
- argv++;
- } else
- usage();
- argc--;
- argv++;
- }
- if(argc <= 1 || strcmp(argv[1], "-") == 0) {
- file = "<stdin>";
- process_file();
- exit(0);
- }
- if(argc > 2)
- usage();
- file = argv[1];
- if(freopen(file, "r", stdin) == 0) {
- sysfatal("open %s: %r\n", file);
- }
- printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
- process_file();
- exit(0);
- }
|