Fix r180999.
[gcc.git] / libgo / runtime / goc2c.c
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.
4
5 /*
6 * Translate a .goc file into a .c file. A .goc file is a combination
7 * of a limited form of Go with C.
8 */
9
10 /*
11 package PACKAGENAME
12 {# line}
13 func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
14 C code with proper brace nesting
15 \}
16 */
17
18 /*
19 * We generate C code which implements the function such that it can
20 * be called from Go and executes the C code.
21 */
22
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 /* Whether we're emitting for gcc */
32 static int gcc;
33
34 /* Package prefix to use; only meaningful for gcc */
35 static const char *prefix;
36
37 /* File and line number */
38 static const char *file;
39 static unsigned int lineno = 1;
40
41 /* List of names and types. */
42 struct params {
43 struct params *next;
44 char *name;
45 char *type;
46 };
47
48 /* index into type_table */
49 enum {
50 Bool,
51 Float,
52 Int,
53 Uint,
54 Uintptr,
55 String,
56 Slice,
57 Eface,
58 };
59
60 static struct {
61 char *name;
62 int size;
63 } type_table[] = {
64 /* variable sized first, for easy replacement */
65 /* order matches enum above */
66 /* default is 32-bit architecture sizes */
67 "bool", 1,
68 "float", 4,
69 "int", 4,
70 "uint", 4,
71 "uintptr", 4,
72 "String", 8,
73 "Slice", 12,
74 "Eface", 8,
75
76 /* fixed size */
77 "float32", 4,
78 "float64", 8,
79 "byte", 1,
80 "int8", 1,
81 "uint8", 1,
82 "int16", 2,
83 "uint16", 2,
84 "int32", 4,
85 "uint32", 4,
86 "int64", 8,
87 "uint64", 8,
88
89 NULL,
90 };
91
92 /* Fixed structure alignment (non-gcc only) */
93 int structround = 4;
94
95 char *argv0;
96
97 static void
98 sysfatal(char *fmt, ...)
99 {
100 char buf[256];
101 va_list arg;
102
103 va_start(arg, fmt);
104 vsnprintf(buf, sizeof buf, fmt, arg);
105 va_end(arg);
106
107 fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
108 exit(1);
109 }
110
111 /* Unexpected EOF. */
112 static void
113 bad_eof(void)
114 {
115 sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
116 }
117
118 /* Out of memory. */
119 static void
120 bad_mem(void)
121 {
122 sysfatal("%s:%ud: out of memory\n", file, lineno);
123 }
124
125 /* Allocate memory without fail. */
126 static void *
127 xmalloc(unsigned int size)
128 {
129 void *ret = malloc(size);
130 if (ret == NULL)
131 bad_mem();
132 return ret;
133 }
134
135 /* Reallocate memory without fail. */
136 static void*
137 xrealloc(void *buf, unsigned int size)
138 {
139 void *ret = realloc(buf, size);
140 if (ret == NULL)
141 bad_mem();
142 return ret;
143 }
144
145 /* Free a list of parameters. */
146 static void
147 free_params(struct params *p)
148 {
149 while (p != NULL) {
150 struct params *next;
151
152 next = p->next;
153 free(p->name);
154 free(p->type);
155 free(p);
156 p = next;
157 }
158 }
159
160 /* Read a character, tracking lineno. */
161 static int
162 getchar_update_lineno(void)
163 {
164 int c;
165
166 c = getchar();
167 if (c == '\n')
168 ++lineno;
169 return c;
170 }
171
172 /* Read a character, giving an error on EOF, tracking lineno. */
173 static int
174 getchar_no_eof(void)
175 {
176 int c;
177
178 c = getchar_update_lineno();
179 if (c == EOF)
180 bad_eof();
181 return c;
182 }
183
184 /* Read a character, skipping comments. */
185 static int
186 getchar_skipping_comments(void)
187 {
188 int c;
189
190 while (1) {
191 c = getchar_update_lineno();
192 if (c != '/')
193 return c;
194
195 c = getchar();
196 if (c == '/') {
197 do {
198 c = getchar_update_lineno();
199 } while (c != EOF && c != '\n');
200 return c;
201 } else if (c == '*') {
202 while (1) {
203 c = getchar_update_lineno();
204 if (c == EOF)
205 return EOF;
206 if (c == '*') {
207 do {
208 c = getchar_update_lineno();
209 } while (c == '*');
210 if (c == '/')
211 break;
212 }
213 }
214 } else {
215 ungetc(c, stdin);
216 return '/';
217 }
218 }
219 }
220
221 /*
222 * Read and return a token. Tokens are string or character literals
223 * or else delimited by whitespace or by [(),{}].
224 * The latter are all returned as single characters.
225 */
226 static char *
227 read_token(void)
228 {
229 int c, q;
230 char *buf;
231 unsigned int alc, off;
232 const char* delims = "(),{}";
233
234 while (1) {
235 c = getchar_skipping_comments();
236 if (c == EOF)
237 return NULL;
238 if (!isspace(c))
239 break;
240 }
241 alc = 16;
242 buf = xmalloc(alc + 1);
243 off = 0;
244 if(c == '"' || c == '\'') {
245 q = c;
246 buf[off] = c;
247 ++off;
248 while (1) {
249 if (off+2 >= alc) { // room for c and maybe next char
250 alc *= 2;
251 buf = xrealloc(buf, alc + 1);
252 }
253 c = getchar_no_eof();
254 buf[off] = c;
255 ++off;
256 if(c == q)
257 break;
258 if(c == '\\') {
259 buf[off] = getchar_no_eof();
260 ++off;
261 }
262 }
263 } else if (strchr(delims, c) != NULL) {
264 buf[off] = c;
265 ++off;
266 } else {
267 while (1) {
268 if (off >= alc) {
269 alc *= 2;
270 buf = xrealloc(buf, alc + 1);
271 }
272 buf[off] = c;
273 ++off;
274 c = getchar_skipping_comments();
275 if (c == EOF)
276 break;
277 if (isspace(c) || strchr(delims, c) != NULL) {
278 if (c == '\n')
279 lineno--;
280 ungetc(c, stdin);
281 break;
282 }
283 }
284 }
285 buf[off] = '\0';
286 return buf;
287 }
288
289 /* Read a token, giving an error on EOF. */
290 static char *
291 read_token_no_eof(void)
292 {
293 char *token = read_token();
294 if (token == NULL)
295 bad_eof();
296 return token;
297 }
298
299 /* Read the package clause, and return the package name. */
300 static char *
301 read_package(void)
302 {
303 char *token;
304
305 token = read_token_no_eof();
306 if (token == NULL)
307 sysfatal("%s:%ud: no token\n", file, lineno);
308 if (strcmp(token, "package") != 0) {
309 sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
310 file, lineno, token);
311 }
312 return read_token_no_eof();
313 }
314
315 /* Read and copy preprocessor lines. */
316 static void
317 read_preprocessor_lines(void)
318 {
319 while (1) {
320 int c;
321
322 do {
323 c = getchar_skipping_comments();
324 } while (isspace(c));
325 if (c != '#') {
326 ungetc(c, stdin);
327 break;
328 }
329 putchar(c);
330 do {
331 c = getchar_update_lineno();
332 putchar(c);
333 } while (c != '\n');
334 }
335 }
336
337 /*
338 * Read a type in Go syntax and return a type in C syntax. We only
339 * permit basic types and pointers.
340 */
341 static char *
342 read_type(void)
343 {
344 char *p, *op, *q;
345 int pointer_count;
346 unsigned int len;
347
348 p = read_token_no_eof();
349 if (*p != '*')
350 return p;
351 op = p;
352 pointer_count = 0;
353 while (*p == '*') {
354 ++pointer_count;
355 ++p;
356 }
357 len = strlen(p);
358 q = xmalloc(len + pointer_count + 1);
359 memcpy(q, p, len);
360 while (pointer_count > 0) {
361 q[len] = '*';
362 ++len;
363 --pointer_count;
364 }
365 q[len] = '\0';
366 free(op);
367 return q;
368 }
369
370 /* Return the size of the given type. */
371 static int
372 type_size(char *p)
373 {
374 int i;
375
376 if(p[strlen(p)-1] == '*')
377 return type_table[Uintptr].size;
378
379 for(i=0; type_table[i].name; i++)
380 if(strcmp(type_table[i].name, p) == 0)
381 return type_table[i].size;
382 if(!gcc) {
383 sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
384 }
385 return 1;
386 }
387
388 /*
389 * Read a list of parameters. Each parameter is a name and a type.
390 * The list ends with a ')'. We have already read the '('.
391 */
392 static struct params *
393 read_params(int *poffset)
394 {
395 char *token;
396 struct params *ret, **pp, *p;
397 int offset, size, rnd;
398
399 ret = NULL;
400 pp = &ret;
401 token = read_token_no_eof();
402 offset = 0;
403 if (strcmp(token, ")") != 0) {
404 while (1) {
405 p = xmalloc(sizeof(struct params));
406 p->name = token;
407 p->type = read_type();
408 p->next = NULL;
409 *pp = p;
410 pp = &p->next;
411
412 size = type_size(p->type);
413 rnd = size;
414 if(rnd > structround)
415 rnd = structround;
416 if(offset%rnd)
417 offset += rnd - offset%rnd;
418 offset += size;
419
420 token = read_token_no_eof();
421 if (strcmp(token, ",") != 0)
422 break;
423 token = read_token_no_eof();
424 }
425 }
426 if (strcmp(token, ")") != 0) {
427 sysfatal("%s:%ud: expected '('\n",
428 file, lineno);
429 }
430 if (poffset != NULL)
431 *poffset = offset;
432 return ret;
433 }
434
435 /*
436 * Read a function header. This reads up to and including the initial
437 * '{' character. Returns 1 if it read a header, 0 at EOF.
438 */
439 static int
440 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
441 {
442 int lastline;
443 char *token;
444
445 lastline = -1;
446 while (1) {
447 token = read_token();
448 if (token == NULL)
449 return 0;
450 if (strcmp(token, "func") == 0) {
451 if(lastline != -1)
452 printf("\n");
453 break;
454 }
455 if (lastline != lineno) {
456 if (lastline == lineno-1)
457 printf("\n");
458 else
459 printf("\n#line %d \"%s\"\n", lineno, file);
460 lastline = lineno;
461 }
462 printf("%s ", token);
463 }
464
465 *name = read_token_no_eof();
466
467 token = read_token();
468 if (token == NULL || strcmp(token, "(") != 0) {
469 sysfatal("%s:%ud: expected \"(\"\n",
470 file, lineno);
471 }
472 *params = read_params(paramwid);
473
474 token = read_token();
475 if (token == NULL || strcmp(token, "(") != 0)
476 *rets = NULL;
477 else {
478 *rets = read_params(NULL);
479 token = read_token();
480 }
481 if (token == NULL || strcmp(token, "{") != 0) {
482 sysfatal("%s:%ud: expected \"{\"\n",
483 file, lineno);
484 }
485 return 1;
486 }
487
488 /* Write out parameters. */
489 static void
490 write_params(struct params *params, int *first)
491 {
492 struct params *p;
493
494 for (p = params; p != NULL; p = p->next) {
495 if (*first)
496 *first = 0;
497 else
498 printf(", ");
499 printf("%s %s", p->type, p->name);
500 }
501 }
502
503 /* Write a 6g function header. */
504 static void
505 write_6g_func_header(char *package, char *name, struct params *params,
506 int paramwid, struct params *rets)
507 {
508 int first, n;
509
510 printf("void\n%s·%s(", package, name);
511 first = 1;
512 write_params(params, &first);
513
514 /* insert padding to align output struct */
515 if(rets != NULL && paramwid%structround != 0) {
516 n = structround - paramwid%structround;
517 if(n & 1)
518 printf(", uint8");
519 if(n & 2)
520 printf(", uint16");
521 if(n & 4)
522 printf(", uint32");
523 }
524
525 write_params(rets, &first);
526 printf(")\n{\n");
527 }
528
529 /* Write a 6g function trailer. */
530 static void
531 write_6g_func_trailer(struct params *rets)
532 {
533 struct params *p;
534
535 for (p = rets; p != NULL; p = p->next)
536 printf("\tFLUSH(&%s);\n", p->name);
537 printf("}\n");
538 }
539
540 /* Define the gcc function return type if necessary. */
541 static void
542 define_gcc_return_type(char *package, char *name, struct params *rets)
543 {
544 struct params *p;
545
546 if (rets == NULL || rets->next == NULL)
547 return;
548 printf("struct %s_%s_ret {\n", package, name);
549 for (p = rets; p != NULL; p = p->next)
550 printf(" %s %s;\n", p->type, p->name);
551 printf("};\n");
552 }
553
554 /* Write out the gcc function return type. */
555 static void
556 write_gcc_return_type(char *package, char *name, struct params *rets)
557 {
558 if (rets == NULL)
559 printf("void");
560 else if (rets->next == NULL)
561 printf("%s", rets->type);
562 else
563 printf("struct %s_%s_ret", package, name);
564 }
565
566 /* Write out a gcc function header. */
567 static void
568 write_gcc_func_header(char *package, char *name, struct params *params,
569 struct params *rets)
570 {
571 int first;
572 struct params *p;
573
574 define_gcc_return_type(package, name, rets);
575 write_gcc_return_type(package, name, rets);
576 printf(" %s_%s(", package, name);
577 first = 1;
578 write_params(params, &first);
579 printf(") asm (\"");
580 if (prefix != NULL)
581 printf("%s.", prefix);
582 printf("%s.%s\");\n", package, name);
583 write_gcc_return_type(package, name, rets);
584 printf(" %s_%s(", package, name);
585 first = 1;
586 write_params(params, &first);
587 printf(")\n{\n");
588 for (p = rets; p != NULL; p = p->next)
589 printf(" %s %s;\n", p->type, p->name);
590 }
591
592 /* Write out a gcc function trailer. */
593 static void
594 write_gcc_func_trailer(char *package, char *name, struct params *rets)
595 {
596 if (rets == NULL)
597 ;
598 else if (rets->next == NULL)
599 printf("return %s;\n", rets->name);
600 else {
601 struct params *p;
602
603 printf(" {\n struct %s_%s_ret __ret;\n", package, name);
604 for (p = rets; p != NULL; p = p->next)
605 printf(" __ret.%s = %s;\n", p->name, p->name);
606 printf(" return __ret;\n }\n");
607 }
608 printf("}\n");
609 }
610
611 /* Write out a function header. */
612 static void
613 write_func_header(char *package, char *name,
614 struct params *params, int paramwid,
615 struct params *rets)
616 {
617 if (gcc)
618 write_gcc_func_header(package, name, params, rets);
619 else
620 write_6g_func_header(package, name, params, paramwid, rets);
621 printf("#line %d \"%s\"\n", lineno, file);
622 }
623
624 /* Write out a function trailer. */
625 static void
626 write_func_trailer(char *package, char *name,
627 struct params *rets)
628 {
629 if (gcc)
630 write_gcc_func_trailer(package, name, rets);
631 else
632 write_6g_func_trailer(rets);
633 }
634
635 /*
636 * Read and write the body of the function, ending in an unnested }
637 * (which is read but not written).
638 */
639 static void
640 copy_body(void)
641 {
642 int nesting = 0;
643 while (1) {
644 int c;
645
646 c = getchar_no_eof();
647 if (c == '}' && nesting == 0)
648 return;
649 putchar(c);
650 switch (c) {
651 default:
652 break;
653 case '{':
654 ++nesting;
655 break;
656 case '}':
657 --nesting;
658 break;
659 case '/':
660 c = getchar_update_lineno();
661 putchar(c);
662 if (c == '/') {
663 do {
664 c = getchar_no_eof();
665 putchar(c);
666 } while (c != '\n');
667 } else if (c == '*') {
668 while (1) {
669 c = getchar_no_eof();
670 putchar(c);
671 if (c == '*') {
672 do {
673 c = getchar_no_eof();
674 putchar(c);
675 } while (c == '*');
676 if (c == '/')
677 break;
678 }
679 }
680 }
681 break;
682 case '"':
683 case '\'':
684 {
685 int delim = c;
686 do {
687 c = getchar_no_eof();
688 putchar(c);
689 if (c == '\\') {
690 c = getchar_no_eof();
691 putchar(c);
692 c = '\0';
693 }
694 } while (c != delim);
695 }
696 break;
697 }
698 }
699 }
700
701 /* Process the entire file. */
702 static void
703 process_file(void)
704 {
705 char *package, *name;
706 struct params *params, *rets;
707 int paramwid;
708
709 package = read_package();
710 read_preprocessor_lines();
711 while (read_func_header(&name, &params, &paramwid, &rets)) {
712 write_func_header(package, name, params, paramwid, rets);
713 copy_body();
714 write_func_trailer(package, name, rets);
715 free(name);
716 free_params(params);
717 free_params(rets);
718 }
719 free(package);
720 }
721
722 static void
723 usage(void)
724 {
725 sysfatal("Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
726 }
727
728 void
729 main(int argc, char **argv)
730 {
731 char *goarch;
732
733 argv0 = argv[0];
734 while(argc > 1 && argv[1][0] == '-') {
735 if(strcmp(argv[1], "-") == 0)
736 break;
737 if(strcmp(argv[1], "--6g") == 0)
738 gcc = 0;
739 else if(strcmp(argv[1], "--gcc") == 0)
740 gcc = 1;
741 else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
742 prefix = argv[2];
743 argc--;
744 argv++;
745 } else
746 usage();
747 argc--;
748 argv++;
749 }
750
751 if(argc <= 1 || strcmp(argv[1], "-") == 0) {
752 file = "<stdin>";
753 process_file();
754 exit(0);
755 }
756
757 if(argc > 2)
758 usage();
759
760 file = argv[1];
761 if(freopen(file, "r", stdin) == 0) {
762 sysfatal("open %s: %r\n", file);
763 }
764
765 if(!gcc) {
766 // 6g etc; update size table
767 goarch = getenv("GOARCH");
768 if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
769 type_table[Uintptr].size = 8;
770 type_table[String].size = 16;
771 type_table[Slice].size = 8+4+4;
772 type_table[Eface].size = 8+8;
773 structround = 8;
774 }
775 }
776
777 process_file();
778 exit(0);
779 }