diff options
Diffstat (limited to 'c/examples/dynamic_typing/dietpass.c')
-rw-r--r-- | c/examples/dynamic_typing/dietpass.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/c/examples/dynamic_typing/dietpass.c b/c/examples/dynamic_typing/dietpass.c new file mode 100644 index 0000000..62c0f9e --- /dev/null +++ b/c/examples/dynamic_typing/dietpass.c @@ -0,0 +1,102 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libdietc.h> + +static void insert_line(struct instruction **insertion_point, char *line); +static int is_void_pointer(struct type *type); +static char *describe_type(struct instruction **insertion_point, struct type *type); + +int main(int argc, char **argv) { + assert(argc == 2); + struct program program = libdietc_parse(argv[1]); + + for (struct function *f = program.functions; f; f = f->next) { + for (struct instruction *i = f->instructions; i; i = i->next) { + // look for x = ( Type_%d ) ... + if (!strstr(i->line, " = ( Type_")) continue; + char *type_tok = libdietc_nth_token(i->line, 3); + unsigned long type_id = 0; + assert(sscanf(type_tok, "Type_%d", &type_id) == 1); + if (!is_void_pointer(program.id2type[type_id])) continue; + char *rhs = libdietc_tokdup(libdietc_nth_token(i->line, 5)); + struct type *rhs_type = libdietc_object_type(program, rhs); + + struct instruction *insertion_point = i; + char *descriptor = describe_type(&insertion_point, rhs_type); + char *line = malloc(strlen(descriptor) + strlen(rhs) + 512); + sprintf(line, "\tannotate_type((void*)%s, %s);", rhs, descriptor); + insert_line(&insertion_point, line); + i = insertion_point; + } + } + libdietc_print(program); + return 0; +} + +static int is_void_pointer(struct type *type) { + if (type->kind != TYPE_POINTER) return 0; + if (type->base->kind != TYPE_BASIC) return 0; + if (strcmp(type->base->basic, "void")) return 0; + return 1; +} + +static char *describe_type(struct instruction **insertion_point, struct type *type) { + assert(type); + static unsigned long count = 0; + char *name = calloc(512, sizeof(char)); + sprintf(name, "dtype_%d", count++); + + char *line = calloc(strlen(name) + 1024, sizeof(char)); + char *base_ty = NULL; + switch (type->kind) { + case TYPE_BASIC: + sprintf(line, "\tvoid *%s = make_basic(\"%s\", sizeof(%s));", + name, type->basic, type->basic); + break; + case TYPE_ARRAY: + base_ty = describe_type(insertion_point, type->base); + sprintf(line, "\tvoid *%s = make_array(%s, %ld);", + name, base_ty, type->length); + break; + case TYPE_POINTER: + base_ty = describe_type(insertion_point, type->base); + sprintf(line, "\tvoid *%s = make_pointer(%s);", name, base_ty); + break; + case TYPE_STRUCT: + case TYPE_UNION: { + sprintf(line, "\tvoid *%s = make_struct(sizeof(Type_%ld));", name, type->id); + insert_line(insertion_point, line); + unsigned long n = 0; + for (struct type *m = type->members; m; m = m->next_member) n++; + struct type **fields = calloc(n, sizeof(*fields)); + unsigned long i = n; + for (struct type *m = type->members; m; m = m->next_member) fields[--i] = m; + + for (i = 0; i < n; i++) { + char *prepend_buffer = calloc(2048, sizeof(char)); + char *fd = describe_type(insertion_point, fields[i]); + sprintf(prepend_buffer, + "\tprepend_member(%s, %s, \"%s\", __builtin_offsetof(Type_%ld, %s));", + name, fd, fields[i]->field_name, type->id, + fields[i]->field_name); + insert_line(insertion_point, prepend_buffer); + } + return name; + } + case TYPE_FUNCTION: + assert(0); // not supported yet + break; + } + insert_line(insertion_point, line); + return name; +} + +static void insert_line(struct instruction **insertion_point, char *line) { + struct instruction *new = calloc(1, sizeof(*new)); + new->line = line; + new->next = (*insertion_point)->next; + (*insertion_point)->next = new; + *insertion_point = new; +} |