make godefs work better for generating Go.

R=r
DELTA=121  (92 added, 4 deleted, 25 changed)
OCL=29706
CL=29721
This commit is contained in:
Russ Cox 2009-06-01 22:14:25 -07:00
parent d7acfc75cd
commit 278b1ab053
3 changed files with 116 additions and 28 deletions

View file

@ -51,6 +51,7 @@ struct Type
int saved; // recorded in typ array
int warned; // warned about needing type
int printed; // has the definition been printed yet?
};
struct Field

View file

@ -85,13 +85,14 @@
void
usage(void)
{
fprint(2, "usage: godefs [-g] [-c cc] [-f cc-flag] defs.c\n");
fprint(2, "usage: godefs [-g package] [-c cc] [-f cc-flag] [defs.c ...]\n");
exit(1);
}
int gotypefmt(Fmt*);
int ctypefmt(Fmt*);
int prefixlen(Type*);
int cutprefix(char*);
Lang go =
{
@ -102,8 +103,8 @@ Lang go =
"type",
"type %s struct {\n",
"type %s union {\n", // not really, but readable
"\tpad%d [%d]byte;\n",
"type %s struct {\n",
"\tPad%d [%d]byte;\n",
"}\n",
gotypefmt,
@ -125,6 +126,8 @@ Lang c =
ctypefmt,
};
char *pkg;
int oargc;
char **oargv;
Lang *lang = &c;
@ -135,11 +138,17 @@ int ncon;
Type **typ;
int ntyp;
void
waitforgcc(void)
{
waitpid();
}
void
main(int argc, char **argv)
{
int p[2], pid, i, j, n, off, npad, prefix;
char *av[30], *q, *r, *tofree, *name;
char **av, *q, *r, *tofree, *name;
Biobuf *bin, *bout;
Type *t;
Field *f;
@ -148,33 +157,37 @@ main(int argc, char **argv)
oargc = argc;
oargv = argv;
av = emalloc((30+argc)*sizeof av[0]);
atexit(waitforgcc);
n = 0;
av[n++] = "gcc";
av[n++] = "-c";
av[n++] = "-fdollars-in-identifiers";
av[n++] = "-S"; // write assembly
av[n++] = "-gstabs"; // include stabs info
av[n++] = "-o-"; // to stdout
av[n++] = "-xc"; // read C
ARGBEGIN{
case 'g':
lang = &go;
pkg = EARGF(usage());
break;
case 'c':
av[0] = EARGF(usage());
break;
case 'f':
if(n+2 >= nelem(av))
sysfatal("too many -f options");
av[n++] = EARGF(usage());
break;
default:
usage();
}ARGEND
if(argc != 1)
usage();
av[n++] = argv[0];
if(argc == 0)
av[n++] = "-";
else
av[n++] = argv[0];
av[n] = nil;
// Run gcc writing assembly and stabs debugging to p[1].
@ -187,11 +200,28 @@ main(int argc, char **argv)
if(pid == 0) {
close(p[0]);
dup(p[1], 1);
if(argc == 0) {
exec(av[0], av);
fprint(2, "exec gcc: %r\n");
exit(1);
}
// Some versions of gcc do not accept -S with multiple files.
// Run gcc once for each file.
close(0);
open("/dev/null", OREAD);
exec(av[0], av);
fprint(2, "exec gcc: %r\n");
exit(1);
for(i=0; i<argc; i++) {
pid = fork();
if(pid < 0)
sysfatal("fork: %r");
if(pid == 0) {
av[n-1] = argv[i];
exec(av[0], av);
fprint(2, "exec gcc: %r\n");
exit(1);
}
waitpid();
}
exit(0);
}
close(p[1]);
@ -244,6 +274,9 @@ main(int argc, char **argv)
Bprint(bout, "// MACHINE GENERATED - DO NOT EDIT.\n");
Bprint(bout, "\n");
if(pkg)
Bprint(bout, "package %s\n\n", pkg);
// Constants.
Bprint(bout, "// Constants\n");
if(ncon > 0) {
@ -276,9 +309,25 @@ main(int argc, char **argv)
for(i=0; i<ntyp; i++) {
Bprint(bout, "\n");
t = typ[i];
while(t && t->kind == Typedef)
t = t->type;
name = t->name;
while(t && t->kind == Typedef) {
if(name == nil && t->name != nil) {
name = t->name;
if(t->printed)
break;
}
t = t->type;
}
if(name == nil && t->name != nil) {
name = t->name;
if(t->printed)
continue;
t->printed = 1;
}
if(name == nil) {
fprint(2, "unknown name for %T", typ[i]);
continue;
}
if(name[0] == '$')
name++;
npad = 0;
@ -293,10 +342,8 @@ main(int argc, char **argv)
Bprint(bout, "%s %lT\n", lang->typdef, name, t);
break;
case Union:
if(lang == &go) {
fprint(2, "%s: cannot emit unions in go\n", name);
continue;
}
// In Go, print union as struct with only first element,
// padded the rest of the way.
Bprint(bout, lang->unionbegin, name, name, name);
goto StructBody;
case Struct:
@ -308,7 +355,7 @@ main(int argc, char **argv)
for(j=0; j<t->nf; j++) {
f = &t->f[j];
// padding
if(t->kind == Struct) {
if(t->kind == Struct || lang == &go) {
if(f->offset%8 != 0 || f->size%8 != 0) {
fprint(2, "ignoring bitfield %s.%s\n", t->name, f->name);
continue;
@ -321,10 +368,15 @@ main(int argc, char **argv)
}
off += f->size;
}
Bprint(bout, "\t%lT;\n", f->name+prefix, f->type);
name = f->name;
if(cutprefix(name))
name += prefix;
Bprint(bout, "\t%lT;\n", name, f->type);
if(t->kind == Union && lang == &go)
break;
}
// final padding
if(t->kind == Struct) {
if(t->kind == Struct || lang == &go) {
if(off/8 < t->size)
Bprint(bout, lang->structpadfmt, npad++, t->size - off/8);
}
@ -444,13 +496,13 @@ gotypefmt(Fmt *f)
s = t->name;
if(s == nil) {
fprint(2, "need name for anonymous struct\n");
s = "STRUCT";
fmtprint(f, "STRUCT");
}
else if(s[0] != '$')
fprint(2, "need name for struct %s\n", s);
else
s++;
fmtprint(f, "%s", s);
else if(s[0] != '$') {
fprint(2, "warning: missing name for struct %s\n", s);
fmtprint(f, "[%d]byte /* %s */", t->size, s);
} else
fmtprint(f, "%s", s+1);
break;
case Array:
@ -471,6 +523,21 @@ gotypefmt(Fmt *f)
return 0;
}
// Is this the kind of name we should cut a prefix from?
// The rule is that the name cannot begin with underscore
// and must have an underscore eventually.
int
cutprefix(char *name)
{
char *p;
for(p=name; *p; p++) {
if(*p == '_')
return p-name > 0;
}
return 0;
}
// Figure out common struct prefix len
int
prefixlen(Type *t)
@ -484,6 +551,8 @@ prefixlen(Type *t)
name = nil;
for(i=0; i<t->nf; i++) {
f = &t->f[i];
if(!cutprefix(f->name))
continue;
p = strchr(f->name, '_');
if(p == nil)
return 0;

View file

@ -209,6 +209,7 @@ parsedef(char **pp, char *name)
t = emalloc(sizeof *t);
switch(*p) {
default:
fprint(2, "unknown type char %c\n", *p);
*pp = "";
return t;
@ -380,7 +381,24 @@ parsedef(char **pp, char *name)
}
break;
case 'x':
// reference to struct, union not yet defined.
p++;
switch(*p) {
case 's':
t->kind = Struct;
break;
case 'u':
t->kind = Union;
break;
default:
fprint(2, "unknown x type char x%c", *p);
*pp = "";
return t;
}
if(parsename(&p, &t->name) < 0)
return nil;
break;
}
*pp = p;
return t;