aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2024-08-30 17:01:28 +0300
committerkartofen <mladenovnasko0@gmail.com>2024-08-30 17:01:28 +0300
commite1ceef73192f0300ff9b10ba9a16475fbebeaa5f (patch)
tree0cb2bc5336a522b965c1d171b433044591721e20
parentde3a062bfc206bf0373f96f4f6cc8c74ffcbab48 (diff)
proper repl, stylistic changes, removed trailing whitespace
-rw-r--r--Makefile2
-rw-r--r--files/test-lambda.l41
-rw-r--r--src/builtin.h78
-rw-r--r--src/common.h12
-rw-r--r--src/env.c12
-rw-r--r--src/hashtable.c32
-rw-r--r--src/lexer.c26
-rw-r--r--src/lexer.h5
-rw-r--r--src/main.c115
-rw-r--r--src/memdebug.h30
-rw-r--r--src/value.c144
-rw-r--r--src/value.h6
12 files changed, 296 insertions, 207 deletions
diff --git a/Makefile b/Makefile
index 240e4f8..10cdf66 100644
--- a/Makefile
+++ b/Makefile
@@ -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
-
diff --git a/src/env.c b/src/env.c
index a530a36..10aa651 100644
--- a/src/env.c
+++ b/src/env.c
@@ -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);
diff --git a/src/main.c b/src/main.c
index a63a392..0ddb7f9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;