mirror of
https://github.com/kanaka/mal.git
synced 2024-09-11 13:55:55 +03:00
c: Add Boehm garbage collector
By default, garbage collection is enabled. You can run: make USE_GC= to build the C implementation without garbage collection.
This commit is contained in:
parent
35bc081fe7
commit
6b3ecaa769
@ -144,7 +144,8 @@ bash stepX_YYY.sh
|
||||
### C
|
||||
|
||||
The C implementation of mal requires the following libraries (lib and
|
||||
header packages): glib, libffi6 and either the libedit or GNU readline library.
|
||||
header packages): glib, libffi6, libgc, and either the libedit or GNU readline
|
||||
library.
|
||||
|
||||
```
|
||||
cd c
|
||||
|
@ -25,4 +25,4 @@ WORKDIR /mal
|
||||
RUN apt-get -y install g++
|
||||
|
||||
# Libraries needed for the C impl
|
||||
RUN apt-get -y install libglib2.0 libglib2.0-dev libffi-dev
|
||||
RUN apt-get -y install libglib2.0 libglib2.0-dev libffi-dev libgc-dev
|
||||
|
@ -1,4 +1,5 @@
|
||||
USE_READLINE ?=
|
||||
USE_GC ?= 1
|
||||
CFLAGS += -g -O2
|
||||
LDFLAGS += -g
|
||||
|
||||
@ -38,6 +39,12 @@ RL_LIBRARY ?= readline
|
||||
CFLAGS += -DUSE_READLINE=1
|
||||
endif
|
||||
|
||||
ifeq (,$(USE_GC))
|
||||
else
|
||||
CFLAGS += -DUSE_GC=1
|
||||
LDFLAGS += -lgc
|
||||
endif
|
||||
|
||||
CFLAGS += $(GLIB_CFLAGS)
|
||||
LDFLAGS += -l$(RL_LIBRARY) $(GLIB_LDFLAGS) -ldl -lffi
|
||||
|
||||
|
10
c/core.c
10
c/core.c
@ -96,8 +96,8 @@ MalVal *prn(MalVal *args) {
|
||||
assert_type(args, MAL_LIST|MAL_VECTOR,
|
||||
"prn called with non-sequential args");
|
||||
char *repr = _pr_str_args(args, " ", 1);
|
||||
g_print("%s\n", repr);
|
||||
free(repr);
|
||||
puts(repr);
|
||||
MAL_GC_FREE(repr);
|
||||
return &mal_nil;
|
||||
}
|
||||
|
||||
@ -107,8 +107,8 @@ MalVal *println(MalVal *args) {
|
||||
assert_type(args, MAL_LIST|MAL_VECTOR,
|
||||
"println called with non-sequential args");
|
||||
char *repr = _pr_str_args(args, " ", 0);
|
||||
g_print("%s\n", repr);
|
||||
free(repr);
|
||||
puts(repr);
|
||||
MAL_GC_FREE(repr);
|
||||
return &mal_nil;
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ char *slurp_raw(char *path) {
|
||||
if (fstat(fd, &fst) < 0) {
|
||||
abort("slurp failed to stat '%s'", path);
|
||||
}
|
||||
data = malloc(fst.st_size+1);
|
||||
data = MAL_GC_MALLOC(fst.st_size+1);
|
||||
sz = read(fd, data, fst.st_size);
|
||||
if (sz < fst.st_size) {
|
||||
abort("slurp failed to read '%s'", path);
|
||||
|
2
c/env.c
2
c/env.c
@ -4,7 +4,7 @@
|
||||
// Env
|
||||
|
||||
Env *new_env(Env *outer, MalVal* binds, MalVal *exprs) {
|
||||
Env *e = malloc(sizeof(Env));
|
||||
Env *e = MAL_GC_MALLOC(sizeof(Env));
|
||||
e->table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
e->outer = outer;
|
||||
|
||||
|
23
c/printer.c
23
c/printer.c
@ -29,13 +29,13 @@ char *_pr_str_hash_map(MalVal *obj, int print_readably) {
|
||||
} else {
|
||||
repr_tmp2 = repr;
|
||||
repr = g_strdup_printf("%s %s %s", repr_tmp2, (char*)key2, repr_tmp1);
|
||||
free(repr_tmp2);
|
||||
MAL_GC_FREE(repr_tmp2);
|
||||
}
|
||||
free(repr_tmp1);
|
||||
MAL_GC_FREE(repr_tmp1);
|
||||
}
|
||||
repr_tmp2 = repr;
|
||||
repr = g_strdup_printf("%s}", repr_tmp2);
|
||||
free(repr_tmp2);
|
||||
MAL_GC_FREE(repr_tmp2);
|
||||
return repr;
|
||||
}
|
||||
|
||||
@ -51,13 +51,13 @@ char *_pr_str_list(MalVal *obj, int print_readably, char start, char end) {
|
||||
} else {
|
||||
repr_tmp2 = repr;
|
||||
repr = g_strdup_printf("%s %s", repr_tmp2, repr_tmp1);
|
||||
free(repr_tmp2);
|
||||
MAL_GC_FREE(repr_tmp2);
|
||||
}
|
||||
free(repr_tmp1);
|
||||
MAL_GC_FREE(repr_tmp1);
|
||||
}
|
||||
repr_tmp2 = repr;
|
||||
repr = g_strdup_printf("%s%c", repr_tmp2, end);
|
||||
free(repr_tmp2);
|
||||
MAL_GC_FREE(repr_tmp2);
|
||||
return repr;
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ char *_pr_str(MalVal *obj, int print_readably) {
|
||||
} else if (print_readably) {
|
||||
char *repr_tmp = g_strescape(obj->val.string, "");
|
||||
repr = g_strdup_printf("\"%s\"", repr_tmp);
|
||||
free(repr_tmp);
|
||||
MAL_GC_FREE(repr_tmp);
|
||||
} else {
|
||||
repr = g_strdup_printf("%s", obj->val.string);
|
||||
}
|
||||
@ -139,13 +139,16 @@ char *_pr_str_args(MalVal *args, char *sep, int print_readably) {
|
||||
if (i != 0) {
|
||||
repr2 = repr;
|
||||
repr = g_strdup_printf("%s%s", repr2, sep);
|
||||
free(repr2);
|
||||
MAL_GC_FREE(repr2);
|
||||
}
|
||||
repr2 = repr;
|
||||
repr = g_strdup_printf("%s%s",
|
||||
repr2, _pr_str(obj, print_readably));
|
||||
free(repr2);
|
||||
MAL_GC_FREE(repr2);
|
||||
}
|
||||
return repr;
|
||||
char* res = MAL_GC_STRDUP(repr);
|
||||
MAL_GC_FREE(repr);
|
||||
// TODO - check why STRDUP was needed here
|
||||
return res;
|
||||
}
|
||||
|
||||
|
20
c/reader.c
20
c/reader.c
@ -13,7 +13,7 @@
|
||||
MalVal *read_form(Reader *reader);
|
||||
|
||||
Reader *reader_new() {
|
||||
Reader *reader = (Reader*)malloc(sizeof(Reader));
|
||||
Reader *reader = (Reader*)MAL_GC_MALLOC(sizeof(Reader));
|
||||
reader->array = g_array_sized_new(TRUE, FALSE, sizeof(char *), 8);
|
||||
reader->position = 0;
|
||||
return reader;
|
||||
@ -39,10 +39,10 @@ char *reader_next(Reader *reader) {
|
||||
void reader_free(Reader *reader) {
|
||||
int i;
|
||||
for(i=0; i < reader->array->len; i++) {
|
||||
free(g_array_index(reader->array, char*, i));
|
||||
MAL_GC_FREE(g_array_index(reader->array, char*, i));
|
||||
}
|
||||
g_array_free(reader->array, TRUE);
|
||||
free(reader);
|
||||
g_array_free(reader->array, TRUE);
|
||||
MAL_GC_FREE(reader);
|
||||
}
|
||||
|
||||
Reader *tokenize(char *line) {
|
||||
@ -82,11 +82,10 @@ char *replace_str(const char *str, const char *old, const char *new)
|
||||
{
|
||||
GRegex *reg = g_regex_new (old, 0, 0, NULL);
|
||||
char *str_tmp = g_regex_replace_literal(reg, str, -1, 0, new, 0, NULL);
|
||||
free(reg);
|
||||
MAL_GC_FREE(reg);
|
||||
return str_tmp;
|
||||
}
|
||||
|
||||
|
||||
MalVal *read_atom(Reader *reader) {
|
||||
char *token;
|
||||
GRegex *regex;
|
||||
@ -120,20 +119,21 @@ MalVal *read_atom(Reader *reader) {
|
||||
//g_print("read_atom string: %s\n", token);
|
||||
char *str_tmp = replace_str(g_match_info_fetch(matchInfo, 6), "\\\\\"", "\"");
|
||||
char *str_tmp2 = replace_str(str_tmp, "\\\\n", "\n");
|
||||
free(str_tmp);
|
||||
MAL_GC_FREE(str_tmp);
|
||||
char *str_tmp3 = replace_str(str_tmp2, "\\\\\\\\", "\\");
|
||||
free(str_tmp2);
|
||||
MAL_GC_FREE(str_tmp2);
|
||||
atom = malval_new_string(str_tmp3);
|
||||
} else if (g_match_info_fetch_pos(matchInfo, 7, &pos, NULL) && pos != -1) {
|
||||
//g_print("read_atom keyword\n");
|
||||
atom = malval_new_keyword(g_match_info_fetch(matchInfo, 7));
|
||||
atom = malval_new_keyword(MAL_GC_STRDUP(g_match_info_fetch(matchInfo, 7)));
|
||||
} else if (g_match_info_fetch_pos(matchInfo, 8, &pos, NULL) && pos != -1) {
|
||||
//g_print("read_atom symbol\n");
|
||||
atom = malval_new_symbol(g_match_info_fetch(matchInfo, 8));
|
||||
atom = malval_new_symbol(MAL_GC_STRDUP(g_match_info_fetch(matchInfo, 8)));
|
||||
} else {
|
||||
malval_free(atom);
|
||||
atom = NULL;
|
||||
}
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ int main()
|
||||
ast = READ(prompt);
|
||||
if (!ast) return 0;
|
||||
exp = EVAL(ast, NULL);
|
||||
g_print("%s\n", PRINT(exp));
|
||||
puts(PRINT(exp));
|
||||
|
||||
free(ast); // Free input string
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -62,6 +62,8 @@ int main()
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
|
||||
@ -74,8 +76,8 @@ int main()
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -24,7 +24,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -130,6 +130,8 @@ int main()
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env();
|
||||
@ -143,8 +145,8 @@ int main()
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -24,7 +24,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -156,6 +156,8 @@ int main()
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env();
|
||||
@ -169,8 +171,8 @@ int main()
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -195,6 +195,8 @@ int main()
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env();
|
||||
@ -208,8 +210,8 @@ int main()
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -208,6 +208,8 @@ int main()
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env();
|
||||
@ -221,8 +223,8 @@ int main()
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -222,6 +222,8 @@ int main(int argc, char *argv[])
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env(argc, argv);
|
||||
@ -241,8 +243,8 @@ int main(int argc, char *argv[])
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -25,7 +25,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -259,6 +259,8 @@ int main(int argc, char *argv[])
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env(argc, argv);
|
||||
@ -278,8 +280,8 @@ int main(int argc, char *argv[])
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -26,7 +26,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -303,6 +303,8 @@ int main(int argc, char *argv[])
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env(argc, argv);
|
||||
@ -322,8 +324,8 @@ int main(int argc, char *argv[])
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -27,7 +27,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -325,6 +325,8 @@ int main(int argc, char *argv[])
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env(argc, argv);
|
||||
@ -344,8 +346,8 @@ int main(int argc, char *argv[])
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
@ -27,7 +27,7 @@ MalVal *READ(char prompt[], char *str) {
|
||||
}
|
||||
}
|
||||
ast = read_str(line);
|
||||
if (!str) { free(line); }
|
||||
if (!str) { MAL_GC_FREE(line); }
|
||||
return ast;
|
||||
}
|
||||
|
||||
@ -332,6 +332,8 @@ int main(int argc, char *argv[])
|
||||
char *output;
|
||||
char prompt[100];
|
||||
|
||||
MAL_GC_SETUP();
|
||||
|
||||
// Set the initial prompt and environment
|
||||
snprintf(prompt, sizeof(prompt), "user> ");
|
||||
init_repl_env(argc, argv);
|
||||
@ -352,8 +354,8 @@ int main(int argc, char *argv[])
|
||||
output = PRINT(exp);
|
||||
|
||||
if (output) {
|
||||
g_print("%s\n", output);
|
||||
free(output); // Free output string
|
||||
puts(output);
|
||||
MAL_GC_FREE(output); // Free output string
|
||||
}
|
||||
|
||||
//malval_free(exp); // Free evaluated expression
|
||||
|
36
c/types.c
36
c/types.c
@ -5,6 +5,37 @@
|
||||
#include "types.h"
|
||||
#include "printer.h"
|
||||
|
||||
#ifdef USE_GC
|
||||
void nop_free(void* ptr) {
|
||||
(void)ptr; // Unused argument
|
||||
}
|
||||
|
||||
static GMemVTable gc_gmem_vtable = {
|
||||
.malloc = GC_malloc,
|
||||
.realloc = GC_realloc,
|
||||
.free = nop_free,
|
||||
.calloc = NULL,
|
||||
.try_malloc = NULL,
|
||||
.try_realloc = NULL
|
||||
};
|
||||
|
||||
void GC_setup() {
|
||||
GC_INIT();
|
||||
setenv("G_SLICE", "always-malloc", 1);
|
||||
g_mem_gc_friendly = TRUE;
|
||||
g_mem_set_vtable(&gc_gmem_vtable);
|
||||
}
|
||||
|
||||
char* GC_strdup(const char *src) {
|
||||
if (!src) {
|
||||
return NULL;
|
||||
}
|
||||
char* dst = (char*)MAL_GC_MALLOC(strlen(src) + 1);
|
||||
strcpy(dst, src);
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Errors/Exceptions
|
||||
|
||||
@ -67,17 +98,16 @@ int _count(MalVal *obj) {
|
||||
|
||||
// Allocate a malval and set its type and value
|
||||
MalVal *malval_new(MalType type, MalVal *metadata) {
|
||||
MalVal *mv = (MalVal*)malloc(sizeof(MalVal));
|
||||
MalVal *mv = (MalVal*)MAL_GC_MALLOC(sizeof(MalVal));
|
||||
mv->type = type;
|
||||
mv->metadata = metadata;
|
||||
return mv;
|
||||
}
|
||||
|
||||
//
|
||||
void malval_free(MalVal *mv) {
|
||||
// TODO: free collection items
|
||||
if (!(mv->type & (MAL_NIL|MAL_TRUE|MAL_FALSE))) {
|
||||
free(mv);
|
||||
MAL_GC_FREE(mv);
|
||||
}
|
||||
}
|
||||
|
||||
|
18
c/types.h
18
c/types.h
@ -3,6 +3,24 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef USE_GC
|
||||
|
||||
#include <gc/gc.h>
|
||||
char* GC_strdup(const char *src);
|
||||
#define MAL_GC_SETUP() GC_setup()
|
||||
#define MAL_GC_MALLOC GC_MALLOC
|
||||
#define MAL_GC_FREE nop_free
|
||||
#define MAL_GC_STRDUP GC_strdup
|
||||
|
||||
#else
|
||||
|
||||
#include <string.h>
|
||||
#define MAL_GC_SETUP()
|
||||
#define MAL_GC_MALLOC malloc
|
||||
#define MAL_GC_FREE free
|
||||
#define MAL_GC_STRDUP strdup
|
||||
|
||||
#endif
|
||||
|
||||
struct MalVal; // pre-declare
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user