2016-07-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
[official-gcc.git] / libgo / runtime / goc2c.c
blob68281c36bca4ad453400c6ac092fb60c581a5898
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.
5 // +build ignore
7 /*
8 * Translate a .goc file into a .c file. A .goc file is a combination
9 * of a limited form of Go with C.
13 package PACKAGENAME
14 {# line}
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.
25 #include <assert.h>
26 #include <ctype.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
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. */
44 struct params {
45 struct params *next;
46 char *name;
47 char *type;
50 char *argv0;
52 static void
53 sysfatal(char *fmt, ...)
55 char buf[256];
56 va_list arg;
58 va_start(arg, fmt);
59 vsnprintf(buf, sizeof buf, fmt, arg);
60 va_end(arg);
62 fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
63 exit(1);
66 /* Unexpected EOF. */
67 static void
68 bad_eof(void)
70 sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
73 /* Out of memory. */
74 static void
75 bad_mem(void)
77 sysfatal("%s:%ud: out of memory\n", file, lineno);
80 /* Allocate memory without fail. */
81 static void *
82 xmalloc(unsigned int size)
84 void *ret = malloc(size);
85 if (ret == NULL)
86 bad_mem();
87 return ret;
90 /* Reallocate memory without fail. */
91 static void*
92 xrealloc(void *buf, unsigned int size)
94 void *ret = realloc(buf, size);
95 if (ret == NULL)
96 bad_mem();
97 return ret;
100 /* Copy a string into memory without fail. */
101 static char *
102 xstrdup(const char *p)
104 char *ret = xmalloc(strlen(p) + 1);
105 strcpy(ret, p);
106 return ret;
109 /* Free a list of parameters. */
110 static void
111 free_params(struct params *p)
113 while (p != NULL) {
114 struct params *next;
116 next = p->next;
117 free(p->name);
118 free(p->type);
119 free(p);
120 p = next;
124 /* Read a character, tracking lineno. */
125 static int
126 getchar_update_lineno(void)
128 int c;
130 c = getchar();
131 if (c == '\n')
132 ++lineno;
133 return c;
136 /* Read a character, giving an error on EOF, tracking lineno. */
137 static int
138 getchar_no_eof(void)
140 int c;
142 c = getchar_update_lineno();
143 if (c == EOF)
144 bad_eof();
145 return c;
148 /* Read a character, skipping comments. */
149 static int
150 getchar_skipping_comments(void)
152 int c;
154 while (1) {
155 c = getchar_update_lineno();
156 if (c != '/')
157 return c;
159 c = getchar();
160 if (c == '/') {
161 do {
162 c = getchar_update_lineno();
163 } while (c != EOF && c != '\n');
164 return c;
165 } else if (c == '*') {
166 while (1) {
167 c = getchar_update_lineno();
168 if (c == EOF)
169 return EOF;
170 if (c == '*') {
171 do {
172 c = getchar_update_lineno();
173 } while (c == '*');
174 if (c == '/')
175 break;
178 } else {
179 ungetc(c, stdin);
180 return '/';
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.
190 static char *
191 read_token(void)
193 int c, q;
194 char *buf;
195 unsigned int alc, off;
196 const char* delims = "(),{}";
198 while (1) {
199 c = getchar_skipping_comments();
200 if (c == EOF)
201 return NULL;
202 if (!isspace(c))
203 break;
205 alc = 16;
206 buf = xmalloc(alc + 1);
207 off = 0;
208 if(c == '"' || c == '\'') {
209 q = c;
210 buf[off] = c;
211 ++off;
212 while (1) {
213 if (off+2 >= alc) { // room for c and maybe next char
214 alc *= 2;
215 buf = xrealloc(buf, alc + 1);
217 c = getchar_no_eof();
218 buf[off] = c;
219 ++off;
220 if(c == q)
221 break;
222 if(c == '\\') {
223 buf[off] = getchar_no_eof();
224 ++off;
227 } else if (strchr(delims, c) != NULL) {
228 buf[off] = c;
229 ++off;
230 } else {
231 while (1) {
232 if (off >= alc) {
233 alc *= 2;
234 buf = xrealloc(buf, alc + 1);
236 buf[off] = c;
237 ++off;
238 c = getchar_skipping_comments();
239 if (c == EOF)
240 break;
241 if (isspace(c) || strchr(delims, c) != NULL) {
242 if (c == '\n')
243 lineno--;
244 ungetc(c, stdin);
245 break;
249 buf[off] = '\0';
250 return buf;
253 /* Read a token, giving an error on EOF. */
254 static char *
255 read_token_no_eof(void)
257 char *token = read_token();
258 if (token == NULL)
259 bad_eof();
260 return token;
263 /* Read the package clause, and return the package name. */
264 static char *
265 read_package(void)
267 char *token;
269 token = read_token_no_eof();
270 if (token == NULL)
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. */
280 static void
281 read_preprocessor_lines(void)
283 while (1) {
284 int c;
286 do {
287 c = getchar_skipping_comments();
288 } while (isspace(c));
289 if (c != '#') {
290 ungetc(c, stdin);
291 break;
293 putchar(c);
294 do {
295 c = getchar_update_lineno();
296 putchar(c);
297 } while (c != '\n');
302 * Read a type in Go syntax and return a type in C syntax. We only
303 * permit basic types and pointers.
305 static char *
306 read_type(void)
308 char *p, *op, *q;
309 int pointer_count;
310 unsigned int len;
312 p = read_token_no_eof();
313 if (*p != '*') {
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");
320 return p;
322 op = p;
323 pointer_count = 0;
324 while (*p == '*') {
325 ++pointer_count;
326 ++p;
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";
336 len = strlen(p);
337 q = xmalloc(len + pointer_count + 1);
338 memcpy(q, p, len);
339 while (pointer_count > 0) {
340 q[len] = '*';
341 ++len;
342 --pointer_count;
344 q[len] = '\0';
345 free(op);
346 return q;
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 *
354 read_params()
356 char *token;
357 struct params *ret, **pp, *p;
359 ret = NULL;
360 pp = &ret;
361 token = read_token_no_eof();
362 if (strcmp(token, ")") != 0) {
363 while (1) {
364 p = xmalloc(sizeof(struct params));
365 p->name = token;
366 p->type = read_type();
367 p->next = NULL;
368 *pp = p;
369 pp = &p->next;
371 token = read_token_no_eof();
372 if (strcmp(token, ",") != 0)
373 break;
374 token = read_token_no_eof();
377 if (strcmp(token, ")") != 0) {
378 sysfatal("%s:%ud: expected '('\n",
379 file, lineno);
381 return ret;
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.
388 static int
389 read_func_header(char **name, struct params **params, struct params **rets)
391 int lastline;
392 char *token;
394 lastline = -1;
395 while (1) {
396 token = read_token();
397 if (token == NULL)
398 return 0;
399 if (strcmp(token, "func") == 0) {
400 if(lastline != -1)
401 printf("\n");
402 break;
404 if (lastline != lineno) {
405 if (lastline == lineno-1)
406 printf("\n");
407 else
408 printf("\n#line %d \"%s\"\n", lineno, file);
409 lastline = lineno;
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",
419 file, lineno);
421 *params = read_params();
423 token = read_token();
424 if (token == NULL || strcmp(token, "(") != 0)
425 *rets = NULL;
426 else {
427 *rets = read_params();
428 token = read_token();
430 if (token == NULL || strcmp(token, "{") != 0) {
431 sysfatal("%s:%ud: expected \"{\"\n",
432 file, lineno);
434 return 1;
437 /* Write out parameters. */
438 static void
439 write_params(struct params *params, int *first)
441 struct params *p;
443 for (p = params; p != NULL; p = p->next) {
444 if (*first)
445 *first = 0;
446 else
447 printf(", ");
448 printf("%s %s", p->type, p->name);
452 /* Define the gcc function return type if necessary. */
453 static void
454 define_gcc_return_type(char *package, char *name, struct params *rets)
456 struct params *p;
458 if (rets == NULL || rets->next == NULL)
459 return;
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);
463 printf("};\n");
466 /* Write out the gcc function return type. */
467 static void
468 write_gcc_return_type(char *package, char *name, struct params *rets)
470 if (rets == NULL)
471 printf("void");
472 else if (rets->next == NULL)
473 printf("%s", rets->type);
474 else
475 printf("struct %s_%s_ret", package, name);
478 /* Write out a gcc function header. */
479 static void
480 write_gcc_func_header(char *package, char *name, struct params *params,
481 struct params *rets)
483 int first;
484 struct params *p;
486 define_gcc_return_type(package, name, rets);
487 write_gcc_return_type(package, name, rets);
488 printf(" %s_%s(", package, name);
489 first = 1;
490 write_params(params, &first);
491 printf(") __asm__ (GOSYM_PREFIX \"");
492 if (pkgpath != NULL)
493 printf("%s", pkgpath);
494 else if (prefix != NULL)
495 printf("%s.%s", prefix, package);
496 else
497 printf("%s", package);
498 printf(".%s\");\n", name);
499 write_gcc_return_type(package, name, rets);
500 printf(" %s_%s(", package, name);
501 first = 1;
502 write_params(params, &first);
503 printf(")\n{\n");
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. */
509 static void
510 write_gcc_func_trailer(char *package, char *name, struct params *rets)
512 if (rets == NULL)
514 else if (rets->next == NULL)
515 printf("return %s;\n", rets->name);
516 else {
517 struct params *p;
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");
524 printf("}\n");
527 /* Write out a function header. */
528 static void
529 write_func_header(char *package, char *name, struct params *params,
530 struct params *rets)
532 write_gcc_func_header(package, name, params, rets);
533 printf("#line %d \"%s\"\n", lineno, file);
536 /* Write out a function trailer. */
537 static void
538 write_func_trailer(char *package, char *name,
539 struct params *rets)
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).
548 static void
549 copy_body(void)
551 int nesting = 0;
552 while (1) {
553 int c;
555 c = getchar_no_eof();
556 if (c == '}' && nesting == 0)
557 return;
558 putchar(c);
559 switch (c) {
560 default:
561 break;
562 case '{':
563 ++nesting;
564 break;
565 case '}':
566 --nesting;
567 break;
568 case '/':
569 c = getchar_update_lineno();
570 putchar(c);
571 if (c == '/') {
572 do {
573 c = getchar_no_eof();
574 putchar(c);
575 } while (c != '\n');
576 } else if (c == '*') {
577 while (1) {
578 c = getchar_no_eof();
579 putchar(c);
580 if (c == '*') {
581 do {
582 c = getchar_no_eof();
583 putchar(c);
584 } while (c == '*');
585 if (c == '/')
586 break;
590 break;
591 case '"':
592 case '\'':
594 int delim = c;
595 do {
596 c = getchar_no_eof();
597 putchar(c);
598 if (c == '\\') {
599 c = getchar_no_eof();
600 putchar(c);
601 c = '\0';
603 } while (c != delim);
605 break;
610 /* Process the entire file. */
611 static void
612 process_file(void)
614 char *package, *name;
615 struct params *params, *rets;
617 package = read_package();
618 read_preprocessor_lines();
619 while (read_func_header(&name, &params, &rets)) {
620 char *p;
621 char *pkg;
622 char *nm;
624 p = strchr(name, '.');
625 if (p == NULL) {
626 pkg = package;
627 nm = name;
628 } else {
629 pkg = name;
630 nm = p + 1;
631 *p = '\0';
633 write_func_header(pkg, nm, params, rets);
634 copy_body();
635 write_func_trailer(pkg, nm, rets);
636 free(name);
637 free_params(params);
638 free_params(rets);
640 free(package);
643 static void
644 usage(void)
646 sysfatal("Usage: goc2c [--go-pkgpath PKGPATH] [--go-prefix PREFIX] [file]\n");
650 main(int argc, char **argv)
652 char *goarch;
654 argv0 = argv[0];
655 while(argc > 1 && argv[1][0] == '-') {
656 if(strcmp(argv[1], "-") == 0)
657 break;
658 if (strcmp(argv[1], "--go-pkgpath") == 0 && argc > 2) {
659 pkgpath = argv[2];
660 argc--;
661 argv++;
662 } else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
663 prefix = argv[2];
664 argc--;
665 argv++;
666 } else
667 usage();
668 argc--;
669 argv++;
672 if(argc <= 1 || strcmp(argv[1], "-") == 0) {
673 file = "<stdin>";
674 process_file();
675 exit(0);
678 if(argc > 2)
679 usage();
681 file = argv[1];
682 if(freopen(file, "r", stdin) == 0) {
683 sysfatal("open %s: %r\n", file);
686 printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
687 process_file();
688 exit(0);