OSDN Git Service

log/syslog: Fix name of C function syslog_c.
[pf3gnuchains/gcc-fork.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 // +build ignore
6
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.
10  */
11
12 /*
13         package PACKAGENAME
14         {# line}
15         func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
16           C code with proper brace nesting
17         \}
18 */
19
20 /*
21  * We generate C code which implements the function such that it can
22  * be called from Go and executes the C code.
23  */
24
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>
32
33 /* Whether we're emitting for gcc */
34 static int gcc;
35
36 /* Package path to use; only meaningful for gcc */
37 static const char *pkgpath;
38
39 /* Package prefix to use; only meaningful for gcc */
40 static const char *prefix;
41
42 /* File and line number */
43 static const char *file;
44 static unsigned int lineno = 1;
45
46 /* List of names and types.  */
47 struct params {
48         struct params *next;
49         char *name;
50         char *type;
51 };
52
53 /* index into type_table */
54 enum {
55         Bool,
56         Float,
57         Int,
58         Uint,
59         Uintptr,
60         String,
61         Slice,
62         Eface,
63 };
64
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,
80
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,
93
94         NULL,
95 };
96
97 /* Fixed structure alignment (non-gcc only) */
98 int structround = 4;
99
100 char *argv0;
101
102 static void
103 sysfatal(char *fmt, ...)
104 {
105         char buf[256];
106         va_list arg;
107
108         va_start(arg, fmt);
109         vsnprintf(buf, sizeof buf, fmt, arg);
110         va_end(arg);
111
112         fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
113         exit(1);
114 }
115
116 /* Unexpected EOF.  */
117 static void
118 bad_eof(void)
119 {
120         sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
121 }
122
123 /* Out of memory.  */
124 static void
125 bad_mem(void)
126 {
127         sysfatal("%s:%ud: out of memory\n", file, lineno);
128 }
129
130 /* Allocate memory without fail.  */
131 static void *
132 xmalloc(unsigned int size)
133 {
134         void *ret = malloc(size);
135         if (ret == NULL)
136                 bad_mem();
137         return ret;
138 }
139
140 /* Reallocate memory without fail.  */
141 static void*
142 xrealloc(void *buf, unsigned int size)
143 {
144         void *ret = realloc(buf, size);
145         if (ret == NULL)
146                 bad_mem();
147         return ret;
148 }
149
150 /* Free a list of parameters.  */
151 static void
152 free_params(struct params *p)
153 {
154         while (p != NULL) {
155                 struct params *next;
156
157                 next = p->next;
158                 free(p->name);
159                 free(p->type);
160                 free(p);
161                 p = next;
162         }
163 }
164
165 /* Read a character, tracking lineno.  */
166 static int
167 getchar_update_lineno(void)
168 {
169         int c;
170
171         c = getchar();
172         if (c == '\n')
173                 ++lineno;
174         return c;
175 }
176
177 /* Read a character, giving an error on EOF, tracking lineno.  */
178 static int
179 getchar_no_eof(void)
180 {
181         int c;
182
183         c = getchar_update_lineno();
184         if (c == EOF)
185                 bad_eof();
186         return c;
187 }
188
189 /* Read a character, skipping comments.  */
190 static int
191 getchar_skipping_comments(void)
192 {
193         int c;
194
195         while (1) {
196                 c = getchar_update_lineno();
197                 if (c != '/')
198                         return c;
199
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;
217                                 }
218                         }
219                 } else {
220                         ungetc(c, stdin);
221                         return '/';
222                 }
223         }
224 }
225
226 /*
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.
230  */
231 static char *
232 read_token(void)
233 {
234         int c, q;
235         char *buf;
236         unsigned int alc, off;
237         const char* delims = "(),{}";
238
239         while (1) {
240                 c = getchar_skipping_comments();
241                 if (c == EOF)
242                         return NULL;
243                 if (!isspace(c))
244                         break;
245         }
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);
257                         }
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;
266                         }
267                 }
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);
276                         }
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;
287                         }
288                 }
289         }
290         buf[off] = '\0';
291         return buf;
292 }
293
294 /* Read a token, giving an error on EOF.  */
295 static char *
296 read_token_no_eof(void)
297 {
298         char *token = read_token();
299         if (token == NULL)
300                 bad_eof();
301         return token;
302 }
303
304 /* Read the package clause, and return the package name.  */
305 static char *
306 read_package(void)
307 {
308         char *token;
309
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);
316         }
317         return read_token_no_eof();
318 }
319
320 /* Read and copy preprocessor lines.  */
321 static void
322 read_preprocessor_lines(void)
323 {
324         while (1) {
325                 int c;
326
327                 do {
328                         c = getchar_skipping_comments();
329                 } while (isspace(c));
330                 if (c != '#') {
331                         ungetc(c, stdin);
332                         break;
333                 }
334                 putchar(c);
335                 do {
336                         c = getchar_update_lineno();
337                         putchar(c);
338                 } while (c != '\n');
339         }
340 }
341
342 /*
343  * Read a type in Go syntax and return a type in C syntax.  We only
344  * permit basic types and pointers.
345  */
346 static char *
347 read_type(void)
348 {
349         char *p, *op, *q;
350         int pointer_count;
351         unsigned int len;
352
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;
361         }
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;
369         }
370         q[len] = '\0';
371         free(op);
372         return q;
373 }
374
375 /* Return the size of the given type. */
376 static int
377 type_size(char *p)
378 {
379         int i;
380
381         if(p[strlen(p)-1] == '*')
382                 return type_table[Uintptr].size;
383
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);
389         }
390         return 1;
391 }
392
393 /*
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 '('.
396  */
397 static struct params *
398 read_params(int *poffset)
399 {
400         char *token;
401         struct params *ret, **pp, *p;
402         int offset, size, rnd;
403
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;
416
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;
424
425                         token = read_token_no_eof();
426                         if (strcmp(token, ",") != 0)
427                                 break;
428                         token = read_token_no_eof();
429                 }
430         }
431         if (strcmp(token, ")") != 0) {
432                 sysfatal("%s:%ud: expected '('\n",
433                         file, lineno);
434         }
435         if (poffset != NULL)
436                 *poffset = offset;
437         return ret;
438 }
439
440 /*
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.
443  */
444 static int
445 read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
446 {
447         int lastline;
448         char *token;
449
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;
459                 }
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;
466                 }
467                 printf("%s ", token);
468         }
469
470         *name = read_token_no_eof();
471
472         token = read_token();
473         if (token == NULL || strcmp(token, "(") != 0) {
474                 sysfatal("%s:%ud: expected \"(\"\n",
475                         file, lineno);
476         }
477         *params = read_params(paramwid);
478
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();
485         }
486         if (token == NULL || strcmp(token, "{") != 0) {
487                 sysfatal("%s:%ud: expected \"{\"\n",
488                         file, lineno);
489         }
490         return 1;
491 }
492
493 /* Write out parameters.  */
494 static void
495 write_params(struct params *params, int *first)
496 {
497         struct params *p;
498
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);
505         }
506 }
507
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)
512 {
513         int first, n;
514
515         printf("void\n%s·%s(", package, name);
516         first = 1;
517         write_params(params, &first);
518
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");
528         }
529
530         write_params(rets, &first);
531         printf(")\n{\n");
532 }
533
534 /* Write a 6g function trailer.  */
535 static void
536 write_6g_func_trailer(struct params *rets)
537 {
538         struct params *p;
539
540         for (p = rets; p != NULL; p = p->next)
541                 printf("\tFLUSH(&%s);\n", p->name);
542         printf("}\n");
543 }
544
545 /* Define the gcc function return type if necessary.  */
546 static void
547 define_gcc_return_type(char *package, char *name, struct params *rets)
548 {
549         struct params *p;
550
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");
557 }
558
559 /* Write out the gcc function return type.  */
560 static void
561 write_gcc_return_type(char *package, char *name, struct params *rets)
562 {
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);
569 }
570
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)
575 {
576         int first;
577         struct params *p;
578
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);
599 }
600
601 /* Write out a gcc function trailer.  */
602 static void
603 write_gcc_func_trailer(char *package, char *name, struct params *rets)
604 {
605         if (rets == NULL)
606                 ;
607         else if (rets->next == NULL)
608                 printf("return %s;\n", rets->name);
609         else {
610                 struct params *p;
611
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");
616         }
617         printf("}\n");
618 }
619
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)
625 {
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);
631 }
632
633 /* Write out a function trailer.  */
634 static void
635 write_func_trailer(char *package, char *name,
636                    struct params *rets)
637 {
638         if (gcc)
639                 write_gcc_func_trailer(package, name, rets);
640         else
641                 write_6g_func_trailer(rets);
642 }
643
644 /*
645  * Read and write the body of the function, ending in an unnested }
646  * (which is read but not written).
647  */
648 static void
649 copy_body(void)
650 {
651         int nesting = 0;
652         while (1) {
653                 int c;
654
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;
687                                         }
688                                 }
689                         }
690                         break;
691                 case '"':
692                 case '\'':
693                         {
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';
702                                         }
703                                 } while (c != delim);
704                         }
705                         break;
706                 }
707         }
708 }
709
710 /* Process the entire file.  */
711 static void
712 process_file(void)
713 {
714         char *package, *name;
715         struct params *params, *rets;
716         int paramwid;
717
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);
727         }
728         free(package);
729 }
730
731 static void
732 usage(void)
733 {
734         sysfatal("Usage: goc2c [--6g | --gc] [--go-pkgpath PKGPATH] [--go-prefix PREFIX] [file]\n");
735 }
736
737 void
738 main(int argc, char **argv)
739 {
740         char *goarch;
741
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++;
762         }
763
764         if(argc <= 1 || strcmp(argv[1], "-") == 0) {
765                 file = "<stdin>";
766                 process_file();
767                 exit(0);
768         }
769
770         if(argc > 2)
771                 usage();
772
773         file = argv[1];
774         if(freopen(file, "r", stdin) == 0) {
775                 sysfatal("open %s: %r\n", file);
776         }
777
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;
787                 }
788         }
789
790         printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
791         process_file();
792         exit(0);
793 }