Commit Diff


commit - ec716a83243eeb924f17d2d31a4401c98681c673
commit + 9be3f8306dc92152ec1af230d2a54cbf3415a976
blob - 3ee1a951bf1c57a144bb0c4d42ad311a08dc983b
blob + b01f1c55cb4f2b49ac28a0eef40040777fc3d561
--- .gitignore
+++ .gitignore
@@ -1,6 +1,7 @@
 destruct
 destruct.inc
 y.tab.h
+test.[ch]
 *.o
 *.swp
 *.core
blob - b4fe389695079fcfcfca811492f94f2ea77ed2dc
blob + 593c0f5e809e181c9ee6f36b3e883793c144170f
--- Makefile
+++ Makefile
@@ -3,10 +3,11 @@ OBJ = parse.o lex.o gen.o main.o
 all: destruct
 
 run: destruct
-	./destruct < test.txt
+	./destruct -H test.h -o test.c test.txt
+	cat test.h test.c
 
 clean:
-	rm -f destruct destruct.inc y.tab.h *.o *.core
+	rm -f destruct destruct.inc y.tab.h test.[ch] *.o *.core
 
 destruct: destruct.inc ${OBJ}
 	${CC} -o $@ ${OBJ}
blob - 339db3a7c4e04375fbde0643a28935bcecba749d
blob + 4b45bdda08790cc04f7060be072644d7a09cd74c
--- ast.h
+++ ast.h
@@ -1,5 +1,6 @@
 #ifndef FILE_AST_H
 #define FILE_AST_H
+#include <stdio.h>
 
 enum type_type {
 	T_I8,
@@ -72,4 +73,7 @@ struct uitem {
 	struct cond *cond;
 };
 
+void gen (struct structure **, const char *hdrpath, FILE *hdr, FILE *src, int from, int to);
+struct structure **parse (void);
+
 #endif // FILE_AST_H
blob - d8784b15cf600d97e8da34aee1185723093aecf9
blob + f91f8a2a73220dc687f44ec3b53363be1801755e
--- gen.c
+++ gen.c
@@ -1,6 +1,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <ctype.h>
 #include <err.h>
 #include "ast.h"
 
@@ -124,119 +125,119 @@ size_t align (size_t offset, size_t alignment)
 	return (offset + alignment - 1) & -alignment;
 }
 
-void prindent (int ind)
+void prindent (FILE *out, int ind)
 {
 	for (int i = 0; i < ind; ++i)
-		putchar ('\t');
+		fputc ('\t', out);
 }
 
-void print_value (struct value *v)
+void print_value (FILE *out, struct value *v)
 {
 	switch (v->type) {
 	case V_NAME:
-		printf ("%s", v->s);
+		fprintf (out, "%s", v->s);
 		break;
 	case V_INT:
-		printf ("%d", v->i);
+		fprintf (out, "%d", v->i);
 		break;
 	}
 }
 
-void print_cond (struct cond *co, const char *prefix)
+void print_cond (FILE *out, struct cond *co, const char *prefix)
 {
 	switch (co->type) {
 	case C_EQ:
-		printf ("%s%s == ", prefix, co->cmp.left);
-		print_value (co->cmp.right);
+		fprintf (out, "%s%s == ", prefix, co->cmp.left);
+		print_value (out, co->cmp.right);
 		break;
 	}
 }
 
