summaryrefslogtreecommitdiff
path: root/c/examples/dynamic_typing/dietpass.c
blob: 6c32f00065252aab91ac89050c180879a69d893c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libdietc.h>
#include <string_helpers.c>

static int is_void_pointer(struct type *);
static char *describe_type(struct instruction *, struct 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);

            char *descriptor = describe_type(i, rhs_type);
            char *line = sbuild("\tannotate_type((void*)%s, %s);", rhs, descriptor);
            libdietc_insert_before(i, line);
        }
    }
    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 *before, struct type *type) {
    assert(type);
    static unsigned long count = 0;
    char *name = sbuild("dtype_%d", count++);

    char *line = 0;
    char *base_ty = NULL;
    switch (type->kind) {
    case TYPE_BASIC:
        line = sbuild("\tvoid *%s = make_basic(\"%s\", sizeof(%s));",
                      name, type->basic, type->basic);
        break;
    case TYPE_ARRAY:
        base_ty = describe_type(before, type->base);
        line = sbuild("\tvoid *%s = make_array(%s, %ld);",
                      name, base_ty, type->length);
        break;
    case TYPE_POINTER:
        base_ty = describe_type(before, type->base);
        line = sbuild("\tvoid *%s = make_pointer(%s);", name, base_ty);
        break;
    case TYPE_STRUCT:
    case TYPE_UNION: {
        line = sbuild("\tvoid *%s = make_struct(sizeof(Type_%ld));", name, type->id);
        libdietc_insert_before(before, 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 *fd = describe_type(before, fields[i]);
            char *prepend_buffer = sbuild(
                "\tprepend_member(%s, %s, \"%s\", __builtin_offsetof(Type_%ld, %s));",
                name, fd, fields[i]->field_name, type->id,
                fields[i]->field_name);
            libdietc_insert_before(before, prepend_buffer);
        }
        return name;
    }
    case TYPE_FUNCTION:
        assert(0); // not supported yet
        break;
    }
    libdietc_insert_before(before, line);
    return name;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback