diff options
author | kartofen <mladenovnasko0@gmail.com> | 2024-08-30 17:01:28 +0300 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2024-08-30 17:01:28 +0300 |
commit | e1ceef73192f0300ff9b10ba9a16475fbebeaa5f (patch) | |
tree | 0cb2bc5336a522b965c1d171b433044591721e20 | |
parent | de3a062bfc206bf0373f96f4f6cc8c74ffcbab48 (diff) |
proper repl, stylistic changes, removed trailing whitespace
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | files/test-lambda.l | 41 | ||||
-rw-r--r-- | src/builtin.h | 78 | ||||
-rw-r--r-- | src/common.h | 12 | ||||
-rw-r--r-- | src/env.c | 12 | ||||
-rw-r--r-- | src/hashtable.c | 32 | ||||
-rw-r--r-- | src/lexer.c | 26 | ||||
-rw-r--r-- | src/lexer.h | 5 | ||||
-rw-r--r-- | src/main.c | 115 | ||||
-rw-r--r-- | src/memdebug.h | 30 | ||||
-rw-r--r-- | src/value.c | 144 | ||||
-rw-r--r-- | src/value.h | 6 |
12 files changed, 296 insertions, 207 deletions
@@ -59,4 +59,4 @@ valgrind: $(NAME) valgrind -s --leak-check=full --show-leak-kinds=all $(BIN)/$(NAME) cppcheck: clean - cppcheck --enable=all $(SRCS) 2> cppcheck.log + cppcheck --enable=all $(SRCS) --check-level=exhaustive 2> cppcheck.log diff --git a/files/test-lambda.l b/files/test-lambda.l index e088ad6..71ef0bd 100644 --- a/files/test-lambda.l +++ b/files/test-lambda.l @@ -4,20 +4,47 @@ '(a b ,((lambda (a) '(test . ,a)) 69) c d) -(define fib (lambda (c) (fib-rec 0 1 0 c))) -(define fib-rec (lambda (a b n c) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define fib (lambda (c) (_fib 0 1 0 c))) +(define _fib (lambda (a b n c) (if (= n c) b - (fib-rec b (+ a b) (+ n 1) c)))) + (_fib b (+ a b) (+ n 1) c)))) + + -(define do (lambda (c f) (do-rec f 0 0 c))) -(define do-rec (lambda (f r n c) + +(define do (lambda (c f) (_do f '() 0 c))) + +(define _do (lambda (f r n c) (if (= n c) r - (do-rec f (f n) (+ n 1) c)))) + (_do f (cons (f n) r) (+ n 1) c)))) ;; comment ;; another comment ;; fib(13) -(do 10 (lambda (n) (display (fib n)))) ; comment +;(do 10 (lambda (n) (display (fib n)))) ; comment + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define +list (lambda (l) (_+list l 0))) +(define _+list (lambda (l acc) + (if (nil? l) + acc + (_+list (cdr l) (+ acc (car l)))))) +(+list '(10 12)) + +(define * (lambda (a n) (+list (do n (lambda (n) a))))) + +(* 9 7) + +(define reverse (lambda (l) (_reverse l '()))) +(define _reverse (lambda (l n) + (if (nil? l) n + (_reverse (cdr l) (cons (car l) n))))) + +;; (+list (do 100 (lambda (n) (fib n)))) +(reverse (do 100 (lambda (n) (fib n)))) diff --git a/src/builtin.h b/src/builtin.h index 43d7ee2..51dd89c 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -8,17 +8,16 @@ X(cons, "cons", 2) \ X(car, "car", 1) \ X(cdr, "cdr", 1) \ - X(display,"display", 1) \ + X(display,"display", 1) \ + X(is_nil, "nil?", 1) \ // Number of builtin procedures #define PLUS_ONE(_symbol, _name, _argc) 1 + #define BUILTIN_PROCEDURES PROCEDURES(PLUS_ONE) 0 // Forward decalration of the procedures -#define DECLARE_PROCEDURE(proc) value_t proc(value_t *args) #define FORWARD_DECLARATION(symbol, _name, _argc) \ - DECLARE_PROCEDURE(symbol); - + value_t symbol(value_t *args); PROCEDURES(FORWARD_DECLARATION) // Fill procedure struct for the value_t @@ -39,40 +38,34 @@ const char *builtin_proc_name_list[] = { // ----- Definitions ----- -#define ASSERT_TYPE(proc, args, pos, vtype, fail) \ - if(args[pos]->type != vtype) { \ - err("Expected arg %d of %s to be %s instead of %s", \ - pos, #proc, "", ""); \ - fail; \ +#define ASSERT_TYPE(proc, args, pos, vtype, fail) \ + if(args[pos]->type != vtype) { \ + err("Expected arg %d of '%s' to be %s instead of %s", \ + pos, #proc, \ + value_type_string[vtype], \ + value_type_string[args[pos]->type]); \ + fail; \ } -#define PROC_ASSERT_TYPE(pos, vtype, fail) \ - ASSERT_TYPE(P, args, pos, vtype, fail) - -#define P plus -DECLARE_PROCEDURE(P) +value_t plus(value_t *args) { - PROC_ASSERT_TYPE(0, VALUE_INT, return VALUE_EMPTY); - PROC_ASSERT_TYPE(1, VALUE_INT, return VALUE_EMPTY); + ASSERT_TYPE(plus, args, 0, VALUE_INT, return VALUE_EMPTY); + ASSERT_TYPE(plus, args, 1, VALUE_INT, return VALUE_EMPTY); int sum = args[0]->value.num + args[1]->value.num; return value_create(VALUE_INT, &sum); } -#undef P -#define P minus -DECLARE_PROCEDURE(P) +value_t minus(value_t *args) { - PROC_ASSERT_TYPE(0, VALUE_INT, return VALUE_EMPTY); - PROC_ASSERT_TYPE(1, VALUE_INT, return VALUE_EMPTY); + ASSERT_TYPE(minus, args, 0, VALUE_INT, return VALUE_EMPTY); + ASSERT_TYPE(minus, args, 1, VALUE_INT, return VALUE_EMPTY); int difference = args[0]->value.num - args[1]->value.num; return value_create(VALUE_INT, &difference); } -#undef P -#define P equal -DECLARE_PROCEDURE(P) +value_t equal(value_t *args) { int f = 0; int t = 1; @@ -90,48 +83,45 @@ l_false: l_true: return value_create(VALUE_INT, &t); } -#undef P -#define P cons -DECLARE_PROCEDURE(P) +value_t cons(value_t *args) { struct cons cons = {value_copy(args[0]), value_copy(args[1])}; return value_create(VALUE_CONS, &cons); } -#undef P -#define P car -DECLARE_PROCEDURE(P) +value_t car(value_t *args) { - PROC_ASSERT_TYPE(0, VALUE_CONS, return VALUE_EMPTY); + ASSERT_TYPE(car, args, 0, VALUE_CONS, return VALUE_EMPTY); value_t left = value_copy(args[0]->value.cons.left); return left; } -#undef P -#define P cdr -DECLARE_PROCEDURE(P) +value_t cdr(value_t *args) { - PROC_ASSERT_TYPE(0, VALUE_CONS, return VALUE_EMPTY); + ASSERT_TYPE(cdr, args, 0, VALUE_CONS, return VALUE_EMPTY); value_t right = value_copy(args[0]->value.cons.right); return right; } -#undef P -#define P display -DECLARE_PROCEDURE(P) +value_t display(value_t *args) { char buf[256]; - value_string(args[0], (sizeof(buf)/sizeof(*buf)), buf); + value_string(args[0], sizeof(buf), buf); + + // if(bytes > sizeof(buf)) ... - #ifdef DEBUG - info("%s", buf); - #else printf("%s\n", buf); - #endif return value_copy(args[0]); } -#undef P + +value_t is_nil(value_t *args) +{ + int f = 0, t = 1; + if(args[0]->type == VALUE_NIL) + return value_create(VALUE_INT, &t); + return value_create(VALUE_INT, &f); +} diff --git a/src/common.h b/src/common.h index b91459a..225f217 100644 --- a/src/common.h +++ b/src/common.h @@ -11,8 +11,15 @@ #define _YELLOW "\033[0;33m" #define _RST "\033[0m" -#define _log_print(...) fprintf(stdout, __VA_ARGS__) +#define _log_print(...) fprintf(stderr, __VA_ARGS__) + +#ifdef DEBUG #define _log(color, message) _log_print("[%s] %s%-7s"_RST" ", timenow(), color, message) +#define _log_file() _log_print(__FILE__":%d: ", __LINE__) +#else +#define _log(color, message) _log_print("%s%-7s"_RST" ", color, message) +#define _log_file() +#endif #define info(...) do { \ _log(_GREEN, "[INFO]"); \ @@ -20,7 +27,7 @@ } while(0) #define err(...) do { \ _log(_RED, "[ERROR]"); \ - _log_print(__FILE__":%d: ", __LINE__); \ + _log_file(); \ _log_print(__VA_ARGS__); _log_print("\n"); \ } while(0) #define die(...) do { \ @@ -95,4 +102,3 @@ DIE_ALLOC_BUILDER(realloc, (void *ptr, size_t size), (ptr, size)) // #endif #endif - @@ -8,7 +8,7 @@ #define ENV_TABLE_CAP (1 << 8) static unsigned long str_hash(char *str) -{ +{ unsigned long hash = 5381; int c; @@ -38,20 +38,20 @@ env_t env_create(env_t parent, env_destroy_func destroy_func) env->destroy_func = destroy_func; env->parent = parent; env->refs = 1; - + ERR_Z(env->table = hashtable_create(ENV_TABLE_CAP, hash, equal), env_destroy(env)); - + return env; } void env_destroy(env_t env) { if(!env) return; - + env->refs--; env_destroy(env->parent); - + if(env->refs > 0) return; hashtable_for_each_item(env->table, item, i) { @@ -65,7 +65,7 @@ void env_destroy(env_t env) env_t env_copy(env_t env) { if(env == ENV_EMPTY) return ENV_EMPTY; - + env->refs++; env_copy(env->parent); diff --git a/src/hashtable.c b/src/hashtable.c index 5ef1839..9f5d2e1 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -25,7 +25,7 @@ hashtable_t hashtable_create(size_t cap, hashtable_hash_func hash_func, hashtabl ht->size = 0; ERR_ERRNO_SET(hashtable_grow(ht, cap), goto fail); - + return ht; fail: hashtable_destroy(ht); @@ -35,15 +35,15 @@ fail: void hashtable_destroy(hashtable_t ht) { if(!ht) return; - + if(ht->table) { hashtable_for_each_item_safe(ht, item, i) { free(item); } - + free(ht->table); } - + free(ht); } @@ -66,7 +66,7 @@ int hashtable_insert(hashtable_t ht, void *key, void *data, void **prevkey, void struct hashtable_item *item, *prev; hashtable_find_item(ht, idx, key, &item, &prev); - + if(item) { if(prevkey) *prevkey = item->key; if(prevdata) *prevdata = item->data; @@ -74,49 +74,49 @@ int hashtable_insert(hashtable_t ht, void *key, void *data, void **prevkey, void item->data = data; return 0; } - + ERR_Z(item = malloc(sizeof(*item)), return -ENOMEM); - + item->key = key; item->data = data; item->next = NULL; hashtable_table_append_item(ht->table, idx, item); ht->size++; - + if(ht->size > (ht->cap * 3/4)) { return hashtable_grow(ht, 1 << ht->cap); } - + return 0; } int hashtable_query(hashtable_t ht, void *key, void **data) { size_t idx = HASH(ht, key); - + struct hashtable_item *item; ERR_NZ_RET(hashtable_find_item(ht, idx, key, &item, NULL)); *data = item->data; - + return 0; } int hashtable_delete(hashtable_t ht, void *key) { size_t idx = HASH(ht, key); - + struct hashtable_item *item, *prev; ERR_NZ_RET(hashtable_find_item(ht, idx, key, &item, &prev)); - + if(prev) prev->next = item->next; else ht->table[idx] = item->next; free(item); - + return 0; } @@ -137,7 +137,7 @@ static int hashtable_grow(hashtable_t ht, size_t cap) ht->table = new_table; ht->cap = cap; - + return 0; } @@ -153,7 +153,7 @@ static int hashtable_find_item(hashtable_t ht, size_t idx, void *key, struct has } if(prev) *prev = _item; } - + return -ENOENT; } diff --git a/src/lexer.c b/src/lexer.c index b546fda..93c7f44 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -7,7 +7,7 @@ #define CH(lexer) (lexer)->str[(lexer)->str_idx] #define TOKEN_SEPARATOR_TABLE(X, l) \ - X((';' == CH(l)), CH(l) = '\0') \ + X((';' == CH(l)), lexer_clear_line(l)) \ X(('(' == CH(l)), on_separator(l, TOKEN_LP)) \ X((')' == CH(l)), on_separator(l, TOKEN_RP)) \ X(('\''== CH(l)), on_separator(l, TOKEN_QUOTE)) \ @@ -78,7 +78,7 @@ lexer_t lexer_create(FILE *fp) lexer->acc_idx = 0; memset(lexer->acc, 0, sizeof(lexer->acc)); memset(lexer->str, 0, sizeof(lexer->str)); - + lexer->token.type = TOKEN_NONE; return lexer; @@ -90,12 +90,18 @@ void lexer_destroy(lexer_t lexer) free(lexer); } +int lexer_clear_line(lexer_t lexer) +{ + lexer->str[lexer->str_idx] = '\0'; + return 0; +} + int lexer_token_next(lexer_t lexer, struct token *token) { if(lexer->acc_idx == 0 && lexer->acc[0] != '\0') { memset(lexer->acc, 0, sizeof(lexer->acc)); } - + while(lexer->token.type == TOKEN_NONE) { if(lexer->str[lexer->str_idx] == '\0') { @@ -103,10 +109,10 @@ int lexer_token_next(lexer_t lexer, struct token *token) lexer->str_idx = 0; lexer->line++; } - + TOKEN_SEPARATOR_TABLE(CALLBACK, lexer) TABLE_END; } - + *token = lexer->token; lexer->token.type = TOKEN_NONE; return 0; @@ -116,7 +122,7 @@ int token_value_string(struct token *token, size_t buf_sz, char *buf) { #define AS_STRING(ttype, ...) \ case ttype: return snprintf(buf, buf_sz, __VA_ARGS__); - + switch(token->type) { TOKEN_VALUE_STRING_TABLE(AS_STRING, token->value); } @@ -175,7 +181,7 @@ static int acc_add_char(lexer_t lexer, char ch) if(lexer->acc_idx >= LEN(lexer->acc) - 1) { return -ENAMETOOLONG; } - + lexer->acc[lexer->acc_idx++] = ch; lexer->str_idx++; @@ -183,10 +189,10 @@ static int acc_add_char(lexer_t lexer, char ch) } static int acc_empty(lexer_t lexer) -{ +{ TOKEN_VALUE_TABLE(CALLBACK_BLIND, lexer) TABLE_END; lexer->acc_idx = 0; - + return 0; } @@ -210,6 +216,6 @@ static int is_special(char *str, enum token_type *type) } else TOKEN_SPECIALS_TABLE(IS_SPECIAL) TABLE_END; - + return 0; } diff --git a/src/lexer.h b/src/lexer.h index b47f800..e40ab05 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -27,7 +27,7 @@ struct token { enum token_type { TOKEN_TYPES(TO_ENUM) } type; - + union { char *id; char *str; @@ -41,7 +41,7 @@ typedef struct lexer * lexer_t; struct lexer { FILE *fp; size_t line; - + char str[256]; size_t str_idx; @@ -52,6 +52,7 @@ struct lexer { lexer_t lexer_create(FILE *fp); void lexer_destroy(lexer_t lexer); +int lexer_clear_line(lexer_t lexer); int lexer_token_next(lexer_t lexer, struct token *token); int token_value_string(struct token *token, size_t buf_sz, char *buf); @@ -1,6 +1,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <getopt.h> #include "lexer.h" #include "value.h" @@ -9,7 +10,6 @@ #ifdef ENABLE_MEMDEBUG #define MEMDEBUG_OUT_OF_BOUNDS #define MEMDEBUG_IMPLEMENTATION -#define MEMDEBUG_MAIN_VOID #define MEMDEBUG_OUTPUT_DIR "files" #endif @@ -22,7 +22,7 @@ // - Think about memory leakage and on non fatal errors // like failed list creation and faild s-exp parsing // - Check for functions not wrapped in ERR_* macro -// - Add more error messages +// - Add more and better error messages #define TOKEN(tctx) (tctx)->token @@ -120,10 +120,6 @@ static struct token *next_token(struct tctx *tctx) break; } - #ifdef DEBUG - // print_token(tctx->token); - #endif - return tctx->token; fail: tctx->token = NULL; @@ -147,6 +143,7 @@ value_t quote_sexp(env_t env, struct tctx *tctx); size_t toklist_expr(struct tctx *tctx, struct token **toklist); static env_t global_env = ENV_EMPTY; +static value_t global_nil = VALUE_EMPTY; static void destroy_env(char *key, value_t value) { @@ -160,22 +157,40 @@ static void destroy_global_env(char *key, value_t value) value_destroy(value); } -int main(void) +int main(int argc, char **argv) { + int opt, repl_flag = 0; +#ifdef DEBUG char *filename = "files/test-lambda.l"; +#else + char *filename = NULL; +#endif - FILE *fp = fopen(filename, "r"); - if(!fp) { - die("fopen: %s", strerror(errno)); + while((opt = getopt(argc, argv, "rhf:")) != -1) { + switch(opt) { + case 'h': + printf("help????"); + return 0; + case 'r': repl_flag = 1; break; + case 'f': filename = optarg; break; + default: + err("No such option %c", opt); + return 1; + } } - lexer_t lexer = lexer_create(fp); + if(optind < argc) { + filename = argv[optind]; + } + + if(!filename) repl_flag = 1; + env_t builtin_env = env_create(ENV_EMPTY, destroy_env); global_env = env_create(builtin_env, destroy_global_env); + global_nil = value_create(VALUE_NIL, NULL); - // add builtins for(size_t i = 0; i < BUILTIN_PROCEDURES; i++) { value_t proc_value = value_create( VALUE_PROC_BUILTIN, @@ -185,28 +200,51 @@ int main(void) (void *)proc_value, NULL, NULL); } + FILE *fp = stdin; + if(!repl_flag) { + fp = fopen(filename, "r"); + if(!fp) { + die("fopen: %s", strerror(errno)); + } + } + + lexer_t lexer = lexer_create(fp); + struct tctx tctx = {0}; tctx_init_lexer(&tctx, lexer); + if(repl_flag) printf("> "); while(next_token(&tctx)) { value_t val = evaluate_expr(ENV_EMPTY, &tctx); - #ifdef DEBUG - info("Line %zu evaluates to:", lexer->line); - print_value(val); - #else - char buf[256] = {0}; - value_string(val, LEN(buf), buf); - printf("%s:%zu: %s\n", filename, lexer->line, buf); - #endif + if(val == VALUE_EMPTY) { + if(!repl_flag) { + printf("%s:%zu: FAILED\n", filename, lexer->line); + break; + } else { + printf("=> FAILED\n"); + lexer_clear_line(lexer); + } + } else { + char buf[256] = {0}; + value_string(val, sizeof(buf), buf); + + if(!repl_flag) { + printf("%s:%zu: %s\n", filename, lexer->line, buf); + } else { + printf("=> %s\n", buf); + } + } + if(repl_flag) printf("> "); value_destroy(val); } lexer_destroy(lexer); fclose(fp); + value_destroy(global_nil); env_destroy(global_env); return 0; } @@ -243,8 +281,7 @@ exit: value_t apply(value_t proc, size_t argc, value_t *argv) { - // TODO: make a global nil and copy it - if(proc == VALUE_EMPTY) return value_create(VALUE_NIL, NULL); + if(proc == VALUE_EMPTY) return value_copy(global_nil); switch(proc->type) { case VALUE_PROC: @@ -338,23 +375,8 @@ value_t evaluate_sexp(env_t env, struct tctx *tctx) TOKEN_NEXT(tctx); } -#ifdef DEBUG - // info("------------------"); - // info("Applying procedure"); - // print_value(body[0]); - // info("With Arguemnts"); - // if(argc > 0) - // for(size_t i = 0; i < argc-1; i++) print_value(body[i+1]); -#endif - ret = apply(body[0], argc-1, &body[1]); -#ifdef DEBUG - // info("Returns"); - // print_value(ret); - // info("-----------------"); -#endif - exit: for(size_t i = 0; i < argc; i++) value_destroy(body[i]); @@ -488,7 +510,7 @@ value_t evaluate_define(env_t env, struct tctx *tctx) if(prevkey) free(prevkey); value_destroy(prevval); - return VALUE_EMPTY; + return value_copy(global_nil); fail: if(key) free(key); @@ -504,6 +526,13 @@ value_t evaluate_if(env_t env, struct tctx *tctx) ERR_Z(cond = evaluate_expr(env, tctx), goto exit); + // if(cond->type == VALUE_NIL) { + // toklist_expr(tctx, NULL); // skip one expression + // TOKEN_NEXT(tctx); + // TOKEN_MATCH(tctx, TOKEN_RP, goto exit); + // goto exit; + // } + ERR_Z(cond->type == VALUE_INT, err("expected condition to evaluate to VALUE_INT"); goto exit); @@ -567,16 +596,11 @@ value_t quote_sexp(env_t env, struct tctx *tctx) value_t ret = VALUE_EMPTY; value_t left = VALUE_EMPTY; value_t right = VALUE_EMPTY; - value_t nil = VALUE_EMPTY; - - // TODO: make global nil and copy it - ERR_Z(nil = value_create(VALUE_NIL, NULL), goto exit); TOKEN_SKIP(tctx, TOKEN_LP, goto exit); - // Parse NIL if(TOKEN(tctx)->type == TOKEN_RP) { - ret = value_copy(nil); + ret = value_copy(global_nil); goto exit; } @@ -596,7 +620,7 @@ value_t quote_sexp(env_t env, struct tctx *tctx) } // Parse list - right = value_copy(nil); + right = value_copy(global_nil); value_t *rightmost = &right; // the final nil while(TOKEN(tctx)->type != TOKEN_RP) { @@ -636,7 +660,6 @@ value_t quote_sexp(env_t env, struct tctx *tctx) exit: value_destroy(left); value_destroy(right); - value_destroy(nil); return ret; } diff --git a/src/memdebug.h b/src/memdebug.h index d219397..358203a 100644 --- a/src/memdebug.h +++ b/src/memdebug.h @@ -15,7 +15,7 @@ * - MEMDEBUG_OUTPUT_DIR - set the directory for the log, * by default it is the current directory (automatically * enables the MEMDEBUG_OUTPUT_LOG - */ + */ void *__memdebug_malloc(size_t size, char *file, int line); void *__memdebug_calloc(size_t nmemb, size_t size, char *file, int line); @@ -48,7 +48,7 @@ void __memdebug_free(void *ptr, char *file, int line); #define MEMDEBUG_OUTPUT_DIR "." #endif -#ifdef MEMDEBUG_OUTPUT_LOG +#ifdef MEMDEBUG_OUTPUT_LOG #define MEMDEBUG_OUTPUT_FMT "memdebug-%lu.log" #endif @@ -103,7 +103,7 @@ void *__memdebug_malloc(size_t size, char *file, int line) #endif MEMDEBUG_LOG_FUNC(malloc, addr, file, line); - + MEMDEBUG_LOG("size: %zu, ret: %p", size, addr); MEMDEBUG_LOG("\n"); @@ -120,9 +120,9 @@ void *__memdebug_realloc(void *ptr, size_t size, char *file, int line) ptr, size + MEMDEBUG_OUT_OF_BOUNDS_EXTRA_SIZE); MEMDEBUG_OUT_OF_BOUNDS_CHECK(addr, size); #endif - + MEMDEBUG_LOG_FUNC(realloc, addr, file, line); - + MEMDEBUG_LOG("ptr: %p, size: %zu, ret: %p", ptr, size, addr); MEMDEBUG_LOG("\n"); @@ -140,9 +140,9 @@ void *__memdebug_calloc(size_t nmemb, size_t size, char *file, int line) MEMDEBUG_OUT_OF_BOUNDS_CHECK(addr, nmemb * size); memset(addr, 0, nmemb * size); #endif - + MEMDEBUG_LOG_FUNC(calloc, addr, file, line); - + MEMDEBUG_LOG("nmemb: %zu, size: %zu, ret: %p", nmemb, size, addr); MEMDEBUG_LOG("\n"); @@ -151,9 +151,9 @@ void *__memdebug_calloc(size_t nmemb, size_t size, char *file, int line) } void __memdebug_free(void *ptr, char *file, int line) -{ +{ MEMDEBUG_LOG_FUNC(free, (void *)1, file, line); - + MEMDEBUG_LOG("ptr: %p", ptr); #ifdef MEMDEBUG_OUT_OF_BOUNDS @@ -164,11 +164,11 @@ void __memdebug_free(void *ptr, char *file, int line) MEMDEBUG_LOG(", "); MEMDEBUG_LOG("out-of-bounds-check: "); - + if(suffix == (memdebug_suffix)MEMDEBUG_MAGIC_SUFFIX) MEMDEBUG_LOG("SUCCESS"); else MEMDEBUG_LOG("FAILED"); - + ptr -= sizeof(size_t); } #endif @@ -193,15 +193,15 @@ int main(int argc, char **argv) (void)argc; (void)argv; #endif - + #ifdef MEMDEBUG_OUTPUT_LOG size_t filename_sz = 64 + sizeof(MEMDEBUG_OUTPUT_DIR) + sizeof(MEMDEBUG_OUTPUT_FMT); char *filename = malloc(filename_sz); if(!filename) return -ENOMEM; - + memset(filename, 0, filename_sz); snprintf(filename, filename_sz, MEMDEBUG_OUTPUT_DIR"/"MEMDEBUG_OUTPUT_FMT, time(NULL)); - + _memdebug_fp = fopen(filename, "w"); if(!_memdebug_fp) { perror(filename); @@ -210,7 +210,7 @@ int main(int argc, char **argv) } int ret = CALL_MAIN; - + fclose(_memdebug_fp); free(filename); return ret; diff --git a/src/value.c b/src/value.c index d7df858..54c0d20 100644 --- a/src/value.c +++ b/src/value.c @@ -5,14 +5,6 @@ #include "value.h" #include "lexer.h" -// TODO: -// - create VALUE_MANAGE_TABLE which manages -// both creation and destruction -// - check the buffer size in cons creation - -// FIX: -// - remove warning for void pointer cast at line 30 - #define NOT_IMPLEMENTED() die("Not Implemented. ABORTING") const char * const value_type_string[] = { @@ -21,7 +13,7 @@ const char * const value_type_string[] = { #define VALUE(_value) (_value)->value -#define FN(fn, ...) fn(buf, buf_sz, __VA_ARGS__) +#define FN(fn, ...) return fn(buf, buf_sz, __VA_ARGS__) #define VALUE_STRING_TABLE(X, v, buf, buf_sz) \ X(VALUE_NIL, FN(snprintf, "(nil)")) \ X(VALUE_ATOM, FN(snprintf, "%s", VALUE(v).atom)) \ @@ -44,23 +36,51 @@ const char * const value_type_string[] = { X(VALUE_PROC, if(NOREFS(v)) proc_destroy(&VALUE(v).proc)) \ X(VALUE_PROC_BUILTIN, (void)NOREFS(v)) -#define CASE_RETURN_APPLY(vtype, apply) \ - case vtype: return apply; -#define CASE_APPLY_BREAK(vtype, apply) \ - case vtype: apply; break; +#define CREATE(vtype, value) return value_create(vtype, value) +#define VALUE_FROM_TOKEN_TABLE(X, t) \ + X(TOKEN_INT, CREATE(VALUE_INT, &t->value.num)) \ + X(TOKEN_STR, \ + char *str = str_alloc_copy(t->value.str); \ + CREATE(VALUE_STR, &str)) \ + X(TOKEN_ID, \ + char *atom = str_alloc_copy(t->value.id); \ + CREATE(VALUE_ATOM, &atom)) + +#define CASE_APPLY(vtype, apply) \ + case vtype: ; apply; break; + +#define VALUE_MEMBER_TABLE(X) \ + X(VALUE_ATOM, atom) \ + X(VALUE_STR, str) \ + X(VALUE_INT, num) \ + X(VALUE_CONS, cons) \ + X(VALUE_PROC, proc) \ + X(VALUE_PROC_BUILTIN, proc_builtin) + + +static char *str_alloc_copy(char *src); static int cons_print(char *buf, size_t buf_sz, struct cons *cons); static int proc_print(char *buf, size_t buf_sz, struct proc *proc); -// static value_t proc_create(...); static void proc_destroy(struct proc *proc); + +#define MEMBER_COPY(vtype, member) \ + case vtype: memcpy(&_value->value.member, value, \ + sizeof(_value->value.member)); \ + break; + value_t value_create(enum value_type type, void *value) { value_t _value = malloc(sizeof(*_value)); _value->type = type; - if(value != NULL) - _value->value = *(union value_union *)value; + + switch(type) { + VALUE_MEMBER_TABLE(MEMBER_COPY); + default: break; + } + _value->refs = 1; return _value; @@ -69,35 +89,20 @@ value_t value_create(enum value_type type, void *value) void value_destroy(value_t value) { if(!value) return; - + switch(value->type) { - VALUE_DESTROY_TABLE(CASE_APPLY_BREAK, value); + VALUE_DESTROY_TABLE(CASE_APPLY, value); } if(value->refs == 0) free(value); } -#define STR_ALLOC_COPY(dest, str) do { \ - size_t len = strlen(str) + 1; \ - dest = malloc(len); \ - memcpy((dest), (str), len); \ - } while(0) - value_t value_from_token(struct token *token) -{ +{ switch(token->type) { - case TOKEN_ID: ; - char *atom = NULL; - STR_ALLOC_COPY(atom, token->value.id); - return value_create(VALUE_ATOM, &atom); - case TOKEN_STR: ; - char *str = NULL; - STR_ALLOC_COPY(str, token->value.str); - return value_create(VALUE_STR, &str); - case TOKEN_INT: - return value_create(VALUE_INT, &token->value); + VALUE_FROM_TOKEN_TABLE(CASE_APPLY, token) default: err("Cannot turn token '%s' to a value", token_type_string[token->type]); @@ -108,59 +113,90 @@ value_t value_from_token(struct token *token) value_t value_copy(value_t value) { if(!value) return value; - + value->refs++; - + if(value->type == VALUE_CONS) { value_copy(value->value.cons.left); value_copy(value->value.cons.right); } - + return value; } int value_string(value_t value, size_t buf_sz, char *buf) { if(!value) return snprintf(buf, buf_sz, "(empty)"); - + switch(value->type) { - VALUE_STRING_TABLE(CASE_RETURN_APPLY, value, buf, buf_sz) + VALUE_STRING_TABLE(CASE_APPLY, value, buf, buf_sz) } return 0; } +static char *str_alloc_copy(char *src) +{ + if(!src) return src; + + size_t len = strlen(src) + 1; + return memcpy(malloc(len), src, len); +} + static int cons_print(char *buf, size_t buf_sz, struct cons *cons) { - // TODO: check for size and off by one errors - int offset = 0; - buf[offset++] = '('; - offset += value_string(cons->left, buf_sz-offset, buf+offset); +#define HAS_SPACE if(offset < buf_sz) +#define SET_CHAR(ch) HAS_SPACE { buf[offset++] = ch; } +#define SET_VALUE_STRING(v) \ + HAS_SPACE { \ + offset += value_string(v, buf_sz-offset, buf+offset); \ + } /*else { \ + offset += value_string(v, 0, NULL); \ + } */ + + size_t offset = 0; + + SET_CHAR('('); + SET_VALUE_STRING(cons->left); value_t right = cons->right; while(right->type == VALUE_CONS) { - buf[offset++] = ' '; - offset += value_string(right->value.cons.left, - buf_sz-offset, buf+offset); + SET_CHAR(' '); + SET_VALUE_STRING(right->value.cons.left) right = right->value.cons.right; } if(right->type != VALUE_NIL) { - buf[offset++] = ' '; - buf[offset++] = '.'; - buf[offset++] = ' '; - offset += value_string(right, buf_sz-offset, buf+offset); + SET_CHAR(' '); + SET_CHAR('.'); + SET_CHAR(' '); + SET_VALUE_STRING(right); + } + + SET_CHAR(')'); + + SET_CHAR('\0') else { + if(buf_sz == 0) goto exit; + + char str[] = "...)"; + + if(buf_sz <= sizeof(str)) { + buf[0] = '\0'; + goto exit; + } + + memcpy(buf+buf_sz - sizeof(str), str, sizeof(str)); } - buf[offset++] = ')'; - return offset; +exit: + return (int)offset; } static int proc_print(char *buf, size_t buf_sz, struct proc *proc) { return 0; (void)buf; (void)buf_sz; - (void)proc; + (void)proc; NOT_IMPLEMENTED(); } diff --git a/src/value.h b/src/value.h index ed30b99..61b8252 100644 --- a/src/value.h +++ b/src/value.h @@ -16,13 +16,13 @@ typedef value_t (*builtin_proc_t)(value_t *args); X(VALUE_INT) \ X(VALUE_CONS) \ X(VALUE_PROC) \ - X(VALUE_PROC_BUILTIN) + X(VALUE_PROC_BUILTIN) #define TO_ENUM(type) type, #define TO_STRING(type) #type, extern const char * const value_type_string[]; - + struct value { enum value_type { VALUE_TYPES(TO_ENUM) @@ -40,7 +40,7 @@ struct value { struct proc { env_t parent_env; - + value_t *arg_keys; size_t argc; |