-void print_item2 (struct type *ty, const char *name, int indent)
+void print_item2 (FILE *out, struct type *ty, const char *name, int indent)
 {
 	switch (ty->type) {
 	case T_I8:
-		printf ("int8_t %s", name);
+		fprintf (out, "int8_t %s", name);
 		break;
 	case T_I16:
-		printf ("int16_t %s", name);
+		fprintf (out, "int16_t %s", name);
 		break;
 	case T_I32:
-		printf ("int32_t %s", name);
+		fprintf (out, "int32_t %s", name);
 		break;
 	case T_I64:
-		printf ("int64_t %s", name);
+		fprintf (out, "int64_t %s", name);
 		break;
 	case T_U8:
-		printf ("uint8_t %s", name);
+		fprintf (out, "uint8_t %s", name);
 		break;
 	case T_U16:
-		printf ("uint16_t %s", name);
+		fprintf (out, "uint16_t %s", name);
 		break;
 	case T_U32:
-		printf ("uint32_t %s", name);
+		fprintf (out, "uint32_t %s", name);
 		break;
 	case T_U64:
-		printf ("uint64_t %s", name);
+		fprintf (out, "uint64_t %s", name);
 		break;
 	case T_ARRAY:
-		print_item2 (ty->inner, name, indent);
-		printf ("[%zu]", ty->len);
+		print_item2 (out, ty->inner, name, indent);
+		fprintf (out, "[%zu]", ty->len);
 		break;
 	case T_NAME:
-		printf ("struct %s %s", ty->name, name);
+		fprintf (out, "struct %s %s", ty->name, name);
 		break;
 	case T_STRUCT:
-		printf ("struct {\n");
+		fprintf (out, "struct {\n");
 
 		for (struct item **i = ty->st->items; *i != NULL; ++i) {
 			struct item *it = *i;
-			prindent (indent + 1);
-			print_item2 (it->type, it->name, indent + 1);
-			puts (";");
+			prindent (out, indent + 1);
+			print_item2 (out, it->type, it->name, indent + 1);
+			fputs (";\n", out);
 		}
 
-		prindent (indent);
-		printf ("} %s", name);
+		prindent (out, indent);
+		fprintf (out, "} %s", name);
 		break;
 	case T_UNION:
-		printf ("union {\n");
+		fputs ("union {\n", out);
 
 		for (struct uitem **i = ty->un; *i != NULL; ++i) {
 			struct uitem *ui = *i;
-			prindent (indent + 1);
-			print_item2 (ui->type, ui->name, indent + 1);
-			printf (" // if ");
-			print_cond (ui->cond, "");
-			puts (";");
+			prindent (out, indent + 1);
+			print_item2 (out, ui->type, ui->name, indent + 1);
+			fprintf (out, "; // if ");
+			print_cond (out, ui->cond, "");
+			fputc ('\n', out);
 		}
 
-		prindent (indent);
-		printf ("} %s", name);
+		prindent (out, indent);
+		fprintf (out, "} %s", name);
 		break;
 	}
 }
 
-void print_item (struct item *it)
+void print_item (FILE *out, struct item *it)
 {
-	putchar ('\t');
-	print_item2 (it->type, it->name, 1);
-	puts (";");
+	fputc ('\t', out);
+	print_item2 (out, it->type, it->name, 1);
+	fputs (";\n", out);
 }
 
-void print_structure (struct structure *st)
+void print_structure (FILE *out, struct structure *st)
 {
 	if (st->name == NULL)
 		errx (1, "a top-level structure was declared without a name");
 
-	printf ("struct %s {\n", st->name);
+	fprintf (out, "struct %s {\n", st->name);
 	for (struct item **it = st->items; *it != NULL; ++it) {
-		print_item (*it);
+		print_item (out, *it);
 	}
-	puts ("};\n");
+	fputs ("};\n\n", out);
 }
 
