* decl.c (get_atexit_node): Remove dead code.
[official-gcc.git] / libgo / runtime / goc2c.c
blob55c6d9b2dc43c26e475eb6f62a7c198870637827
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 /* Whether we're emitting for gcc */
34 static int gcc;
36 /* Package path to use; only meaningful for gcc */
37 static const char *pkgpath;
39 /* Package prefix to use; only meaningful for gcc */
40 static const char *prefix;
42 /* File and line number */
43 static const char *file;
44 static unsigned int lineno = 1;
46 /* List of names and types. */
47 struct params {
48 struct params *next;
49 char *name;
50 char *type;
53 /* index into type_table */
54 enum {
55 Bool,
56 Float,
57 Int,
58 Uint,
59 Uintptr,
60 String,
61 Slice,
62 Eface,
65 static struct {
66 char *name;
67 int size;
68 } type_table[] = {
69 /* variable sized first, for easy replacement */
70 /* order matches enum above */
71 /* default is 32-bit architecture sizes */
72 "bool", 1,
73 "float", 4,
74 "int", 4,
75 "uint", 4,
76 "uintptr", 4,
77 "String", 8,
78 "Slice", 12,
79 "Eface", 8,
81 /* fixed size */
82 "float32", 4,
83 "float64", 8,
84 "byte", 1,
85 "int8", 1,
86 "uint8", 1,
87 "int16", 2,
88 "uint16", 2,
89 "int32", 4,
90 "uint32", 4,
91 "int64", 8,
92 "uint64", 8,
94 NULL,
97 /* Fixed structure alignment (non-gcc only) */
98 int structround = 4;
100 char *argv0;
102 static void
103 sysfatal(char *fmt, ...)
105 char buf[256];
106 va_list arg;
108 va_start(arg, fmt);
109 vsnprintf(buf, sizeof buf, fmt, arg);
110 va_end(arg);
112 fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
113 exit(1);
116 /* Unexpected EOF. */
117 static void
118 bad_eof(void)
120 sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
123 /* Out of memory. */
124 static void
125 bad_mem(void)
127 sysfatal("%s:%ud: out of memory\n", file, lineno);
130 /* Allocate memory without fail. */
131 static void *
132 xmalloc(unsigned int size)
134 void *ret = malloc(size);
135 if (ret == NULL)
136 bad_mem();
137 return ret;
140 /* Reallocate memory without fail. */
141 static void*
142 xrealloc(void *buf, unsigned int size)
144 void *ret = realloc(buf, size);
145 if (ret == NULL)
146 bad_mem();
147 return ret;
150 /* Free a list of parameters. */
151 static void
152 free_params(struct params *p)
154 while (p != NULL) {
155 struct params *next;
157 next = p->next;
158 free(p->name);
159 free(p->type);
160 free(p);
161 p = next;
165 /* Read a character, tracking lineno. */
166 static int
167 getchar_update_lineno(void)
169 int c;
171 c = getchar();
172 if (c == '\n')
173 ++lineno;
174 return c;
177 /* Read a character, giving an error on EOF, tracking lineno. */
178 static int
179 getchar_no_eof(void)
181 int c;
183 c = getchar_update_lineno();
184 if (c == EOF)
185 bad_eof();
186 return c;
189 /* Read a character, skipping comments. */
190 static int
191 getchar_skipping_comments(void)
193 int c;
195 while (1) {
196 c = getchar_update_lineno();
197 if (c != '/')
198 return c;
200 c = getchar();
201 if (c == '/') {
202 do {
203 c = getchar_update_lineno();
204 } while (c != EOF && c != '\n');
205 return c;
206 } else if (c == '*') {
207 while (1) {
208 c = getchar_update_lineno();
209 if (c == EOF)
210 return EOF;
211 if (c == '*') {
212 do {
213 c = getchar_update_lineno();
214 } while (c == '*');
215 if (c == '/')
216 break;
219 } else {
220 ungetc(c, stdin);
221 return '/';
227 * Read and return a token. Tokens are string or character literals
228 * or else delimited by whitespace or by [(),{}].
229 * The latter are all returned as single characters.
231 static char *
232 read_token(void)
234 int c, q;
235 char *buf;
236 unsigned int alc, off;
237 const char* delims = "(),{}";
239 while (1) {
240 c = getchar_skipping_comments();
241 if (c == EOF)
242 return NULL;
243 if (!isspace(c))
244 break;
246 alc = 16;
247 buf = xmalloc(alc + 1);
248 off = 0;
249 if(c == '"' || c == '\'') {
250 q = c;
251 buf[off] = c;
252 ++off;
253 while (1) {
254 if (off+2 >= alc) { // room for c and maybe next char
255 alc *= 2;
256 buf = xrealloc(buf, alc + 1);
258 c = getchar_no_eof();
259 buf[off] = c;
260 ++off;
261 if(c == q)
262 break;
263 if(c == '\\') {
264 buf[off] = getchar_no_eof();
265 ++off;
268 } else if (strchr(delims, c) != NULL) {
269 buf[off] = c;
270 ++off;
271 } else {
272 while (1) {
273 if (off >= alc) {
274 alc *= 2;
275 buf = xrealloc(buf, alc + 1);
277 buf[off] = c;
278 ++off;
279 c = getchar_skipping_comments();
280 if (c == EOF)
281 break;
282 if (isspace(c) || strchr(delims, c) != NULL) {
283 if (c == '\n')
284 lineno--;
285 ungetc(c, stdin);
286 break;
290 buf[off] = '\0';
291 return buf;
294 /* Read a token, giving an error on EOF. */
295 static char *
296 read_token_no_eof(void)
298 char *token = read_token();
299 if (token == NULL)
300 bad_eof();
301 return token;
304 /* Read the package clause, and return the package name. */
305 static char *
306 read_package(void)
308 char *token;
310 token = read_token_no_eof();
311 if (token == NULL)
312 sysfatal("%s:%ud: no token\n", file, lineno);
313 if (strcmp(token, "package") != 0) {
314 sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
315 file, lineno, token);
317 return read_token_no_eof();
320 /* Read and copy preprocessor lines. */
321 static void
322 read_preprocessor_lines(void)
324 while (1) {
325 int c;
327 do {
328 c = getchar_skipping_comments();
329 } while (isspace(c));
330 if (c != '#') {
331 ungetc(c, stdin);
332 break;
334 putchar(c);
335 do {
336 c = getchar_update_lineno();
337 putchar(c);
338 } while (c != '\n');
343 * Read a type in Go syntax and return a type in C syntax. We only
344 * permit basic types and pointers.
346 static char *
347 read_type(void)
349 char *p, *op, *q;
350 int pointer_count;
351 unsigned int len;
353 p = read_token_no_eof();
354 if (*p != '*')
355 return p;
356 op = p;
357 pointer_count = 0;
358 while (*p == '*') {
359 ++pointer_count;
360 ++p;
362 len = strlen(p);
363 q = xmalloc(len + pointer_count + 1);
364 memcpy(q, p, len);
365 while (pointer_count > 0) {
366 q[len] = '*';
367 ++len;
368 --pointer_count;
370 q[len] = '\0';
371 free(op);
372 return q;
375 /* Return the size of the given type. */
376 static int
377 type_size(char *p)
379 int i;
381 if(p[strlen(p)-1] == '*')
382 return type_table[Uintptr].size;
384 for(i=0; type_table[i].name; i++)
385 if(strcmp(type_table[i].name, p) == 0)
386 return type_table[i].size;
387 if(!gcc) {
388 sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
390 return 1;
394 * Read a list of parameters. Each parameter is a name and a type.
395 * The list ends with a ')'. We have already read the '('.
397 static struct params *
398 read_params(int *poffset)
400 char *token;
401 struct params *ret, **pp, *p;
402 int offset, size, rnd;
404 ret = NULL;
405 pp = &ret;
406 token = read_token_no_eof();
407 offset = 0;
408 if (strcmp(token, ")") != 0) {
409 while (1) {
410 p = xmalloc(sizeof(struct params));
411 p->name = token;
412 p->type = read_type();
413 p->next = NULL;
414 *pp = p;
415 pp = &p->next;
417 size = type_size(p->type);
418 rnd = size;
419 if(rnd > structround)
420 rnd = structround;
421 if(offset%rnd)
422 offset += rnd - offset%rnd;
423 offset += size;
425 token = read_token_no_eof();
426 if (strcmp(token, ",") != 0)
427 break;
428 token = read_token_no_eof();
431 if (strcmp(token, ")") != 0) {
432 sysfatal("%s:%ud: expected '('\n",
433 file, lineno);
435 if (poffset != NULL)
436 *poffset = offset;
437 return ret;
441 * Read a function header. This reads up to and including the initial
442 * '{' character. Returns 1 if it read a header, 0 at EOF.
444 static int
445 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
447 int lastline;
448 char *token;
450 lastline = -1;
451 while (1) {
452 token = read_token();
453 if (token == NULL)
454 return 0;
455 if (strcmp(token, "func") == 0) {
456 if(lastline != -1)
457 printf("\n");
458 break;
460 if (lastline != lineno) {
461 if (lastline == lineno-1)
462 printf("\n");
463 else
464 printf("\n#line %d \"%s\"\n", lineno, file);
465 lastline = lineno;
467 printf("%s ", token);
470 *name = read_token_no_eof();
472 token = read_token();
473 if (token == NULL || strcmp(token, "(") != 0) {
474 sysfatal("%s:%ud: expected \"(\"\n",
475 file, lineno);
477 *params = read_params(paramwid);
479 token = read_token();
480 if (token == NULL || strcmp(token, "(") != 0)
481 *rets = NULL;
482 else {
483 *rets = read_params(NULL);
484 token = read_token();
486 if (token == NULL || strcmp(token, "{") != 0) {
487 sysfatal("%s:%ud: expected \"{\"\n",
488 file, lineno);
490 return 1;
493 /* Write out parameters. */
494 static void
495 write_params(struct params *params, int *first)
497 struct params *p;
499 for (p = params; p != NULL; p = p->next) {
500 if (*first)
501 *first = 0;
502 else
503 printf(", ");
504 printf("%s %s", p->type, p->name);
508 /* Write a 6g function header. */
509 static void
510 write_6g_func_header(char *package, char *name, struct params *params,
511 int paramwid, struct params *rets)
513 int first, n;
515 printf("void\n%s·%s(", package, name);
516 first = 1;
517 write_params(params, &first);
519 /* insert padding to align output struct */
520 if(rets != NULL && paramwid%structround != 0) {
521 n = structround - paramwid%structround;
522 if(n & 1)
523 printf(", uint8");
524 if(n & 2)
525 printf(", uint16");
526 if(n & 4)
527 printf(", uint32");
530 write_params(rets, &first);
531 printf(")\n{\n");
534 /* Write a 6g function trailer. */
535 static void
536 write_6g_func_trailer(struct params *rets)
538 struct params *p;
540 for (p = rets; p != NULL; p = p->next)
541 printf("\tFLUSH(&%s);\n", p->name);
542 printf("}\n");
545 /* Define the gcc function return type if necessary. */
546 static void
547 define_gcc_return_type(char *package, char *name, struct params *rets)
549 struct params *p;
551 if (rets == NULL || rets->next == NULL)
552 return;
553 printf("struct %s_%s_ret {\n", package, name);
554 for (p = rets; p != NULL; p = p->next)
555 printf(" %s %s;\n", p->type, p->name);
556 printf("};\n");
559 /* Write out the gcc function return type. */
560 static void
561 write_gcc_return_type(char *package, char *name, struct params *rets)
563 if (rets == NULL)
564 printf("void");
565 else if (rets->next == NULL)
566 printf("%s", rets->type);
567 else
568 printf("struct %s_%s_ret", package, name);
571 /* Write out a gcc function header. */
572 static void
573 write_gcc_func_header(char *package, char *name, struct params *params,
574 struct params *rets)
576 int first;
577 struct params *p;
579 define_gcc_return_type(package, name, rets);
580 write_gcc_return_type(package, name, rets);
581 printf(" %s_%s(", package, name);
582 first = 1;
583 write_params(params, &first);
584 printf(") asm (\"");
585 if (pkgpath != NULL)
586 printf("%s", pkgpath);
587 else if (prefix != NULL)
588 printf("%s.%s", prefix, package);
589 else
590 printf("%s", package);
591 printf(".%s\");\n", name);
592 write_gcc_return_type(package, name, rets);
593 printf(" %s_%s(", package, name);
594 first = 1;
595 write_params(params, &first);
596 printf(")\n{\n");
597 for (p = rets; p != NULL; p = p->next)
598 printf(" %s %s;\n", p->type, p->name);
601 /* Write out a gcc function trailer. */
602 static void
603 write_gcc_func_trailer(char *package, char *name, struct params *rets)
605 if (rets == NULL)
607 else if (rets->next == NULL)
608 printf("return %s;\n", rets->name);
609 else {
610 struct params *p;
612 printf(" {\n struct %s_%s_ret __ret;\n", package, name);
613 for (p = rets; p != NULL; p = p->next)
614 printf(" __ret.%s = %s;\n", p->name, p->name);
615 printf(" return __ret;\n }\n");
617 printf("}\n");
620 /* Write out a function header. */
621 static void
622 write_func_header(char *package, char *name,
623 struct params *params, int paramwid,
624 struct params *rets)
626 if (gcc)
627 write_gcc_func_header(package, name, params, rets);
628 else
629 write_6g_func_header(package, name, params, paramwid, rets);
630 printf("#line %d \"%s\"\n", lineno, file);
633 /* Write out a function trailer. */
634 static void
635 write_func_trailer(char *package, char *name,
636 struct params *rets)
638 if (gcc)
639 write_gcc_func_trailer(package, name, rets);
640 else
641 write_6g_func_trailer(rets);
645 * Read and write the body of the function, ending in an unnested }
646 * (which is read but not written).
648 static void
649 copy_body(void)
651 int nesting = 0;
652 while (1) {
653 int c;
655 c = getchar_no_eof();
656 if (c == '}' && nesting == 0)
657 return;
658 putchar(c);
659 switch (c) {
660 default:
661 break;
662 case '{':
663 ++nesting;
664 break;
665 case '}':
666 --nesting;
667 break;
668 case '/':
669 c = getchar_update_lineno();
670 putchar(c);
671 if (c == '/') {
672 do {
673 c = getchar_no_eof();
674 putchar(c);
675 } while (c != '\n');
676 } else if (c == '*') {
677 while (1) {
678 c = getchar_no_eof();
679 putchar(c);
680 if (c == '*') {
681 do {
682 c = getchar_no_eof();
683 putchar(c);
684 } while (c == '*');
685 if (c == '/')
686 break;
690 break;
691 case '"':
692 case '\'':
694 int delim = c;
695 do {
696 c = getchar_no_eof();
697 putchar(c);
698 if (c == '\\') {
699 c = getchar_no_eof();
700 putchar(c);
701 c = '\0';
703 } while (c != delim);
705 break;
710 /* Process the entire file. */
711 static void
712 process_file(void)
714 char *package, *name;
715 struct params *params, *rets;
716 int paramwid;
718 package = read_package();
719 read_preprocessor_lines();
720 while (read_func_header(&name, &params, &paramwid, &rets)) {
721 write_func_header(package, name, params, paramwid, rets);
722 copy_body();
723 write_func_trailer(package, name, rets);
724 free(name);
725 free_params(params);
726 free_params(rets);
728 free(package);
731 static void
732 usage(void)
734 sysfatal("Usage: goc2c [--6g | --gc] [--go-pkgpath PKGPATH] [--go-prefix PREFIX] [file]\n");
737 void
738 main(int argc, char **argv)
740 char *goarch;
742 argv0 = argv[0];
743 while(argc > 1 && argv[1][0] == '-') {
744 if(strcmp(argv[1], "-") == 0)
745 break;
746 if(strcmp(argv[1], "--6g") == 0)
747 gcc = 0;
748 else if(strcmp(argv[1], "--gcc") == 0)
749 gcc = 1;
750 else if (strcmp(argv[1], "--go-pkgpath") == 0 && argc > 2) {
751 pkgpath = argv[2];
752 argc--;
753 argv++;
754 } else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
755 prefix = argv[2];
756 argc--;
757 argv++;
758 } else
759 usage();
760 argc--;
761 argv++;
764 if(argc <= 1 || strcmp(argv[1], "-") == 0) {
765 file = "<stdin>";
766 process_file();
767 exit(0);
770 if(argc > 2)
771 usage();
773 file = argv[1];
774 if(freopen(file, "r", stdin) == 0) {
775 sysfatal("open %s: %r\n", file);
778 if(!gcc) {
779 // 6g etc; update size table
780 goarch = getenv("GOARCH");
781 if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
782 type_table[Uintptr].size = 8;
783 type_table[String].size = 16;
784 type_table[Slice].size = 8+4+4;
785 type_table[Eface].size = 8+8;
786 structround = 8;
790 printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
791 process_file();
792 exit(0);