From c8ef4cf86bb97033238e3aa5c95789ea665341b1 Mon Sep 17 00:00:00 2001 From: Matthew Sotoudeh Date: Sun, 30 Jul 2023 21:16:09 -0700 Subject: C dynamic typing pass works as well --- c/examples/dynamic_typing/.gitignore | 1 + c/examples/dynamic_typing/Makefile | 12 +++++ c/examples/dynamic_typing/dietpass.c | 102 +++++++++++++++++++++++++++++++++++ c/examples/dynamic_typing/runtime | 1 + c/examples/dynamic_typing/test.c | 1 + c/examples/zero_init/test.c | 21 +------- c/libdietc.h | 2 + c/libdietc.l | 59 +++++++++++++------- 8 files changed, 161 insertions(+), 38 deletions(-) create mode 100644 c/examples/dynamic_typing/.gitignore create mode 100644 c/examples/dynamic_typing/Makefile create mode 100644 c/examples/dynamic_typing/dietpass.c create mode 120000 c/examples/dynamic_typing/runtime create mode 120000 c/examples/dynamic_typing/test.c mode change 100644 => 120000 c/examples/zero_init/test.c (limited to 'c') diff --git a/c/examples/dynamic_typing/.gitignore b/c/examples/dynamic_typing/.gitignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/c/examples/dynamic_typing/.gitignore @@ -0,0 +1 @@ +test diff --git a/c/examples/dynamic_typing/Makefile b/c/examples/dynamic_typing/Makefile new file mode 100644 index 0000000..0f22078 --- /dev/null +++ b/c/examples/dynamic_typing/Makefile @@ -0,0 +1,12 @@ +test: test.c runtime/dynamic_typing.o dietpass + dietcc -I $(PWD)/runtime -o $@ test.c runtime/dynamic_typing.o --dietc-pass $(PWD)/dietpass + +dietpass: dietpass.c ../../libdietc.l ../../libdietc.h + make -C ../.. + gcc -g -O3 dietpass.c ../../libdietc.o -I../../ -lfl -o $@ + +runtime/dynamic_typing.o: runtime/dynamic_typing.c + gcc -c -o $@ $^ + +clean: + rm -f runtime/dynamic_typing.o test dietpass 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 +#include +#include +#include +#include + +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; +} diff --git a/c/examples/dynamic_typing/runtime b/c/examples/dynamic_typing/runtime new file mode 120000 index 0000000..9e69bb5 --- /dev/null +++ b/c/examples/dynamic_typing/runtime @@ -0,0 +1 @@ +../../../python/examples/dynamic_typing/runtime \ No newline at end of file diff --git a/c/examples/dynamic_typing/test.c b/c/examples/dynamic_typing/test.c new file mode 120000 index 0000000..750e9a9 --- /dev/null +++ b/c/examples/dynamic_typing/test.c @@ -0,0 +1 @@ +../../../python/examples/dynamic_typing/test.c \ No newline at end of file diff --git a/c/examples/zero_init/test.c b/c/examples/zero_init/test.c deleted file mode 100644 index 5db109a..0000000 --- a/c/examples/zero_init/test.c +++ /dev/null @@ -1,20 +0,0 @@ -#include - -int set_xyz() { - int xyz = 1; - return xyz; -} - -int foo() { - int xyz; - return xyz; -} - -int main() { - printf("Foo return value: %d\n", foo()); - set_xyz(); - printf("Foo return value: %d\n", foo()); - set_xyz(); - printf("Foo return value: %d\n", foo()); - return 0; -} diff --git a/c/examples/zero_init/test.c b/c/examples/zero_init/test.c new file mode 120000 index 0000000..73e2712 --- /dev/null +++ b/c/examples/zero_init/test.c @@ -0,0 +1 @@ +../../../python/examples/zero_init/test.c \ No newline at end of file diff --git a/c/libdietc.h b/c/libdietc.h index 14b7ad2..e63af8d 100644 --- a/c/libdietc.h +++ b/c/libdietc.h @@ -81,3 +81,5 @@ struct identifiers { char *libdietc_tokdup(char *tok); struct program libdietc_parse(char *filename); void libdietc_print(struct program program); +char *libdietc_nth_token(char *string, int n); +struct type *libdietc_object_type(struct program program, char *name); diff --git a/c/libdietc.l b/c/libdietc.l index cd167b2..7133803 100644 --- a/c/libdietc.l +++ b/c/libdietc.l @@ -21,17 +21,20 @@ static void end_function(); ^[#].*$ {} "typedef Type_"[0-9]*" * Type_"[0-9]*" ;" { declare_pointer(yytext); } "typedef Type_"[0-9]*" Type_"[0-9]*" [ "[^ ]*" ] ;" { declare_array(yytext); } -"typedef Type_"[0-9]*" ( "[^)\n]*") ;" { declare_function(yytext); } +"typedef Type_"[0-9]*" Type_"[0-9]*" ( "[^)\n]*") ;" { declare_function(yytext); } "typedef struct Struct_"[0-9]*" Type_"[0-9]*" ;" { predeclare_struct(yytext); } "struct Struct_"[0-9]*" { "[^}\n]*"} ;" { define_aggregate(yytext); } "typedef union Union_"[0-9]*" Type_"[0-9]*" ;" { predeclare_union(yytext); } "union Union_"[0-9]*" { "[^}\n]*"} ;" { define_aggregate(yytext); } -"typedef ".*" ;" { declare_basic(yytext); } +"typedef "[^*\n\t(]*" ;" { declare_basic(yytext); } "extern Type_"[0-9]*" "[^ \n]*" ;" { declare_object(yytext); } "static Type_"[0-9]*" "[^ \n]*" ;" { declare_object(yytext); } ^[^=\n\t]*"= ".*$ { /* definition */ } ^[^{\n]*"{"$ { start_function(yytext); } -\tType_[0-9]*" "[a-zA-Z0-9_]*" ;" { declare_object(yytext); add_instruction(yytext); } +^\tType_[0-9]*" "[a-zA-Z0-9_]*" ;"$ { + declare_object(yytext); + add_instruction(yytext); + } \t[^\n]*$ { add_instruction(yytext); } "}"$ { end_function(); } \n { } @@ -124,7 +127,7 @@ static void define_aggregate(char *line) { *insert_at = field_type; insert_at = &(field_type->next_member); - line = strchrnul(strchrnul(line, ','), 'T'); + line = strchrnul(strchrnul(line, ';'), 'T'); } *insert_at = 0; } @@ -132,11 +135,12 @@ static void define_aggregate(char *line) { static void declare_basic(char *line) { char *basic = strdup(line + strlen("typedef ")); char *basic_end = basic; - while (strncmp(basic_end + 1, "Type_", strlen(basic_end))) basic_end++; + while (strncmp(basic_end, "Type_", strlen("Type_"))) basic_end++; + basic_end--; // now basic_end is the space right before Type_ *basic_end = '\0'; - line += (basic_end - basic); - struct type type = {strdup(line), TYPE_BASIC, next_number(&line), 0}; + char *type_name = line + (basic_end - basic); + struct type type = {strdup(line), TYPE_BASIC, next_number(&type_name), 0}; type.basic = basic; add_type(type); } @@ -152,30 +156,31 @@ static unsigned long hash(char *str) { // djb2 } // ... Type_# name ; -static void declare_object(char *line) { +static void insert_object(struct object *object) { // MAYBE REHASH if (PROGRAM.n_objects >= PROGRAM.cap_objects / 2) { unsigned long old_cap = PROGRAM.cap_objects; struct object **old_objects = PROGRAM.objects; PROGRAM.cap_objects = 4 * (PROGRAM.n_objects + 1); PROGRAM.objects = calloc(PROGRAM.cap_objects, sizeof(void*)); - for (unsigned long i = 0; i < old_cap; i++) { - if (!old_objects[i]) continue; - unsigned long h = hash(old_objects[i]->name) % old_cap; - while (PROGRAM.objects[h]) h = (h + 1) % old_cap; - PROGRAM.objects[h] = old_objects[i]; - } + for (unsigned long i = 0; i < old_cap; i++) + if (old_objects[i]) + insert_object(old_objects[i]); free(old_objects); } // INSERT - struct object *object = malloc(sizeof(*object)); - object->type = PROGRAM.id2type[next_number(&line)]; - object->name = libdietc_tokdup(line + 1); PROGRAM.n_objects++; unsigned long h = hash(object->name) % PROGRAM.cap_objects; - while (PROGRAM.objects[h]) h = (h + 1) % PROGRAM.cap_objects; + while (PROGRAM.objects[h]) + h = ((h + 1) % PROGRAM.cap_objects); PROGRAM.objects[h] = object; } +static void declare_object(char *line) { + struct object *object = calloc(1, sizeof(object)); + object->type = PROGRAM.id2type[next_number(&line)]; + object->name = libdietc_tokdup(line + 1); + insert_object(object); +} static void start_function(char *line) { FUNCTION = (struct function){0}; @@ -241,3 +246,21 @@ void libdietc_print(struct program program) { printf("}\n"); } } + +char *libdietc_nth_token(char *string, int n) { + while (isspace(*string)) string++; + for (int i = 0; i < n; i++) { + while (!isspace(*string)) string++; + while (isspace(*string)) string++; + } + return string; +} + +struct type *libdietc_object_type(struct program program, char *name) { + char *name_tok = libdietc_tokdup(name); + unsigned long h = hash(name_tok) % program.cap_objects; + while (program.objects[h] && strcmp(program.objects[h]->name, name)) + h = (h + 1) % program.cap_objects; + free(name_tok); + return program.objects[h] ? program.objects[h]->type : 0; +} -- cgit v1.2.3