-void encode (size_t *offset, struct type *ty, const char *from, const char *parent, int indent)
+void encode (FILE *out, size_t *offset, struct type *ty, const char *from, const char *parent, int indent)
 {
 	size_t sz, off2;
 	char *s;
@@ -253,59 +254,58 @@ void encode (size_t *offset, struct type *ty, const ch
 	case T_U16:
 	case T_U32:
 	case T_U64:
-		prindent (indent);
-		printf ("write%zu (out + %zu, %s);\n", sz * 8, *offset, from);
+		prindent (out, indent);
+		fprintf (out, "write%zu (out + %zu, %s);\n", sz * 8, *offset, from);
 		*offset += sz;
 		break;
 	case T_ARRAY:
 		for (size_t i = 0; i < ty->len; ++i) {
 			asprintf (&s, "%s[%zu]", from, i);
-			encode (offset, ty->inner, s, parent, indent);
+			encode (out, offset, ty->inner, s, parent, indent);
 			free (s);
 		}
 		break;
 	case T_NAME:
-		prindent (indent);
-		printf ("encode_%s (out + %zu, &%s);\n", ty->name, *offset, from);
+		prindent (out, indent);
+		fprintf (out, "encode_%s (out + %zu, &%s);\n", ty->name, *offset, from);
 		*offset += sz;
 		break;
 	case T_STRUCT:
 		for (struct item **i = ty->st->items; *i != NULL; ++i) {
 			struct item *it = *i;
 			asprintf (&s, "%s.%s", from, it->name);
-			encode (offset, it->type, s, from, indent);
+			encode (out, offset, it->type, s, from, indent);
 			free (s);
 		}
 		break;
 	case T_UNION:
-		prindent (indent);
+		prindent (out, indent);
 		for (struct uitem **i = ty->un; *i != NULL; ++i) {
 			struct uitem *ui = *i;
 			char *prefix;
 
 			asprintf (&prefix, "%s.", parent);
-			printf ("if (");
-			print_cond (ui->cond, prefix);
-			printf (") {\n");
+			fputs ("if (", out);
+			print_cond (out, ui->cond, prefix);
+			fputs (") {\n", out);
 			free (prefix);
 
 			off2 = *offset;
 			asprintf (&s, "%s.%s", from, ui->name);
-			encode (&off2, ui->type, s, parent, indent + 1);
+			encode (out, &off2, ui->type, s, parent, indent + 1);
 			free (s);
-			prindent (indent);
-			printf ("} else ");
+			prindent (out, indent);
+			fputs ("} else ", out);
 		}
-		puts (";");
+		fputs (";\n", out);
 		*offset += size_of_union (ty->un);
 		break;
 	}
 }
 
-void print_encode (struct structure *st)
+void print_encode (FILE *out, struct structure *st)
 {
-	printf ("static void encode_%s (uint8_t *out, const struct %s *in)\n", st->name, st->name);
-	puts ("{");
+	fprintf (out, "static void encode_%s (uint8_t *out, const struct %s *in)\n{\n", st->name, st->name);
 
 	size_t offset = 0;
 
@@ -314,14 +314,14 @@ void print_encode (struct structure *st)
 		char *from;
 
 		asprintf (&from, "in->%s", it->name);
-		encode (&offset, it->type, from, "(*in)", 1);
+		encode (out, &offset, it->type, from, "(*in)", 1);
 		free (from);
 	}
 
-	puts ("}\n");
+	fputs ("}\n\n", out);
 }
 
-void decode (size_t *offset, struct type *ty, const char *into, const char *parent, int indent)
+void decode (FILE *out, size_t *offset, struct type *ty, const char *into, const char *parent, int indent)
 {
 	size_t sz, off2;
 	char *s;
@@ -338,59 +338,58 @@ void decode (size_t *offset, struct type *ty, const ch
 	case T_U16:
 	case T_U32:
 	case T_U64:
-		prindent (indent);
-		printf ("%s = read%zu (in + %zu);\n", into, sz * 8, *offset);
+		prindent (out, indent);
+		fprintf (out, "%s = read%zu (in + %zu);\n", into, sz * 8, *offset);
 		*offset += sz;
 		break;
 	case T_ARRAY:
 		for (size_t i = 0; i < ty->len; ++i) {
 			asprintf (&s, "%s[%zu]", into, i);
-			decode (offset, ty->inner, s, parent, indent);
+			decode (out, offset, ty->inner, s, parent, indent);
 			free (s);
 		}
 		break;
 	case T_NAME:
-		prindent (indent);
-		printf ("decode_%s (&%s, in + %zu);\n", ty->name, into, *offset);
+		prindent (out, indent);
+		fprintf (out, "decode_%s (&%s, in + %zu);\n", ty->name, into, *offset);
 		*offset += sz;
 		break;
 	case T_STRUCT:
 		for (struct item **i = ty->st->items; *i != NULL; ++i) {
 			struct item *it = *i;
 			asprintf (&s, "%s.%s", into, it->name);
-			decode (offset, it->type, s, into, indent);
+			decode (out, offset, it->type, s, into, indent);
 			free (s);
 		}
 		break;
 	case T_UNION:
-		prindent (indent);
+		prindent (out, indent);
 		for (struct uitem **i = ty->un; *i != NULL; ++i) {
 			struct uitem *ui = *i;
 			char *prefix;
 
 			asprintf (&prefix, "%s.", parent);
-			printf ("if (");
-			print_cond (ui->cond, prefix);
-			printf (") {\n");
+			fputs ("if (", out);
+			print_cond (out, ui->cond, prefix);
+			fputs (") {\n", out);
 			free (prefix);
 
 			off2 = *offset;
 			asprintf (&s, "%s.%s", into, ui->name);
-			decode (&off2, ui->type, s, parent, indent + 1);
+			decode (out, &off2, ui->type, s, parent, indent + 1);
 			free (s);
-			prindent (indent);
-			printf ("} else ");
+			prindent (out, indent);
+			fputs ("} else ", out);
 		}
-		puts (";");
+		fputs (";\n", out);
 		*offset += size_of_union (ty->un);
 		break;
 	}
 }
 
