diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libgo/runtime/goc2c.c | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libgo/runtime/goc2c.c')
-rw-r--r-- | libgo/runtime/goc2c.c | 735 |
1 files changed, 735 insertions, 0 deletions
diff --git a/libgo/runtime/goc2c.c b/libgo/runtime/goc2c.c new file mode 100644 index 000000000..bf7483309 --- /dev/null +++ b/libgo/runtime/goc2c.c @@ -0,0 +1,735 @@ +// 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. + +/* 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +/* Whether we're emitting for gcc */ +static int gcc; + +/* Package prefix to use; only meaningful for gcc */ +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; +}; + +/* index into type_table */ +enum { + Bool, + Float, + Int, + Uint, + Uintptr, + String, + Slice, + Eface, +}; + +static struct { + char *name; + int size; +} type_table[] = { + /* variable sized first, for easy replacement */ + /* order matches enum above */ + /* default is 32-bit architecture sizes */ + "bool", 1, + "float", 4, + "int", 4, + "uint", 4, + "uintptr", 4, + "String", 8, + "Slice", 12, + "Eface", 8, + + /* fixed size */ + "float32", 4, + "float64", 8, + "byte", 1, + "int8", 1, + "uint8", 1, + "int16", 2, + "uint16", 2, + "int32", 4, + "uint32", 4, + "int64", 8, + "uint64", 8, + + NULL, +}; + +/* Fixed structure alignment (non-gcc only) */ +int structround = 4; + +/* Unexpected EOF. */ +static void +bad_eof(void) +{ + fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno); + exit(1); +} + +/* Out of memory. */ +static void +bad_mem(void) +{ + fprintf(stderr, "%s:%u: out of memory\n", file, lineno); + exit(1); +} + +/* 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; +} + +/* 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 delimited by whitespace or by + [(),{}]. The latter are all returned as single characters. */ +static char * +read_token(void) +{ + int c; + 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 (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 (strcmp(token, "package") != 0) { + fprintf(stderr, + "%s:%u: expected \"package\", got \"%s\"\n", + file, lineno, token); + exit(1); + } + 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 != '*') + return p; + op = p; + pointer_count = 0; + while (*p == '*') { + ++pointer_count; + ++p; + } + 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; +} + +/* Return the size of the given type. */ +static int +type_size(char *p) +{ + int i; + + if(p[strlen(p)-1] == '*') + return type_table[Uintptr].size; + + for(i=0; type_table[i].name; i++) + if(strcmp(type_table[i].name, p) == 0) + return type_table[i].size; + if(!gcc) { + fprintf(stderr, "%s:%u: unknown type %s\n", file, lineno, p); + exit(1); + } + return 1; +} + +/* 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(int *poffset) +{ + char *token; + struct params *ret, **pp, *p; + int offset, size, rnd; + + ret = NULL; + pp = &ret; + token = read_token_no_eof(); + offset = 0; + 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; + + size = type_size(p->type); + rnd = size; + if(rnd > structround) + rnd = structround; + if(offset%rnd) + offset += rnd - offset%rnd; + offset += size; + + token = read_token_no_eof(); + if (strcmp(token, ",") != 0) + break; + token = read_token_no_eof(); + } + } + if (strcmp(token, ")") != 0) { + fprintf(stderr, "%s:%u: expected '('\n", + file, lineno); + exit(1); + } + if (poffset != NULL) + *poffset = offset; + 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, int *paramwid, 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) { + fprintf(stderr, "%s:%u: expected \"(\"\n", + file, lineno); + exit(1); + } + *params = read_params(paramwid); + + token = read_token(); + if (token == NULL || strcmp(token, "(") != 0) + *rets = NULL; + else { + *rets = read_params(NULL); + token = read_token(); + } + if (token == NULL || strcmp(token, "{") != 0) { + fprintf(stderr, "%s:%u: expected \"{\"\n", + file, lineno); + exit(1); + } + 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); + } +} + +/* Write a 6g function header. */ +static void +write_6g_func_header(char *package, char *name, struct params *params, + int paramwid, struct params *rets) +{ + int first, n; + + printf("void\n%s·%s(", package, name); + first = 1; + write_params(params, &first); + + /* insert padding to align output struct */ + if(rets != NULL && paramwid%structround != 0) { + n = structround - paramwid%structround; + if(n & 1) + printf(", uint8"); + if(n & 2) + printf(", uint16"); + if(n & 4) + printf(", uint32"); + } + + write_params(rets, &first); + printf(")\n{\n"); +} + +/* Write a 6g function trailer. */ +static void +write_6g_func_trailer(struct params *rets) +{ + struct params *p; + + for (p = rets; p != NULL; p = p->next) + printf("\tFLUSH(&%s);\n", p->name); + printf("}\n"); +} + +/* 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 (\""); + if (prefix != NULL) + printf("%s.", prefix); + printf("%s.%s\");\n", package, 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, int paramwid, + struct params *rets) +{ + if (gcc) + write_gcc_func_header(package, name, params, rets); + else + write_6g_func_header(package, name, params, paramwid, 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) +{ + if (gcc) + write_gcc_func_trailer(package, name, rets); + else + write_6g_func_trailer(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; + int paramwid; + + package = read_package(); + read_preprocessor_lines(); + while (read_func_header(&name, ¶ms, ¶mwid, &rets)) { + write_func_header(package, name, params, paramwid, rets); + copy_body(); + write_func_trailer(package, name, rets); + free(name); + free_params(params); + free_params(rets); + } + free(package); +} + +static void +usage(void) +{ + fprintf(stderr, "Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + char *goarch; + + while(argc > 1 && argv[1][0] == '-') { + if(strcmp(argv[1], "-") == 0) + break; + if(strcmp(argv[1], "--6g") == 0) + gcc = 0; + else if(strcmp(argv[1], "--gcc") == 0) + gcc = 1; + 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(); + return 0; + } + + if(argc > 2) + usage(); + + file = argv[1]; + if(freopen(file, "r", stdin) == 0) { + fprintf(stderr, "open %s: %s\n", file, strerror(errno)); + exit(1); + } + + if(!gcc) { + // 6g etc; update size table + goarch = getenv("GOARCH"); + if(goarch != NULL && strcmp(goarch, "amd64") == 0) { + type_table[Uintptr].size = 8; + type_table[String].size = 16; + type_table[Slice].size = 8+4+4; + type_table[Eface].size = 8+8; + structround = 8; + } + } + + process_file(); + return 0; +} |