summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2015-09-15 00:10:18 -0700
committerOri Bernstein <ori@eigenstate.org>2015-09-15 00:12:29 -0700
commit3c348076e792369472ec5c01a9c81e22440eb488 (patch)
tree071ebd31b50f7fb2f8cb78308e40aac8c26c2fa2
parente755da348db4af9ee68510a6b8aea6e1db40ede3 (diff)
downloadmcbind-3c348076e792369472ec5c01a9c81e22440eb488.tar.gz
Get closer to generating valid C glue.
-rw-r--r--cgen.c184
-rw-r--r--cparse.c277
-rw-r--r--main.c25
-rw-r--r--mcbind.h84
-rw-r--r--myrgen.c130
-rw-r--r--optctx.c1
-rw-r--r--util.c24
-rw-r--r--util.h37
8 files changed, 736 insertions, 26 deletions
diff --git a/cgen.c b/cgen.c
new file mode 100644
index 0000000..b59d352
--- /dev/null
+++ b/cgen.c
@@ -0,0 +1,184 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "mcbind.h"
+
+void writecdecl(FILE *fd, Type *ty, char *name)
+{
+ size_t i;
+ char *sep;
+ char buf[64];
+
+ switch (ty->type) {
+ case Tynone: die("invalid type\n"); break;
+
+ case Tyvoid: fprintf(fd, "void"); break;
+ case Tybool: fprintf(fd, "bool %s", name); break;
+ case Tychar: fprintf(fd, "uint32_t %s", name); break;
+
+ case Tyint8: fprintf(fd, "int8_t %s", name); break;
+ case Tyint16: fprintf(fd, "int16_t %s", name); break;
+ case Tyint: fprintf(fd, "int32_t %s", name); break;
+ case Tyint32: fprintf(fd, "int32_t %s", name); break;
+ case Tyint64: fprintf(fd, "int64_t %s", name); break;
+ case Tylong: fprintf(fd, "int64_t %s", name); break;
+
+ case Tybyte: fprintf(fd, "uint8_t %s", name); break;
+ case Tyuint8: fprintf(fd, "uint8_t %s", name); break;
+ case Tyuint16: fprintf(fd, "uint16_t %s", name); break;
+ case Tyuint: fprintf(fd, "uint8_t %s", name); break;
+ case Tyuint32: fprintf(fd, "uint32_t %s", name); break;
+ case Tyuint64: fprintf(fd, "uint64_t %s", name); break;
+ case Tyulong: fprintf(fd, "uint64_t %s", name); break;
+
+ case Tyflt32: fprintf(fd, "float %s", name); break;
+ case Tyflt64: fprintf(fd, "double %s", name); break;
+
+ case Typtr:
+ fprintf(fd, "(*");
+ writecdecl(fd, ty->sub[0], "");
+ fprintf(fd, ")");
+ break;
+
+ case Tyfunc:
+ writecdecl(fd, ty->sub[0], "");
+ fprintf(fd, " %s(", name);
+ sep = "";
+ for (i = 0; i < ty->nsub - 1; i++) {
+ fprintf(fd, "%s", sep);
+ if (ty->subname[i]) {
+ writecdecl(fd, ty->sub[i], ty->subname[i]);
+ } else {
+ snprintf(buf, sizeof buf, "a%zd", i);
+ writecdecl(fd, ty->sub[i], buf);
+ }
+ sep = ", ";
+ }
+ fprintf(fd, ")");
+ break;
+
+ case Tyarray:
+ writecdecl(fd, ty->sub[0], name);
+ if (ty->arraysz)
+ fprintf(fd, "[%zd]", ty->arraysz);
+ else
+ fprintf(fd, "[]");
+ break;
+ case Tystruct:
+ fprintf(fd, "struct %s {\n", name);
+ for (i = 0; i < ty->nsub; i++) {
+ writecdecl(fd, ty->sub[i], ty->subname[i]);
+ fprintf(fd, "\n");
+ }
+ fprintf(fd, "}");
+ break;
+ case Tyunion:
+ fprintf(fd, "union %s {\n", name);
+ for (i = 0; i < ty->nsub; i++) {
+ writecdecl(fd, ty->sub[i], ty->subname[i]);
+ fprintf(fd, ";\n");
+ }
+ fprintf(fd, "}");
+ break;
+ case Tyname:
+ fprintf(fd, "typedef ");
+ writecdecl(fd, ty->sub[0], ty->defname);
+ break;
+ case Tyopaque:
+ fprintf(fd, "/*opaque %s: */byte[%zd]", ty->defname, ty->arraysz);
+ break;
+ }
+}
+
+void writewrapper(FILE *fd, Dcl *dcl)
+{
+ char buf[64];
+ char *sep;
+ Type *ty;
+ size_t i;
+
+ ty = dcl->type;
+ fprintf(fd, "{\n");
+
+ fprintf(fd, "\t");
+ if (ty->sub[0]->type != Tyvoid)
+ fprintf(fd, "return ");
+
+ fprintf(fd, "%s(", dcl->name);
+ sep = "";
+ for (i = 0; i < ty->nsub - 1; i++) {
+ if (ty->subname[i]) {
+ fprintf(fd, "%s%s", sep, ty->subname[i]);
+ } else {
+ snprintf(buf, sizeof buf, "a%zd", i);
+ fprintf(fd, "%s%s", sep, buf);
+ }
+ sep = ", ";
+ }
+ fprintf(fd, ");\n");
+ fprintf(fd, "}\n");
+}
+
+void aliasdecl(FILE *fd, Dcl *dcl, char *pkg)
+{
+ char buf[512];
+ snprintf(buf, sizeof buf, "%s$%s", pkg, dcl->name);
+
+ writecdecl(fd, dcl->type, buf);
+ fprintf(fd, "__attribute__((weak, alias(%s)))", dcl->name);
+}
+
+void funcdcl(FILE *fd, Dcl *dcl, char *pkg)
+{
+ char buf[512];
+
+ snprintf(buf, sizeof buf, "%s$%s", pkg, dcl->name);
+ writecdecl(fd, dcl->type, buf);
+ fprintf(fd, "\n");
+ writewrapper(fd, dcl);
+}
+
+void writecdcl(FILE *fd, Dcl *dcl, char *pkg)
+{
+ if (dcl->type->type == Tyfunc)
+ funcdcl(fd, dcl, pkg);
+ else
+ aliasdecl(fd, dcl, pkg);
+}
+
+void writeheaders(FILE *fd)
+{
+ size_t i;
+
+ fprintf(fd, "/*\n");
+ fprintf(fd, "This file is generated by the Myrddin C binding generator.\n");
+ fprintf(fd, "Unless you like having your work clobbered, I would suggest\n");
+ fprintf(fd, "that you edit elsewhere\n");
+ fprintf(fd, "*/\n\n");
+ fprintf(fd, "#include <stdint.h>\n");
+ fprintf(fd, "#include <stddef.h>\n");
+ for (i = 0; i < binding.nhdr; i++) {
+ fprintf(fd, "#include <%s>\n", binding.hdr[i]);
+ }
+ fprintf(fd, "\n");
+}
+
+void gluegen(char *hdr)
+{
+ char out[512];
+ size_t i;
+ FILE *fd;
+
+ swapsuffix(out, sizeof out, hdr, ".h", "-glue.c");
+ fd = fopen(out, "w");
+ writeheaders(fd);
+
+ for (i = 0; i < binding.ndcl; i++) {
+ writecdcl(fd, binding.dcl[i], binding.pkg);
+ }
+ fclose(fd);
+}
diff --git a/cparse.c b/cparse.c
index f04faf0..170e75f 100644
--- a/cparse.c
+++ b/cparse.c
@@ -1,45 +1,314 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <string.h>
+#include <assert.h>
#include <clang-c/Index.h>
#include "util.h"
#include "mcbind.h"
+Type *gettype(CXType t);
+
+Dcl *mkdcl(char *cname, Type *type, int isconst)
+{
+ Dcl *dcl;
+
+ dcl = zalloc(sizeof(Dcl));
+ dcl->isconst = 1;
+ dcl->name = cname; /* FIXME: should transform the name. */
+ dcl->cname = cname;
+ dcl->type = type;
+ return dcl;
+}
+
void initargs(char ***args, size_t *nargs, char *f)
{
*args = NULL;
*nargs = 0;
lappend(args, nargs, "-I/usr/include");
+ lappend(args, nargs, "-I.");
lappend(args, nargs, f);
}
-enum CXChildVisitResult dumpdcls(CXCursor c, CXCursor pc, CXClientData d)
+char *striptype(const char *s)
+{
+ if (strstr(s, "struct ") == s)
+ return strdup(s + strlen("struct "));
+ else if (strstr(s, "union ") == s)
+ return strdup(s + strlen("union "));
+ else
+ return strdup(s);
+}
+
+enum CXChildVisitResult
+addmembers(CXCursor c, CXCursor pc, CXClientData d)
+{
+ CXString str, dname;
+ CXType mtype;
+ Type *ty, *mty;
+ char *name;
+
+ if (clang_getCursorKind(c) != CXCursor_FieldDecl) {
+ str = clang_getCursorSpelling(c);
+ printf("%s is not a member\n", clang_getCString(str));
+ clang_disposeString(str);
+ return CXChildVisit_Continue;
+ }
+
+ ty = d;
+ mtype = clang_getCursorType(c);
+ dname = clang_getCursorSpelling(c);
+ name = strdup(clang_getCString(dname));
+ mty = gettype(mtype);
+ lappend(&ty->sub, &ty->nsub, mty);
+ lappend(&ty->subname, &ty->nsubname, name);
+ return CXChildVisit_Continue;
+}
+
+Type *gettyperecord(CXType t, const char *tydef)
{
+ CXCursor c;
+ CXString str;
+ Type *ty;
+ char *s;
+
+ str = clang_getTypeSpelling(t);
+ if (tydef)
+ s = strdup(tydef);
+ else
+ s = striptype(clang_getCString(str));
+ c = clang_getTypeDeclaration(t);
switch (clang_getCursorKind(c)) {
+ case CXCursor_UnionDecl:
+ ty = mktyunion(s, NULL, 0);
+ clang_visitChildren(c, addmembers, ty);
+ break;
case CXCursor_StructDecl:
- printf("struct\n");
+ ty = mktystruct(s, NULL, 0);
+ clang_visitChildren(c, addmembers, ty);
+ break;
+ default:
+ die("skipped kind: %s\n", clang_getCString(clang_getCursorSpelling(c)));
+ break;
+ }
+ return ty;
+}
+
+Type *gettypex(CXType t, const char *tydef)
+{
+ size_t narg, sz, i;
+ CXType subt;
+ CXString str;
+ char *s;
+ Type *ty;
+
+ switch (t.kind) {
+ case CXType_Invalid:
+ case CXType_Void: return mktype(Tyvoid); break;
+ case CXType_Bool: return mktype(Tybool); break;
+ case CXType_Char_U: return mktype(Tybyte); break;
+ case CXType_UChar: return mktype(Tybyte); break;
+ case CXType_Char32: return mktype(Tychar); break;
+ case CXType_UShort: return mktype(Tyuint16); break;
+ case CXType_UInt: return mktype(Tyuint32); break;
+ case CXType_ULong: return mktype(Tyuint64); break;
+ case CXType_ULongLong: return mktype(Tyuint64); break;
+
+ case CXType_Char_S: return mktype(Tyint8); break;
+ case CXType_SChar: return mktype(Tyint8); break;
+ case CXType_Short: return mktype(Tyint16); break;
+ case CXType_Int: return mktype(Tyint32); break;
+ case CXType_Long: return mktype(Tyint64); break;
+ case CXType_LongLong: return mktype(Tyint64); break;
+
+ case CXType_Float: return mktype(Tyflt32); break;
+ case CXType_Double: return mktype(Tyflt64); break;
+
+ case CXType_ConstantArray:
+ subt = clang_getArrayElementType(t);
+ sz = clang_getArraySize(t);
+ return mktyarray(gettype(subt), sz);
+ break;
+ case CXType_IncompleteArray:
+ subt = clang_getArrayElementType(t);
+ return mktyptr(gettype(subt));
+ break;
+ case CXType_Pointer:
+ subt = clang_getPointeeType(t);
+ return mktyptr(gettype(subt));
+ break;
+ case CXType_Enum:
+ printf("ENUM %s\n", clang_getCString(clang_getTypeSpelling(t)));
+ return NULL;
+ break;
+ case CXType_Typedef:
+ str = clang_getTypeSpelling(t);
+ s = strdup(clang_getCString(str));
+ return mktyname(s);
+ break;
+
+ case CXType_FunctionProto:
+ ty = mktype(Tyfunc);
+ lappend(&ty->sub, &ty->nsub, gettype(clang_getResultType(t)));
+ lappend(&ty->subname, &ty->nsubname, NULL);
+ narg = clang_getNumArgTypes(t);
+ for (i = 0; i < narg; i++) {
+ subt = clang_getArgType(t, i);
+ lappend(&ty->sub, &ty->nsub, gettype(subt));
+ lappend(&ty->subname, &ty->nsubname, NULL);
+ }
+ return ty;
+ break;
+ /* union and enum */
+ case CXType_Record:
+ return gettyperecord(t, tydef);
+
+ case CXType_Unexposed:
+ str = clang_getTypeSpelling(t);
+ s = strdup(clang_getCString(str));
+ fprintf(stderr, "warning: stubbed type %s: unexposed type\n", s);
+ clang_disposeString(str);
+ return mktyopaque(s, clang_Type_getSizeOf(t));
+ break;
+ /* Unsupported or non-C type */
+ case CXType_FunctionNoProto:
+ default:
+ str = clang_getTypeSpelling(t);
+ die("unsupported type %s\n", clang_getCString(str));
+ break;
+ }
+}
+
+Type *gettype(CXType t)
+{
+ Type *ty;
+
+ ty = gettypex(t, NULL);
+ assert(ty != NULL);
+ return ty;
+}
+
+void addfuncdcl(CXCursor c)
+{
+ CXString dname, dtype;
+ CXType type;
+ Type *ty;
+ Dcl *dcl;
+ char *n;
+
+ type = clang_getCursorType(c);
+ dname = clang_getCursorSpelling(c);
+ dtype = clang_getTypeSpelling(type);
+
+ if (clang_isFunctionTypeVariadic(type)) {
+ fprintf(stderr, "rejected %s of type %s: variadics unsupported\n",
+ clang_getCString(dname), clang_getCString(dtype));
+ goto dispose;
+ }
+ n = strdup(clang_getCString(dname));
+ ty = gettype(type);
+ if (ty) {
+ dcl = mkdcl(n, ty, 1);
+ lappend(&binding.dcl, &binding.ndcl, dcl);
+ }
+
+dispose:
+ clang_disposeString(dname);
+ clang_disposeString(dtype);
+}
+
+void addvardcl(CXCursor c)
+{
+ CXString dname;
+ CXType type;
+ Type *ty;
+ Dcl *dcl;
+ char *n;
+
+ type = clang_getCursorType(c);
+ dname = clang_getCursorSpelling(c);
+
+ n = strdup(clang_getCString(dname));
+ ty = gettype(type);
+ if (ty) {
+ dcl = mkdcl(n, ty, 1);
+ lappend(&binding.dcl, &binding.ndcl, dcl);
+ }
+
+ clang_disposeString(dname);
+}
+
+void addtypedef(CXCursor c)
+{
+ CXString str;
+ CXType sub;
+ Type *ty;
+
+ str = clang_getCursorSpelling(c);
+ sub = clang_getTypedefDeclUnderlyingType(c);
+ ty = gettypex(sub, clang_getCString(str));
+ lappend(&binding.type, &binding.ntype, ty);
+ clang_disposeString(str);
+}
+
+void addstructdef(CXCursor c)
+{
+ Type *ty;
+
+ ty = gettypex(clang_getCursorType(c), NULL);
+ lappend(&binding.type, &binding.ntype, ty);
+}
+
+void adduniondef(CXCursor c)
+{
+ Type *ty;
+
+ ty = gettypex(clang_getCursorType(c), NULL);
+ lappend(&binding.type, &binding.ntype, ty);
+}
+
+enum CXChildVisitResult scrapedcl(CXCursor c, CXCursor pc, CXClientData d)
+{
+ switch (clang_getCursorKind(c)) {
+ case CXCursor_FunctionDecl:
+ addfuncdcl(c);
+ break;
+ case CXCursor_VarDecl:
+ addvardcl(c);
+ break;
+ case CXCursor_TypedefDecl:
+ addtypedef(c);
+ break;
+ case CXCursor_StructDecl:
+ addstructdef(c);
+ break;
+ case CXCursor_UnionDecl:
+ adduniondef(c);
break;
default:
+ printf("skipped kind: %d\n", clang_getCursorKind(c));
break;
}
return CXChildVisit_Continue;
}
-void loadhdr(char *f)
+void
+loadhdr(char *f)
{
char **args;
size_t nargs;
+ lappend(&binding.hdr, &binding.nhdr, f);
initargs(&args, &nargs, f);
CXIndex idx = clang_createIndex(0, 1);
CXTranslationUnit tu = clang_parseTranslationUnit(
idx, 0,
(const char * const *) args, nargs,
0, 0, CXTranslationUnit_None);
- clang_visitChildren(clang_getTranslationUnitCursor(tu), dumpdcls, NULL);
+ clang_visitChildren(clang_getTranslationUnitCursor(tu), scrapedcl, NULL);
clang_disposeTranslationUnit(tu);
clang_disposeIndex(idx);
}
diff --git a/main.c b/main.c
index 750c67b..afcc2be 100644
--- a/main.c
+++ b/main.c
@@ -1,40 +1,55 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <clang-c/Index.h>
+#include "util.h"
#include "mcbind.h"
#include "optctx.h"
-char *opt_pkgname;
-char *opt_cprefix;
+Binding binding = {0};
static void usage(char *bin)
{
- printf("%s [-h] [-p pkg] [-P prefix]\n", bin);
+ printf("%s [-h] [-p pkg] [-P prefix] hdrs..\n", bin);
printf("\t-h\tprint this help\n");
printf("\t-p pkg\tgenerate bindings in package 'pkg'\n");
printf("\t-P pfx\tstrip 'pfx' from C function names\n");
+ printf("\t-H inc\tinclude header `inc` before the headers");
exit(0);
}
int main(int argc, char **argv)
{
Optctx ctx;
+ char *out;
size_t i;
optinit(&ctx, "hp:P:", argv, argc);
while (!optdone(&ctx)) {
switch (optnext(&ctx)) {
case 'h': usage(argv[0]); break;
- case 'p': opt_pkgname = ctx.optarg; break;
- case 'P': opt_cprefix = ctx.optarg; break;
+ case 'p': binding.pkg = ctx.optarg; break;
+ case 'P': binding.prefix = ctx.optarg; break;
}
}
+ if (!binding.pkg) {
+ fprintf(stderr, "package name is mandatory");
+ exit(1);
+ }
+ if (ctx.nargs == 0) {
+ fprintf(stderr, "missing input headers\n");
+ exit(1);
+ }
+
+ out = binding.pkg;
for (i = 0; i < ctx.nargs; i++) {
loadhdr(ctx.args[i]);
}
+ myrgen(out);
+ gluegen(out);
return 0;
}
diff --git a/mcbind.h b/mcbind.h
index 8deaf94..104ca31 100644
--- a/mcbind.h
+++ b/mcbind.h
@@ -1,43 +1,93 @@
typedef struct Type Type;
typedef struct Dcl Dcl;
+typedef struct Binding Binding;
+
extern char *opt_pkgname;
extern char *opt_cprefix;
-/* C types */
+/* Myrddin types */
typedef enum {
+ Tynone,
Tyvoid,
Tybool,
-
Tychar,
- Tyshort,
+
+ Tyint8,
+ Tyint16,
Tyint,
+ Tyint32,
+ Tyint64,
Tylong,
- Tyvlong,
- Tyuchar,
- Tyushort,
+
+ Tybyte,
+ Tyuint8,
+ Tyuint16,
Tyuint,
+ Tyuint32,
+ Tyuint64,
Tyulong,
- Tyuvlong,
- Tyfloat,
- Tydouble,
- Tystruct,
- Tyunion,
+ Tyflt32,
+ Tyflt64,
+
+ Typtr,
+ Tyarray,
Tyfunc,
+ Tystruct,
+ Tyunion,
+ Tyname,
+ Tyopaque,
} Ty;
struct Type {
- Ty ty;
- struct {
- size_t nsub;
- Type **sub;
- char **subname;
- };
+ Ty type;
+ size_t arraysz;
+ Type **sub;
+ size_t nsub;
+ char **subname;
+ size_t nsubname;
+ char *defname;
};
struct Dcl {
char *name;
+ char *cname;
Type *type;
+ char isconst;
+};
+
+struct Binding {
+ char *pkg; /* the Myrddin package name */
+ char *prefix; /* the prefix to remove from C funcs */
+ char **hdr; /* the C headers the glue needs to include */
+ size_t nhdr; /* the count of headers to include */
+ FILE *rejfile; /* the rejected functions that need manual binding */
+ Htab *defs; /* the definitions */
+ Type **type; /* the C types */
+ size_t ntype; /* the number of C types */
+ Dcl **dcl; /* the C declarations */
+ size_t ndcl; /* the number of C declarations */
};
+extern Binding binding;
+
void loadhdr(char *f);
+
+/* type */
+Type *mktype(Ty ty);
+Type *mktyarray(Type *sub, size_t sz);
+Type *mktydefn(Type *sub, char *name);
+Type *mktyptr(Type *sub);
+Type *mktyname(char *s);
+Type *mktystruct(char *s, Dcl **dcl, size_t ndcl);
+Type *mktyunion(char *s, Dcl **dcl, size_t ndcl);
+Type *mktyopaque(char *name, size_t sz);
+void writetype(FILE *fd, Type *t);
+
+/* code gen */
+void myrgen(char *hdr);
+void gluegen(char *hdr);
+
+/* dcl */
+Dcl *mkdcl(char *cname, Type *type, int isconst);
+void writedcl(FILE *fd, Dcl *d);
diff --git a/myrgen.c b/myrgen.c
index e69de29..32aa322 100644
--- a/myrgen.c
+++ b/myrgen.c
@@ -0,0 +1,130 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "mcbind.h"
+
+void writemyrtype(FILE *fd, Type *ty)
+{
+ size_t i;
+ char *sep;
+
+ switch (ty->type) {
+ case Tynone: die("invalid type\n"); break;
+
+ case Tyvoid: fprintf(fd, "void"); break;
+ case Tybool: fprintf(fd, "bool"); break;
+ case Tychar: fprintf(fd, "char"); break;
+
+ case Tyint8: fprintf(fd, "int8"); break;
+ case Tyint16: fprintf(fd, "int16"); break;
+ case Tyint: fprintf(fd, "int"); break;
+ case Tyint32: fprintf(fd, "int32"); break;
+ case Tyint64: fprintf(fd, "int64"); break;
+ case Tylong: fprintf(fd, "int64"); break;
+
+ case Tybyte: fprintf(fd, "byte"); break;
+ case Tyuint8: fprintf(fd, "uint8"); break;
+ case Tyuint16: fprintf(fd, "uint16"); break;
+ case Tyuint: fprintf(fd, "uint"); break;
+ case Tyuint32: fprintf(fd, "uint32"); break;
+ case Tyuint64: fprintf(fd, "uint64"); break;
+ case Tyulong: fprintf(fd, "uint64"); break;
+
+ case Tyflt32: fprintf(fd, "flt32"); break;
+ case Tyflt64: fprintf(fd, "flt64"); break;
+
+ case Typtr:
+ writemyrtype(fd, ty->sub[0]);
+ fprintf(fd, "#");
+ break;
+
+ case Tyfunc:
+ fprintf(fd, "(");
+ sep = "";
+ for (i = 0; i < ty->nsub - 1; i++) {
+ if (ty->subname[i])
+ fprintf(fd, "%s%s : ", sep, ty->subname[i]);
+ else
+ fprintf(fd, "%sa%zd : ", sep, i);
+ writemyrtype(fd, ty->sub[i + 1]);
+ sep = ", ";
+ }
+ fprintf(fd, " -> ");
+ writemyrtype(fd, ty->sub[0]);
+ fprintf(fd, ")");
+ break;
+
+ case Tyarray:
+ writemyrtype(fd, ty->sub[0]);
+ if (ty->arraysz)
+ fprintf(fd, "[%zd]", ty->arraysz);
+ else
+ fprintf(fd, "[]");
+ break;
+ case Tystruct:
+ fprintf(fd, "struct\n");
+ for (i = 0; i < ty->nsub; i++) {
+ fprintf(fd, "\t%s : ", ty->subname[i]);
+ writemyrtype(fd, ty->sub[i]);
+ fprintf(fd, "\n");
+ }
+ fprintf(fd, ";;");
+ break;
+ case Tyunion:
+ fprintf(fd, "union\n");
+ for (i = 0; i < ty->nsub; i++) {
+ fprintf(fd, "\t%s : ", ty->subname[i]);
+ writemyrtype(fd, ty->sub[i]);
+ fprintf(fd, "[0]");
+ fprintf(fd, "\n");
+ }
+ fprintf(fd, ";;");
+ break;
+ case Tyname:
+ fprintf(fd, "type %s =", ty->defname);
+ break;
+ case Tyopaque:
+ fprintf(fd, "/*opaque %s: */byte[%zd]", ty->defname, ty->arraysz);
+ break;
+ }
+}
+
+void writemyrdcl(FILE *fd, Dcl *d)
+{
+ if (d->isconst)
+ fprintf(fd, "const\t%s : ", d->name);
+ else
+ fprintf(fd, "var\t%s : ", d->name);
+ writemyrtype(fd, d->type);
+
+}
+
+void myrgen(char *hdr)
+{
+ char out[512];
+ size_t i;
+ FILE *fd;
+
+ swapsuffix(out, sizeof out, hdr, ".h", ".myr");
+ fd = fopen(out, "w");
+ fprintf(fd, "/*\n");
+ fprintf(fd, "This file is generated by the Myrddin C binding generator.\n");
+ fprintf(fd, "Unless you like having your work clobbered, I would suggest\n");
+ fprintf(fd, "that you edit elsewhere\n");
+ fprintf(fd, "*/\n\n");
+
+ fprintf(fd, "pkg %s =\n", binding.pkg ? binding.pkg : "");
+ for (i = 0; i < binding.ntype; i++) {
+ writemyrtype(fd, binding.type[i]);
+ fprintf(fd, "\n");
+ }
+ for (i = 0; i < binding.ndcl; i++) {
+ writemyrdcl(fd, binding.dcl[i]);
+ fprintf(fd, "\n");
+ }
+ fprintf(fd, ";;\n");
+}
diff --git a/optctx.c b/optctx.c
index 22c7201..b8dae7f 100644
--- a/optctx.c
+++ b/optctx.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <string.h>
#include "optctx.h"
diff --git a/util.c b/util.c
index d7114f2..592523e 100644
--- a/util.c
+++ b/util.c
@@ -119,3 +119,27 @@ void lfree(void *l, size_t *len)
*len = 0;
}
+char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap)
+{
+ size_t slen, suflen, swaplen;
+
+ slen = strlen(s);
+ suflen = strlen(suf);
+ swaplen = strlen(swap);
+
+ if (slen < suflen)
+ return NULL;
+ if (slen + swaplen >= sz)
+ die("swapsuffix: buf too small");
+
+ buf[0] = '\0';
+ /* if we have matching suffixes */
+ if (suflen < slen && !strcmp(suf, &s[slen - suflen])) {
+ strncat(buf, s, slen - suflen);
+ strncat(buf, swap, swaplen);
+ } else {
+ snprintf(buf, sz, "%s%s", s, swap);
+ }
+
+ return buf;
+}
diff --git a/util.h b/util.h
index 4d25181..ef2f150 100644
--- a/util.h
+++ b/util.h
@@ -3,6 +3,41 @@
#else
# define FATAL
#endif
+typedef uint8_t byte;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef long long vlong;
+typedef unsigned long long uvlong;
+
+typedef struct Htab Htab;
+
+struct Htab {
+ size_t nelt;
+ size_t sz;
+ ulong (*hash)(void *k);
+ int (*cmp)(void *a, void *b);
+ void **keys;
+ void **vals;
+ ulong *hashes;
+ char *dead;
+};
+
+/* hash tables */
+Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2));
+void htfree(Htab *ht);
+int htput(Htab *ht, void *k, void *v);
+void htdel(Htab *ht, void *k);
+void *htget(Htab *ht, void *k);
+int hthas(Htab *ht, void *k);
+void **htkeys(Htab *ht, size_t *nkeys);
+
+/* general hash functions */
+ulong strhash(void *key);
+int streq(void *a, void *b);
+ulong ptrhash(void *key);
+int ptreq(void *a, void *b);
+ulong inthash(uint64_t key);
+int inteq(uint64_t a, uint64_t b);
/* death */
void die(char *msg, ...) FATAL;
@@ -20,3 +55,5 @@ void *lpop(void *l, size_t *len);
void ldel(void *l, size_t *len, size_t idx);
void lfree(void *l, size_t *len);
+/* string utils */
+char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap);