diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 15 | ||||
| -rw-r--r-- | lisp.c | 33 | ||||
| -rw-r--r-- | lisp.h | 1 | ||||
| -rw-r--r-- | lisp_api.h | 7 | ||||
| -rw-r--r-- | main.c | 2 | ||||
| -rw-r--r-- | modules/test_module.c | 19 |
7 files changed, 76 insertions, 2 deletions
@@ -1,4 +1,5 @@ *.o +*.so lex.yy.* lisp.tab.* main @@ -1,9 +1,12 @@ LEX = flex YACC = bison CC = gcc -g -CFLAGS = -DYYDEBUG=1 +CFLAGS = -DYYDEBUG=1 -fPIC LIBS = -lreadline -lfl -lm OBJS = lisp.o lisp.tab.o lex.yy.o + +MODULE_SRC = $(wildcard modules/*.c) +MODULE_SO = $(MODULE_SRC:.c=.so) .SUFFIXES: main: main.c $(OBJS) @@ -25,7 +28,7 @@ lex.yy.o: lex.yy.c $(CC) $(CFLAGS) -c lex.yy.c clean: - rm -f *.o main test lisp.tab.c lisp.tab.h lex.yy.c lex.yy.h + rm -f *.o main test lisp.tab.c lisp.tab.h lex.yy.c lex.yy.h modules/*.so test: test.o $(OBJS) $(CC) $(CFLAGS) -o $@ test.o $(OBJS) $(LIBS) @@ -40,4 +43,12 @@ run: main run_std: main ./main lisp/standard_functions.lisp +modules: $(MODULE_SO) + @echo "All modules built successfully." + +modules/%.so: modules/%.c lisp.o + gcc -fPIC -c $< -o $*.o + gcc -fPIC -shared $*.o lisp.o -o $@ + rm $*.o + .PHONY: clean test run @@ -3,6 +3,7 @@ #include <readline/readline.h> #include <readline/history.h> #include <math.h> +#include <dlfcn.h> #include "lisp_api.h" #include "lisp.h" #include "lex.yy.h" @@ -488,6 +489,38 @@ value *builtin_lt(env *e, value *args) { return make_int(1); } +value *builtin_load_module(env *e, value *args) { + value *fst_arg = eval(e, car(args)); + + if (fst_arg->type != VT_STRING) { + printf("error: not a string:"); + print_value(fst_arg); + return make_nil(); //TODO: make_err + } + + const char *path = fst_arg->as.str; + + void *handle = dlopen(path, RTLD_LAZY); + if (!handle) { + printf("dlopen error: %s\n", dlerror()); + return make_nil(); //TODO: make_err + } + + module_export *(*init)(void) = dlsym(handle, "module_init"); + + if (!init) { + printf("not a valid module: %s\n", dlerror()); + return make_nil(); //TODO: make_err + } + + module_export *exports = init(); + for (int i = 0; exports[i].name; i++) { + env_define(e, exports[i].name, exports[i].v); + } + + return make_nil(); +} + int is_integer(double x) { return floor(x) == x && isfinite(x); } @@ -37,6 +37,7 @@ value *builtin_sub(env *e, value *args); value *builtin_mul(env *e, value *args); value *builtin_div(env *e, value *args); value *builtin_lt(env *e, value *args); +value *builtin_load_module(env *e, value *args); int is_integer(double x); @@ -49,4 +49,11 @@ value *car(value *cons); value *cdr(value *cons); value *reverse(value *list); +typedef struct { + const char *name; + value *v; +} module_export; + +module_export *module_init(); + #endif @@ -106,6 +106,8 @@ int main(int argc, char **argv) { env_define(global_env, "/", make_builtin(builtin_div)); env_define(global_env, "<", make_builtin(builtin_lt)); + env_define(global_env, "load_module", make_builtin(builtin_load_module)); + // evaluate files for(int i = 1; i < argc; i++) { eval_file(argv[i]); diff --git a/modules/test_module.c b/modules/test_module.c new file mode 100644 index 0000000..ead7b91 --- /dev/null +++ b/modules/test_module.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include "../lisp_api.h" + +value *hello_fun(env *e, value *args) { + printf("Hello from dynamically loaded module!\n"); + return make_nil(); +} + +module_export *module_init() { + static module_export exports[2]; + + exports[0].name = "hello"; + exports[0].v = make_builtin(&hello_fun); + + exports[1].name = NULL; + exports[1].v = NULL; + + return exports; +} |
