diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-29 20:36:14 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-29 20:36:14 -0400 |
commit | c8e6972ee18a95db544980513f619567a3bc171e (patch) | |
tree | 8f5882e9371d2d400958ecf03651792611c5f3ff | |
parent | ed62db5344e1fb39f17883c69bd398d18758f29b (diff) |
finished replacing err_malloc with allocators; now there are no memory leaks!
-rw-r--r-- | abbrevs.txt | 1 | ||||
-rw-r--r-- | allocator.c | 36 | ||||
-rw-r--r-- | arr.c | 6 | ||||
-rw-r--r-- | eval.c | 39 | ||||
-rw-r--r-- | identifiers.c | 9 | ||||
-rw-r--r-- | main.c | 34 | ||||
-rw-r--r-- | parse.c | 28 | ||||
-rw-r--r-- | test.toc | 26 | ||||
-rw-r--r-- | tests.c | 5 | ||||
-rw-r--r-- | tokenizer.c | 21 | ||||
-rw-r--r-- | types.c | 61 |
11 files changed, 170 insertions, 96 deletions
diff --git a/abbrevs.txt b/abbrevs.txt index d5a3a68..d907681 100644 --- a/abbrevs.txt +++ b/abbrevs.txt @@ -6,6 +6,7 @@ deref - dereference direct - directive eof - end of file err - error +evalr - evaluator expr - expression fn - function ident - identifier diff --git a/allocator.c b/allocator.c index f10c703..2b6b0b3 100644 --- a/allocator.c +++ b/allocator.c @@ -4,10 +4,15 @@ typedef struct Page { max_align_t data[]; } Page; +typedef struct DynPage { + struct DynPage **self; + max_align_t data[]; +} DynPage; + typedef struct { Page *first; Page *last; - void **dyn; /* array of void*s for dynamic memory */ + DynPage **dyn; size_t dyn_len; size_t dyn_cap; } Allocator; @@ -17,6 +22,8 @@ typedef struct { static void allocr_create(Allocator *a) { a->first = a->last = NULL; + a->dyn = NULL; + a->dyn_len = a->dyn_cap = 0; } static void *allocr_malloc(Allocator *a, size_t bytes) { @@ -42,14 +49,36 @@ static void *allocr_malloc(Allocator *a, size_t bytes) { } } -static void *allocr_calloc(Allocator *a, size_t bytes) { +static void *allocr_calloc(Allocator *a, size_t n, size_t sz) { + /* OPTIM: use calloc */ + size_t bytes = n * sz; void *data = allocr_malloc(a, bytes); memset(data, 0, bytes); return data; } -/* IMPORTANT: this can only be called with data which was originally allocated with allocr_realloc(a, NULL, x) */ +/* IMPORTANT: this can only be called with data which was originally allocated with allocr_realloc(a, NULL, x) + */ static void *allocr_realloc(Allocator *a, void *data, size_t new_size) { + if (data) { + DynPage *page = (DynPage *)((char *)data - offsetof(DynPage, data)); + page = err_realloc(page, new_size + sizeof(DynPage)); + *page->self = page; + return page->data; + } else { + if (a->dyn_len >= a->dyn_cap) { + a->dyn_cap = 2 * (a->dyn_len + 1); + a->dyn = realloc(a->dyn, a->dyn_cap * sizeof(DynPage *)); + for (size_t i = 0; i < a->dyn_len; i++) { + a->dyn[i]->self = &a->dyn[i]; + } + } + DynPage *page = err_malloc(sizeof(DynPage) + new_size); + page->self = &a->dyn[a->dyn_len]; + *page->self = page; + a->dyn_len++; + return page->data; + } return NULL; } @@ -62,4 +91,5 @@ static void allocr_free_all(Allocator *a) { for (size_t i = 0; i < a->dyn_len; i++) { free(a->dyn[i]); } + free(a->dyn); } @@ -18,7 +18,7 @@ static inline void arr_reserve(Array *arr, size_t n) { static inline void arr_reservea(Array *arr, size_t n, Allocator *a) { arr->cap = n; - arr->data = allocr_realloc(a, arr->data, n); + arr->data = allocr_realloc(a, arr->data, arr->item_sz * arr->cap); } /* like arr_reserve, but sets the length of the array too */ @@ -64,10 +64,6 @@ static void arr_clear(Array *arr) { static void arr_remove_last(Array *arr) { /* OPTIM (memory): Shorten array. */ arr->len--; - if (!arr->len) { - arr_clear(arr); - } - } static void arr_free(Array *arr) { @@ -12,6 +12,22 @@ typedef enum { #define VAL_FLAG_FN_NULL 0x01 /* is this function null? */ +typedef struct { + Allocator allocr; +} Evaluator; + +static void evalr_create(Evaluator *ev) { + allocr_create(&ev->allocr); +} + +static void evalr_free(Evaluator *ev) { + allocr_free_all(&ev->allocr); +} + +static inline void *evalr_malloc(Evaluator *ev, size_t bytes) { + return allocr_malloc(&ev->allocr, bytes); +} + typedef double FloatVal; typedef struct { @@ -348,7 +364,7 @@ static inline void val_promote_to_float(Value *v) { } /* NOTE: expr must be typed before it can be evaluated */ -static bool eval_expr(Expression *e, Value *v) { +static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { switch (e->kind) { case EXPR_LITERAL_FLOAT: v->kind = VAL_FLOAT; @@ -380,7 +396,7 @@ static bool eval_expr(Expression *e, Value *v) { case EXPR_UNARY_OP: { Expression *of_expr = e->unary.of; Value of; - if (!eval_expr(of_expr, &of)) return false; + if (!eval_expr(ev, of_expr, &of)) return false; switch (e->unary.op) { case UNARY_MINUS: { assert(e->type.kind == TYPE_BUILTIN); @@ -421,8 +437,8 @@ static bool eval_expr(Expression *e, Value *v) { Expression *lhs_expr = of_expr->binary.lhs; Expression *rhs_expr = of_expr->binary.rhs; Value lhs, rhs; - if (!eval_expr(lhs_expr, &lhs) - || !eval_expr(rhs_expr, &rhs)) + if (!eval_expr(ev, lhs_expr, &lhs) + || !eval_expr(ev, rhs_expr, &rhs)) return false; assert(lhs.kind == VAL_ARR && (rhs.kind == VAL_INT || rhs.kind == VAL_UINT)); v->ptr = (char *)lhs.arr.data + (Integer)sizeof_val_kind(lhs.arr_kind) @@ -471,8 +487,8 @@ static bool eval_expr(Expression *e, Value *v) { case EXPR_BINARY_OP: { Value lhs, rhs; /* NOTE: this will need to change for short-circuiting */ - if (!eval_expr(e->binary.lhs, &lhs)) return false; - if (!eval_expr(e->binary.rhs, &rhs)) return false; + if (!eval_expr(ev, e->binary.lhs, &lhs)) return false; + if (!eval_expr(ev, e->binary.rhs, &rhs)) return false; if (e->type.kind != TYPE_BUILTIN) { err_print(e->where, "Operators can only be applied to builtin types."); return false; @@ -608,8 +624,8 @@ static bool eval_expr(Expression *e, Value *v) { return false; } if (!d->val) { - d->val = err_malloc(sizeof *d->val); /* OPTIM */ - if (!eval_expr(&d->expr, d->val)) + d->val = evalr_malloc(ev, sizeof *d->val); /* OPTIM */ + if (!eval_expr(ev, &d->expr, d->val)) return false; } *v = *d->val; @@ -626,12 +642,12 @@ static bool eval_expr(Expression *e, Value *v) { break; } Value cond; - if (!eval_expr(i->cond, &cond)) + if (!eval_expr(ev, i->cond, &cond)) return false; if (eval_truthiness(&cond)) { if (!eval_block(&i->body, v)) return false; } else if (i->next_elif) { - if (!eval_expr(i->next_elif, v)) return false; + if (!eval_expr(ev, i->next_elif, v)) return false; } else { v->kind = VAL_VOID; } @@ -641,7 +657,7 @@ static bool eval_expr(Expression *e, Value *v) { return eval_block(&e->block, v); case EXPR_CAST: { Value cast_val; - if (!eval_expr(e->cast.expr, &cast_val)) return false; + if (!eval_expr(ev, e->cast.expr, &cast_val)) return false; if (!val_cast(e->where, v, cast_val, &e->cast.type)) return false; break; } @@ -665,3 +681,4 @@ static bool eval_expr(Expression *e, Value *v) { } return true; } + diff --git a/identifiers.c b/identifiers.c index 6eafc41..08a205c 100644 --- a/identifiers.c +++ b/identifiers.c @@ -60,6 +60,7 @@ static Identifier ident_new(Identifiers *ids, Identifier parent, unsigned char i tree->parent = NULL; for (size_t i = 0; i < TREE_NCHILDREN; i++) tree->children[i] = NULL; + tree->decls.data = NULL; #endif tree->parent = parent; if (parent) @@ -186,6 +187,14 @@ static IdentDecl *ident_decl(Identifier i) { return i->decls.item_sz == 0 ? NULL : (IdentDecl*)arr_last(&i->decls); } +static void ident_tree_free(IdentTree *id) { + if (!id) return; + arr_free(&id->decls); + for (int i = 0; i < TREE_NCHILDREN; i++) + ident_tree_free(id->children[i]); +} + static void idents_free(Identifiers *ids) { + ident_tree_free(ids->root); block_arr_free(&ids->trees); } @@ -14,7 +14,6 @@ int main(int argc, char **argv) { #ifdef TOC_DEBUG test_all(); #endif - return 0; if (argc < 2) { fprintf(stderr, "Please specify an input file.\n"); return EXIT_FAILURE; @@ -67,38 +66,31 @@ int main(int argc, char **argv) { err_fprint(TEXT_IMPORTANT("Errors occured while parsing.\n")); return EXIT_FAILURE; } - + tokr_free_tokens(&t); fprint_parsed_file(stdout, &f); - + printf("\n\n-----\n\n"); block_enter(NULL, &f.stmts); /* enter global scope */ - if (!types_file(&f)) { + Typer tr; + Evaluator ev; + evalr_create(&ev); + typer_create(&tr, &ev); + if (!types_file(&tr, &f)) { err_fprint(TEXT_IMPORTANT("Errors occured while determining types.\n")); return EXIT_FAILURE; } parse_printing_after_types = true; fprint_parsed_file(stdout, &f); + block_exit(NULL, &f.stmts); /* exit global scope */ tokr_free(&t); - - - - /* TODO (eventually): use a tmp file (don't overwrite old output if there's an error) */ - /* const char *c_out_filename = "out.c"; */ - /* const char *h_out_filename = "out.h"; */ - /* FILE *c_out = fopen(c_out_filename, "w"); */ - /* FILE *h_out = fopen(h_out_filename, "w"); */ - /* CGenerator cgen; */ - /* cgen_create(&cgen, &file_idents, c_out, h_out, h_out_filename); */ - /* if (!cgen_file(&cgen, &f)) { */ - /* err_fprint(TEXT_IMPORTANT("Errors occured while generating C code.\n")); */ - /* return EXIT_FAILURE; */ - /* } */ - - block_exit(NULL, &f.stmts); /* exit global scope */ + free(contents); - + + parser_free(&p); + typer_free(&tr); + evalr_free(&ev); /* fclose(c_out); */ /* fclose(h_out); */ idents_free(&file_idents); @@ -428,17 +428,20 @@ static char *type_to_str(Type *t) { return ret; } -/* - allocate a new expression. -*/ -static Expression *parser_new_expr(Parser *p) { - return allocr_malloc(&p->allocr, sizeof(Expression)); +static inline void *parser_arr_add(Parser *p, Array *a) { + return arr_adda(a, &p->allocr); } -static void *parser_arr_add(Parser *p, Array *a) { - return arr_adda(a, &p->allocr); +static inline void *parser_malloc(Parser *p, size_t bytes) { + return allocr_malloc(&p->allocr, bytes); } +/* + allocate a new expression. +*/ +static inline Expression *parser_new_expr(Parser *p) { + return parser_malloc(p, sizeof(Expression)); +} /* TODO: check that we check which thing ends it everywhere */ @@ -586,7 +589,7 @@ static bool parse_type(Parser *p, Type *type) { type->arr.n_expr = parser_new_expr(p); if (!parse_expr(p, type->arr.n_expr, end)) return false; t->token = end + 1; /* go past ] */ - type->arr.of = err_malloc(sizeof *type->arr.of); /* OPTIM */ + type->arr.of = parser_malloc(p, sizeof *type->arr.of); if (!parse_type(p, type->arr.of)) return false; type->flags = 0; type->where = start->where; @@ -616,7 +619,7 @@ static bool parse_type(Parser *p, Type *type) { case KW_AMPERSAND: /* pointer */ type->kind = TYPE_PTR; - type->ptr.of = err_malloc(sizeof *type->ptr.of); /* OPTIM */ + type->ptr.of = parser_malloc(p, sizeof *type->ptr.of); t->token++; /* move past & */ if (!parse_type(p, type->ptr.of)) return false; break; @@ -1565,7 +1568,6 @@ static void parser_free(Parser *p) { allocr_free_all(&p->allocr); } - #define PARSE_PRINT_LOCATION(l) //fprintf(out, "[l%lu]", (unsigned long)(l).line); /* in theory, this shouldn't be global, but these functions are mostly for debugging anyways */ @@ -1577,7 +1579,9 @@ static void fprint_decl(FILE *out, Declaration *d); static void fprint_type(FILE *out, Type *t) { PARSE_PRINT_LOCATION(t->where); - fprintf(out, "%s", type_to_str(t)); + char *s = type_to_str(t); + fprintf(out, "%s", s); + free(s); } @@ -1763,5 +1767,3 @@ static void fprint_parsed_file(FILE *out, ParsedFile *f) { fprint_stmt(out, stmt); } } - -/* TODO: Freeing parser (remember to free args) */ @@ -1,17 +1,17 @@ main @= fn() { - // arr1 : ['a' as u8]int; - // arr2 : [main as u64]int; - // arr3 : [main as i64]int; - // N @= (-10 + (97 as char as f32)) as u32; - // arr4 : [N]int; - // arr5 : [main as u64]int; - // // arr6 : [main as u64 as fn() as u64]int;FIXME - // arr7 : [main as u64 as fn() int as u64]int; + arr1 : ['a' as u8]int; + arr2 : [main as u64]int; + arr3 : [main as i64]int; + N @= (-10 + (97 as char as f32)) as u32; + arr4 : [N]int; + arr5 : [main as u64]int; + // arr6 : [main as u64 as fn() as u64]int;FIXME + arr7 : [main as u64 as fn() int as u64]int; - // str @= "foo"; - // arr8 : [(str[0] as u32) + (str[1] as u32) + (str[2] as u32)]int; - // asdf @= new int; - // arr9 : [asdf as u64]int; - // arr10 : [main as &i32 as u64]int; + str @= "foo"; + arr8 : [(str[0] as u32) + (str[1] as u32) + (str[2] as u32)]int; + asdf @= new int; + arr9 : [asdf as u64]int; + arr10 : [main as &i32 as u64]int; arr11 : [((main as &u64) as [4]u64)[3]]int; }; @@ -11,7 +11,7 @@ static void allocr_test(void) { for (int i = 0; i < nfoos; i++) assert(foos[i] == i); int nbars = x; - int *bars = allocr_calloc(&a, (size_t)nbars * sizeof(int)); + int *bars = allocr_calloc(&a, (size_t)nbars, sizeof(int)); for (int i = 0; i < nbars; i++) assert(bars[i] == 0); for (int i = 0; i < nbars; i++) @@ -38,7 +38,8 @@ static void allocr_test(void) { arr_create(&arr, sizeof(int)); int n = 1000; for (int i = 0; i < n; i++) { - *(int *)arr_adda(&arr, &a) = i; + int *p = arr_adda(&arr, &a); + *p = i; } int *arr_data = arr.data; for (int i = 0; i < n; i++) { diff --git a/tokenizer.c b/tokenizer.c index 7adb7d5..8807b33 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -153,6 +153,7 @@ typedef struct { } Token; typedef struct { + Allocator allocr; Array tokens; char *s; /* string being parsed */ const char *filename; @@ -161,14 +162,10 @@ typedef struct { Identifiers *idents; } Tokenizer; - - static inline bool token_is_kw(Token *t, Keyword kw) { return t->kind == TOKEN_KW && t->kw == kw; } - - static const char *token_kind_to_str(TokenKind t) { switch (t) { case TOKEN_KW: return "keyword"; @@ -288,10 +285,15 @@ static void tokr_get_location(Tokenizer *tokr, Token *t) { static void tokr_create(Tokenizer *t, Identifiers *idents, const char *filename) { arr_create(&t->tokens, sizeof(Token)); arr_reserve(&t->tokens, 256); + allocr_create(&t->allocr); t->idents = idents; t->filename = filename; } +static inline void *tokr_malloc(Tokenizer *t, size_t bytes) { + return allocr_malloc(&t->allocr, bytes); +} + static Token *tokr_add(Tokenizer *t) { Token *token = arr_add(&t->tokens); tokr_put_location(t, token); @@ -552,7 +554,7 @@ static bool tokenize_string(Tokenizer *t, char *str) { len++; tokr_nextchar(t); } - char *strlit = err_malloc(len + 1); + char *strlit = tokr_malloc(t, len + 1); char *strptr = strlit; tokr_get_location(t, token); tokr_nextchar(t); /* past opening " */ @@ -599,7 +601,12 @@ static bool tokenize_string(Tokenizer *t, char *str) { return !has_err; } -/* Does NOT free string literals!!! */ -static void tokr_free(Tokenizer *t) { +/* ONLY frees tokens, not string literals. You can call this followed by tokr_free. */ +static void tokr_free_tokens(Tokenizer *t) { arr_clear(&t->tokens); } + +static void tokr_free(Tokenizer *t) { + tokr_free_tokens(t); + allocr_free_all(&t->allocr); +} @@ -1,4 +1,6 @@ typedef struct { + Allocator allocr; + Evaluator *evalr; Array in_decls; /* array of declarations we are currently inside */ Block *block; bool can_ret; @@ -11,6 +13,18 @@ static bool types_expr(Typer *tr, Expression *e); static bool types_block(Typer *tr, Block *b); static bool type_resolve(Typer *tr, Type *t); +static inline void *typer_malloc(Typer *tr, size_t bytes) { + return allocr_malloc(&tr->allocr, bytes); +} + +static inline void *typer_calloc(Typer *tr, size_t n, size_t sz) { + return allocr_calloc(&tr->allocr, n, sz); +} + +static inline void *typer_arr_add(Typer *tr, Array *arr) { + return arr_adda(arr, &tr->allocr); +} + static bool add_ident_decls(Block *b, Declaration *d) { bool ret = true; arr_foreach(&d->idents, Identifier, ident) { @@ -165,7 +179,7 @@ static bool expr_must_lval(Expression *e) { static bool type_of_fn(Typer *tr, FnExpr *f, Type *t) { t->kind = TYPE_FN; arr_create(&t->fn.types, sizeof(Type)); - Type *ret_type = arr_add(&t->fn.types); + Type *ret_type = typer_arr_add(tr, &t->fn.types); if (!type_resolve(tr, &f->ret_type)) return false; *ret_type = f->ret_type; @@ -175,7 +189,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Type *t) { if (!type_resolve(tr, &decl->type)) return false; for (size_t i = 0; i < decl->idents.len; i++) { - Type *param_type = arr_add(&t->fn.types); + Type *param_type = typer_arr_add(tr, &t->fn.types); *param_type = decl->type; } } @@ -267,7 +281,7 @@ static bool type_resolve(Typer *tr, Type *t) { free(s); return false; } - if (!eval_expr(n_expr, &val)) return false; /* resolve N */ + if (!eval_expr(tr->evalr, n_expr, &val)) return false; /* resolve N */ Integer size = val.intv; if (size < 0) { err_print(t->arr.n_expr->where, "Negative array length (" INTEGER_FMT ")", size); @@ -411,7 +425,7 @@ static bool types_expr(Typer *tr, Expression *e) { case EXPR_LITERAL_STR: t->kind = TYPE_ARR; t->arr.n = e->strl.len; - t->arr.of = err_malloc(sizeof *t->arr.of); + t->arr.of = typer_malloc(tr, sizeof *t->arr.of); t->arr.of->flags = TYPE_FLAG_RESOLVED; t->arr.of->kind = TYPE_BUILTIN; t->arr.of->builtin = BUILTIN_CHAR; @@ -442,7 +456,7 @@ static bool types_expr(Typer *tr, Expression *e) { } break; case EXPR_NEW: t->kind = TYPE_PTR; - t->ptr.of = err_malloc(sizeof *t->ptr.of); + t->ptr.of = typer_malloc(tr, sizeof *t->ptr.of); t->ptr.of = &e->new.type; if (!type_resolve(tr, t)) return false; @@ -534,7 +548,7 @@ static bool types_expr(Typer *tr, Expression *e) { arr_create(&new_args_arr, sizeof(Expression)); arr_set_len(&new_args_arr, nparams); Expression *new_args = new_args_arr.data; - bool *params_set = calloc(nparams, sizeof *params_set); + bool *params_set = typer_calloc(tr, nparams, sizeof *params_set); if (f->kind == EXPR_IDENT) { IdentDecl *decl = ident_decl(f->ident); assert(decl); @@ -684,7 +698,7 @@ static bool types_expr(Typer *tr, Expression *e) { return false; } t->kind = TYPE_PTR; - t->ptr.of = err_malloc(sizeof *t->ptr.of); /* OPTIM */ + t->ptr.of = typer_malloc(tr, sizeof *t->ptr.of); /* OPTIM */ *t->ptr.of = *of_type; break; case UNARY_DEREF: @@ -819,19 +833,19 @@ static bool types_expr(Typer *tr, Expression *e) { if (lhs_type->kind == TYPE_TUPLE) { /* tuple, x => tuple */ arr_foreach(&lhs_type->tuple, Type, child) { - *(Type*)arr_add(tup_types) = *child; + *(Type*)typer_arr_add(tr, tup_types) = *child; } } else { - *(Type*)arr_add(tup_types) = *lhs_type; + *(Type*)typer_arr_add(tr, tup_types) = *lhs_type; } if (rhs_type->kind == TYPE_TUPLE) { /* x, tuple => tuple */ arr_foreach(&rhs_type->tuple, Type, child) { - *(Type*)arr_add(tup_types) = *child; + *(Type*)typer_arr_add(tr, tup_types) = *child; } } else { - *(Type*)arr_add(tup_types) = *rhs_type; + *(Type*)typer_arr_add(tr, tup_types) = *rhs_type; } } break; } @@ -866,7 +880,7 @@ static bool types_block(Typer *tr, Block *b) { static bool types_decl(Typer *tr, Declaration *d) { bool success = true; if (d->flags & DECL_FLAG_FOUND_TYPE) goto ret; - Declaration **dptr = arr_add(&tr->in_decls); + Declaration **dptr = typer_arr_add(tr, &tr->in_decls); *dptr = d; if (d->flags & DECL_FLAG_ANNOTATES_TYPE) { /* type supplied */ @@ -898,8 +912,8 @@ static bool types_decl(Typer *tr, Declaration *d) { } if (d->flags & DECL_FLAG_CONST) { if (!d->val) { - d->val = err_malloc(sizeof *d->val); /* OPTIM */ - if (!eval_expr(&d->expr, d->val)) { + d->val = typer_malloc(tr, sizeof *d->val); /* OPTIM */ + if (!eval_expr(tr->evalr, &d->expr, d->val)) { success = false; goto ret; } @@ -963,19 +977,24 @@ static bool types_stmt(Typer *tr, Statement *s) { return true; } -static void typer_create(Typer *tr) { +static void typer_create(Typer *tr, Evaluator *ev) { tr->block = NULL; tr->can_ret = false; + tr->evalr = ev; arr_create(&tr->in_decls, sizeof(Declaration *)); + allocr_create(&tr->allocr); } -static bool types_file(ParsedFile *f) { - Typer tr; - typer_create(&tr); +static bool types_file(Typer *tr, ParsedFile *f) { + bool ret = true; arr_foreach(&f->stmts, Statement, s) { - if (!types_stmt(&tr, s)) { - return false; + if (!types_stmt(tr, s)) { + ret = false; } } - return true; + return ret; +} + +static void typer_free(Typer *tr) { + allocr_free_all(&tr->allocr); } |