From 86f852cd76cf92a4b08b59b127cc954420f95744 Mon Sep 17 00:00:00 2001 From: Matthew Sotoudeh Date: Mon, 31 Jul 2023 13:53:16 -0700 Subject: share more code between the C examples --- c/examples/dynamic_typing/dietpass.c | 63 ++++++++++++++---------------------- c/examples/refcounting/dietpass.c | 55 ++++++++----------------------- c/examples/zero_init/dietpass.c | 9 ++---- c/libdietc.h | 2 ++ c/libdietc.l | 20 ++++++++++++ c/string_helpers.c | 48 +++++++++++++++++++++++++++ 6 files changed, 111 insertions(+), 86 deletions(-) create mode 100644 c/string_helpers.c (limited to 'c') diff --git a/c/examples/dynamic_typing/dietpass.c b/c/examples/dynamic_typing/dietpass.c index 62c0f9e..6c32f00 100644 --- a/c/examples/dynamic_typing/dietpass.c +++ b/c/examples/dynamic_typing/dietpass.c @@ -3,10 +3,10 @@ #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); +static int is_void_pointer(struct type *); +static char *describe_type(struct instruction *, struct type *); int main(int argc, char **argv) { assert(argc == 2); @@ -23,12 +23,9 @@ int main(int argc, char **argv) { 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; + 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); @@ -42,32 +39,31 @@ static int is_void_pointer(struct type *type) { return 1; } -static char *describe_type(struct instruction **insertion_point, struct type *type) { +static char *describe_type(struct instruction *before, struct type *type) { assert(type); static unsigned long count = 0; - char *name = calloc(512, sizeof(char)); - sprintf(name, "dtype_%d", count++); + char *name = sbuild("dtype_%d", count++); - char *line = calloc(strlen(name) + 1024, sizeof(char)); + char *line = 0; char *base_ty = NULL; switch (type->kind) { case TYPE_BASIC: - sprintf(line, "\tvoid *%s = make_basic(\"%s\", sizeof(%s));", - name, type->basic, type->basic); + line = sbuild("\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); + 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(insertion_point, type->base); - sprintf(line, "\tvoid *%s = make_pointer(%s);", name, base_ty); + base_ty = describe_type(before, type->base); + line = sbuild("\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); + 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)); @@ -75,13 +71,12 @@ static char *describe_type(struct instruction **insertion_point, struct type *ty 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); + 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; } @@ -89,14 +84,6 @@ static char *describe_type(struct instruction **insertion_point, struct type *ty assert(0); // not supported yet break; } - insert_line(insertion_point, line); + libdietc_insert_before(before, 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/refcounting/dietpass.c b/c/examples/refcounting/dietpass.c index 33e2531..395eac2 100644 --- a/c/examples/refcounting/dietpass.c +++ b/c/examples/refcounting/dietpass.c @@ -3,10 +3,9 @@ #include #include #include +#include static int startswith(char *s, char *p); -static struct instruction *instruction_before(struct instruction *i, char *line); -static struct instruction *instruction_after(struct instruction *i, char *line); static char **pointer_expressions(char *name, struct type *type); static void rewrite(struct instruction *i, char *old, char *new); @@ -41,22 +40,19 @@ int main(int argc, char **argv) { sscanf(type_name, "Type_%ld", &type_id); char **ptr_exprs = pointer_expressions(name, program.id2type[type_id]); for (char **expr = ptr_exprs; *expr; expr++) { - char *line = calloc(strlen(*expr) + 128, sizeof(char)); - sprintf(line, "\t%s = 0;", *expr); - i = instruction_after(i, line); + char *line = sbuild("\t%s = 0;", *expr); + i = libdietc_insert_after(i, line); } // is this the return expression? if (!strcmp(name, return_expr)) { // yes for (char **expr = ptr_exprs; *expr; expr++) { - char *line = calloc(strlen(*expr) + 128, sizeof(char)); - sprintf(line, "\trefcount_returning(%s);", *expr); - instruction_before(return_instruction, line); + char *line = sbuild("\trefcount_returning(%s);", *expr); + libdietc_insert_before(return_instruction, line); } } else { // no for (char **expr = ptr_exprs; *expr; expr++) { - char *line = calloc(strlen(*expr) + 128, sizeof(char)); - sprintf(line, "\trefcount_write(0, %s);", *expr); - instruction_after(before_return, line); + char *line = sbuild("\trefcount_write(0, %s);", *expr); + libdietc_insert_after(before_return, line); } } } else if (strstr(i->line, " = ")) { @@ -83,17 +79,14 @@ int main(int argc, char **argv) { // *before* the instruction, need to insert backups unsigned long backup_count = count; for (char **e = ptr_exprs; *e; e++) { - char *line = calloc(strlen(*e) + 128, sizeof(char)); - assert(strlen(*e)); - sprintf(line, "\tvoid *backup_%lu = (%s);", count++, *e); - instruction_before(i, line); + char *line = sbuild("\tvoid *backup_%lu = (%s);", count++, *e); + libdietc_insert_before(i, line); } // *then* execute the instruction // *then* call refcount_write for (char **e = ptr_exprs; *e; e++) { - char *line = calloc(strlen(*e) + 128, sizeof(char)); - sprintf(line, "\trefcount_write(%s, backup_%lu);", *e, backup_count++); - i = instruction_after(i, line); + char *line = sbuild("\trefcount_write(%s, backup_%lu);", *e, backup_count++); + i = libdietc_insert_after(i, line); } } } @@ -107,26 +100,6 @@ static int startswith(char *s, char *p) { return !strncmp(s, p, strlen(p)); } -static struct instruction *instruction_before(struct instruction *i, char *line) { - struct instruction *new = calloc(1, sizeof(*new)); - *(i->pprev) = new; - new->pprev = i->pprev; - new->line = line; - new->next = i; - i->pprev = &(new->next); - return new; -} - -static struct instruction *instruction_after(struct instruction *i, char *line) { - struct instruction *new = calloc(1, sizeof(*new)); - new->line = line; - new->next = i->next; - i->next->pprev = &(new->next); - new->pprev = &(i->next); - i->next = new; - return new; -} - static char **empty_list() { return calloc(1, sizeof(char *)); } @@ -151,8 +124,7 @@ static char **pointer_expressions(char *name, struct type *type) { case TYPE_ARRAY: { char **list = empty_list(); for (unsigned long i = 0; i < type->length; i++) { - char *line = calloc(strlen(name) + 128, sizeof(char)); - sprintf(line, "((%s)[%ld])", name, i); + char *line = sbuild("((%s)[%ld])", name, i); list = append_list(list, line); } return list; @@ -161,8 +133,7 @@ static char **pointer_expressions(char *name, struct type *type) { case TYPE_UNION: { char **list = empty_list(); for (struct type *m = type->members; m; m = m->next_member) { - char *subname = calloc(strlen(name) + strlen(m->field_name) + 4, sizeof(char)); - sprintf(subname, "%s.%s", name, m->field_name); + char *subname = sbuild("%s.%s", name, m->field_name); char **sublist = pointer_expressions(subname, m); for (char **subline = sublist; *subline; subline++) list = append_list(list, *subline); diff --git a/c/examples/zero_init/dietpass.c b/c/examples/zero_init/dietpass.c index e145a91..962337c 100644 --- a/c/examples/zero_init/dietpass.c +++ b/c/examples/zero_init/dietpass.c @@ -3,6 +3,7 @@ #include #include #include +#include int main(int argc, char **argv) { assert(argc == 2); @@ -12,12 +13,8 @@ int main(int argc, char **argv) { for (struct instruction *i = f->instructions; i; i = i->next) { if (strncmp(i->line, "\tType_", strlen("\tType_"))) continue; char *name = libdietc_tokdup(strchrnul(i->line, ' ') + 1); - struct instruction *n = calloc(1, sizeof(*n)); - n->line = malloc(strlen(name) + 512); - sprintf(n->line, "memset(&%s, 0, sizeof(%s));", name, name); - n->next = i->next; - i->next = n; - i = n; + char *line = sbuild("memset(&%s, 0, sizeof(%s));", name, name); + i = libdietc_insert_after(i, line); } } libdietc_print(program); diff --git a/c/libdietc.h b/c/libdietc.h index 4dea137..081bf2b 100644 --- a/c/libdietc.h +++ b/c/libdietc.h @@ -94,3 +94,5 @@ void libdietc_print(struct program program); char *libdietc_nth_token(char *string, int n); struct type *libdietc_object_type(struct program program, char *name); struct type *libdietc_lhs_type(struct program program, struct instruction *instruction); +struct instruction *libdietc_insert_before(struct instruction *i, char *line); +struct instruction *libdietc_insert_after(struct instruction *i, char *line); diff --git a/c/libdietc.l b/c/libdietc.l index 51c8e91..abdb914 100644 --- a/c/libdietc.l +++ b/c/libdietc.l @@ -280,3 +280,23 @@ struct type *libdietc_lhs_type(struct program program, struct instruction *instr name = libdietc_tokdup(libdietc_nth_token(instruction->line, 0)); return libdietc_object_type(program, name); } + +struct instruction *libdietc_insert_before(struct instruction *i, char *line) { + struct instruction *new = calloc(1, sizeof(*new)); + *(i->pprev) = new; + new->pprev = i->pprev; + new->line = line; + new->next = i; + i->pprev = &(new->next); + return new; +} + +struct instruction *libdietc_insert_after(struct instruction *i, char *line) { + struct instruction *new = calloc(1, sizeof(*new)); + new->line = line; + new->next = i->next; + i->next->pprev = &(new->next); + new->pprev = &(i->next); + i->next = new; + return new; +} diff --git a/c/string_helpers.c b/c/string_helpers.c new file mode 100644 index 0000000..636bad3 --- /dev/null +++ b/c/string_helpers.c @@ -0,0 +1,48 @@ +#include +#include + +static char *sbuild(char *format, ...) { + // (1) overapproximate the length of the string. adapted from man va_start + unsigned long max_len = 1; + char *s; + va_list ap; + va_start(ap, format); + for (char *c = format; *c; c++) { + if (*c != '%') { + max_len++; + continue; + } + + switch (*(++c)) { + case 's': + s = va_arg(ap, char*); + max_len += strlen(s); + break; + case 'l': // not quite accurate + va_arg(ap, unsigned long); + max_len += 64; + break; + case 'd': + va_arg(ap, int); + max_len += 32; + break; + case 'u': + va_arg(ap, unsigned); + max_len += 32; + break; + case 'f': + va_arg(ap, double); + max_len += 64; + break; + default: assert(0); + } + } + va_end(ap); + + char *str = calloc(max_len, sizeof(char)); + va_list ap_; + va_start(ap_, format); + vsprintf(str, format, ap_); + va_end(ap_); + return str; +} -- cgit v1.2.3