diff options
| author | Felix Perktold <Felix.Perktold@student.uibk.ac.at> | 2025-12-23 14:29:00 +0100 |
|---|---|---|
| committer | Felix Perktold <Felix.Perktold@student.uibk.ac.at> | 2025-12-23 14:29:00 +0100 |
| commit | c63cbd8db40fbdeccabd218229010cbfb8a93977 (patch) | |
| tree | 34a9725eb1207a624cb8486420d780bbfb983482 | |
| parent | b99be4933bcb850cbaf96f89750e925ecf2e8386 (diff) | |
fix tests, fix empty input behavior
| -rw-r--r-- | lisp.c | 1 | ||||
| -rw-r--r-- | lisp.l | 3 | ||||
| -rw-r--r-- | lisp.y | 24 | ||||
| -rw-r--r-- | lisp/meta_cirular_eval.lisp | 64 | ||||
| -rw-r--r-- | lisp/standard_functions.lisp | 15 | ||||
| -rw-r--r-- | test.c | 8 |
6 files changed, 95 insertions, 20 deletions
@@ -99,6 +99,7 @@ void println_value(value *val){ printf("\n"); } void print_value(value *val){ + if(!val) { return; } switch (val->type) { case VT_INT: printf("%d", val->as.i); @@ -7,9 +7,8 @@ int tcnt = 0; %} %% -[[:space:]&&[^\n]]+ { /* ignore whitespace */ } +[[:space:]]+ { /* ignore whitespace */ } ";"[^\n]* { /* ignore comment */ } -\n { return NLINE; } "(" { return LPAREN; } ")" { return RPAREN; } "\." { return DOT; } @@ -5,6 +5,13 @@ int yylex(void); int yyerror(const char *s); + +void eval_and_print_REPL(value *v) { + if(!v) { return; } + value *ve = eval(global_env, v); + printf(";> "); + println_value(ve); +} %} %union { @@ -14,7 +21,7 @@ int yyerror(const char *s); } %token <dval> NUMBER %token <strval> STRING SYMBOL -%token LPAREN RPAREN DOT QUOTE NLINE +%token LPAREN RPAREN DOT QUOTE %type <val> expr atom list list_items @@ -22,24 +29,13 @@ int yyerror(const char *s); %% exprs: /* nothing */ - | expr - { - value *v = eval(global_env, $1); - printf(";> "); - println_value(v); - } - | exprs expr - { - value *v = eval(global_env, $2); - printf(";> "); - println_value(v); - }; + | expr { eval_and_print_REPL($1); } + | exprs expr { eval_and_print_REPL($2); } expr: atom | list | LPAREN expr DOT expr RPAREN { $$ = cons($2, $4); } | QUOTE expr { $$ = cons(make_symbol("quote"), cons($2, make_nil())); } - | NLINE { $$ = make_nil(); }; list: LPAREN list_items RPAREN { $$ = $2; }; diff --git a/lisp/meta_cirular_eval.lisp b/lisp/meta_cirular_eval.lisp new file mode 100644 index 0000000..60b7bf8 --- /dev/null +++ b/lisp/meta_cirular_eval.lisp @@ -0,0 +1,64 @@ +; metacircular evaluator in your Lisp +(define global-env '()) + +; helper to extend environment +(define (extend-env vars vals base) + (cons (cons vars vals) base)) + +; lookup variable +(define (lookup var env) + (cond + ((null? env) (print "symbol " var " not found") ()) + ((eq? var (car (car env))) (cadr (car env))) + (else (lookup var (cdr env))))) + +; eval sequence (for lambda bodies) +(define (eval-sequence exps env) + (if (null? (cdr exps)) + (eval (car exps) env) + (begin (eval (car exps) env) + (eval-sequence (cdr exps) env)))) + +; eval +(define (eval exp env) + (cond + ((number? exp) exp) + ((string? exp) exp) + ((symbol? exp) (lookup exp env)) + ((pair? exp) + (let ((head (car exp)) (tail (cdr exp))) + (cond + ((eq? head 'quote) (car tail)) + ((eq? head 'if) + (let ((test (car tail)) + (then (car (cdr tail))) + (else (car (cdr (cdr tail))))) + (if (eval test env) + (eval then env) + (eval else env)))) + ((eq? head 'define) + (let ((var (car tail)) + (val (eval (car (cdr tail)) env))) + (set! global-env (extend-env (list var) (list val) global-env)) + 1)) ; return 1 for success + ((eq? head 'lambda) + (list 'closure (car tail) (cdr tail) env)) + (else ; procedure application + (let ((proc (eval head env)) + (args (map (lambda (x) (eval x env)) tail))) + (apply proc args)))))) + (else (print "Unknown expression type") ())) + +) + +; apply +(define (apply proc args) + (cond + ((procedure? proc) (apply proc args)) ; builtin + ((and (pair? proc) (eq? (car proc) 'closure)) + (let ((params (cadr proc)) + (body (caddr proc)) + (env (cadddr proc))) + (eval-sequence body (extend-env params args env)))) + (else (print "Unknown procedure type") ())) +) diff --git a/lisp/standard_functions.lisp b/lisp/standard_functions.lisp new file mode 100644 index 0000000..9658ef9 --- /dev/null +++ b/lisp/standard_functions.lisp @@ -0,0 +1,15 @@ +; comparisons +(define <= (lambda (x y) + (if (< x y) + 1 + (if (eq? x y) 1 ())))) +(define > (lambda (x y) (< y x))) +(define >= (lambda (x y) (<= y x))) + +; boolean funs +(define and (lambda (x y) + (if x + (if y 1 ()) + ()))) +(define or (lambda (x y) (if x 1 y))) +(define nand (lambda (x y) (null? (and x y)))) @@ -348,7 +348,7 @@ void test_recursive_factorial() { void test_eq_ints() { env *e = env_create(NULL); - env_define(e, "eq", make_builtin(builtin_eq)); + env_define(e, "eq", make_builtin(builtin_equal)); value *expr = cons(make_symbol("eq"), @@ -365,7 +365,7 @@ void test_eq_ints() { void test_eq_ints_false() { env *e = env_create(NULL); - env_define(e, "eq", make_builtin(builtin_eq)); + env_define(e, "eq", make_builtin(builtin_equal)); value *expr = cons(make_symbol("eq"), @@ -380,7 +380,7 @@ void test_eq_ints_false() { void test_eq_symbols() { env *e = env_create(NULL); - env_define(e, "eq", make_builtin(builtin_eq)); + env_define(e, "eq", make_builtin(builtin_equal)); value *expr = cons(make_symbol("eq"), @@ -395,7 +395,7 @@ void test_eq_symbols() { void test_eq_lists() { env *e = env_create(NULL); - env_define(e, "eq", make_builtin(builtin_eq)); + env_define(e, "eq", make_builtin(builtin_equal)); value *list1 = cons(make_int(1), |
