OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [runtime/] [goc2c.c] - Rev 771

Go to most recent revision | Compare with Previous | Blame | View Log

// 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>
 
/* 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;
 
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;
}
 
/* 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 != '*')
		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) {
		sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
	}
	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) {
		sysfatal("%s:%ud: expected '('\n",
			file, lineno);
	}
	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) {
		sysfatal("%s:%ud: expected \"(\"\n",
			file, lineno);
	}
	*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) {
		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);
	}
}
 
/* 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, &params, &paramwid, &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)
{
	sysfatal("Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
}
 
void
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], "--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();
		exit(0);
	}
 
	if(argc > 2)
		usage();
 
	file = argv[1];
	if(freopen(file, "r", stdin) == 0) {
		sysfatal("open %s: %r\n", file);
	}
 
	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;
		}
	}
 
	printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
	process_file();
	exit(0);
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.