-void print_decode (struct structure *st)
+void print_decode (FILE *out, struct structure *st)
 {
-	printf ("static void decode_%s (struct %s *out, uint8_t *in)\n", st->name, st->name);
-	puts ("{");
+	fprintf (out, "static void decode_%s (struct %s *out, uint8_t *in)\n{\n", st->name, st->name);
 
 	size_t offset = 0;
 
@@ -400,39 +399,89 @@ void print_decode (struct structure *st)
 		char *into;
 
 		asprintf (&into, "out->%s", it->name);
-		decode (&offset, it->type, into, "(*out)", 1);
+		decode (out, &offset, it->type, into, "(*out)", 1);
 		free (into);
 	}
 
-	puts ("}\n");
+	fputs ("}\n\n", out);
 }
 
+void declare (FILE *out, struct structure *st)
+{
+	fprintf (out, "static void encode_%s (uint8_t *out, const struct %s *in);\n", st->name, st->name);
+	fprintf (out, "static void decode_%s (struct %s *out, uint8_t *in);\n", st->name, st->name);
+}
+
 static const char *header =
 #include "destruct.inc"
 ;
 
-void gen (struct structure **f, int from, int to)
+void include_guard (char *path)
 {
+	char *s;
+
+	s = strrchr (s, '/');
+	if (s != NULL) {
+		++s;
+	} else {
+		s = path;
+	}
+
+	for (; *s != '\0'; ++s) {
+		switch (*s) {
+		case '.':
+		case '/':
+			*s = '_';
+			break;
+		default:
+			*s = toupper (*s);
+			break;
+		}
+	}
+}
+
+void gen (struct structure **f, const char *hdrpath, FILE *hdr, FILE *src, int from, int to)
+{
+	char *inc = NULL;
+
 	file = f;
 
-	puts ("#ifndef DST_FROM_ENDIAN");
-	printf ("# define DST_FROM_ENDIAN %d\n", from);
-	puts ("#endif\n");
 
-	puts ("#ifndef DST_TO_ENDIAN");
-	printf ("# define DST_TO_ENDIAN %d\n", to);
-	puts ("#endif\n");
+	if (hdrpath != NULL) {
+		fprintf (src, "#include \"%s\"\n\n", hdrpath);
+		inc = strdup (hdrpath);
+		include_guard (inc);
+		fprintf (hdr, "#ifndef FILE_%s\n", inc);
+		fprintf (hdr, "#define FILE_%s\n", inc);
+	}
 
-	puts (header);
+	fputs ("#include <stdint.h>\n\n", hdr);
 
+	fprintf (src, "#ifndef DST_FROM_ENDIAN\n");
+	fprintf (src, "# define DST_FROM_ENDIAN %d\n", from);
+	fprintf (src, "#endif\n\n");
+
+	fprintf (src, "#ifndef DST_TO_ENDIAN\n");
+	fprintf (src, "# define DST_TO_ENDIAN %d\n", to);
+	fprintf (src, "#endif\n\n");
+
+	fputs (header, src);
+	fputc ('\n', src);
+
+
 	// Declare the structures
 	for (struct structure **st = file; *st != NULL; ++st) {
-		print_structure (*st);
+		print_structure (hdr, *st);
 	}
 
 	// Define functions
-	for (struct structure **st = file; *st != NULL; ++st) {
-		print_encode (*st);
-		print_decode (*st);
+	for (struct structure **i = file; *i != NULL; ++i) {
+		struct structure *st = *i;
+		declare (hdr, st);
+		print_encode (src, st);
+		print_decode (src, st);
 	}
+
+	if (inc != NULL)
+		fprintf (hdr, "\n#endif // FILE_%s\n", inc);
 }
blob - e9b7907d4c124ac1ac36ca3bea04d40efa4bdebb
blob + 9c8bd4d25f744c526e3fecc3586cc3c3cadaf8c0
--- main.c
+++ main.c
@@ -8,9 +8,6 @@
 #define DST_BIG_ENDIAN 4321
 #define DST_DEFAULT_ENDIAN DST_LITTLE_ENDIAN
 
-void gen (struct structure **, int from, int to);
-struct structure **parse (void);
-
 int parse_endian2 (const char *s)
 {
 	if (strcmp (s, "little") == 0) {
@@ -40,21 +37,29 @@ void parse_endian (char *s, int *from, int *to)
 
 int usage (void)
 {
-	fputs ("usage: destruct [-e endian[:endian]]\n", stderr);
+	fputs ("usage: destruct [-e endian[:endian]] [-H headerfile] [-o srcfile] [input]\n", stderr);
 	return 1;
 }
 
 int main (int argc, char *argv[])
 {
 	struct structure **file;
+	const char *hdrpath = NULL, *srcpath = NULL;
+	FILE *src = stdout, *hdr = stdout;
 	int from = DST_DEFAULT_ENDIAN, to = DST_DEFAULT_ENDIAN;
 	int option;
 
-	while ((option = getopt (argc, argv, "e:")) != -1) {
+	while ((option = getopt (argc, argv, "e:H:o:")) != -1) {
 		switch (option) {
 		case 'e':
 			parse_endian (optarg, &from, &to);
 			break;
+		case 'H':
+			hdrpath = optarg;
+			break;
+		case 'o':
+			srcpath = optarg;
+			break;
 		default:
 			return usage ();
 		}
@@ -70,6 +75,18 @@ int main (int argc, char *argv[])
 		return usage ();
 	}
 
+	if (hdrpath != NULL) {
+		hdr = fopen (hdrpath, "w");
+		if (hdr == NULL)
+			err (1, "cannot open '%s'", hdrpath);
+	}
+
+	if (srcpath != NULL) {
+		src = fopen (srcpath, "w");
+		if (src == NULL)
+			err (1, "cannot open '%s'", srcpath);
+	}
+
 	file = parse ();
 
 	if (file == NULL) {
@@ -77,7 +94,7 @@ int main (int argc, char *argv[])
 		return 1;
 	}
 
-	gen (file, from, to);
+	gen (file, hdrpath, hdr, src, from, to);
 
 	return 0;
 }
blob - 0765b0168719e313ce4f1f1df97423ee10cb54cb
blob + 03a1ee5bbe7953382aa7c52d8d258a0d0c5df460
--- test.txt
+++ test.txt
@@ -19,7 +19,24 @@ struct asdf {
 	},
 	u: union {
 		a: u8 if x == 0,
-		b: u8 if x == 0,
+		b: u8 if x == 1,
 	},
 	z: i8,
 };
+
+struct elf64_ehdr {
+	ident: [u8; 16],
+	type: u16,
+	machine: u16,
+	version: u32,
+	entry: u64,
+	phoff: u64,
+	shoff: u64,
+	flags: u32,
+	ehsize: u16,
+	phentsize: u16,
+	phnum: u16,
+	shentsize: u16,
+	shnum: u16,
+	shstrndx: u16,
+};