summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Perktold <Felix.Perktold@student.uibk.ac.at>2025-12-22 00:14:15 +0100
committerFelix Perktold <Felix.Perktold@student.uibk.ac.at>2025-12-22 00:14:15 +0100
commita7a070371bcc10d0dbf94e503650856ac37ed81d (patch)
tree7b2e5968b623d15947bc0537a4ff64a385119f68
parent33b3d80c2dcd12dbf692984e0d736bfa9906a8b5 (diff)
add reading from files, add quote shorthand (')
-rw-r--r--lisp.l9
-rw-r--r--lisp.y28
-rw-r--r--main.c26
-rw-r--r--test.c12
4 files changed, 47 insertions, 28 deletions
diff --git a/lisp.l b/lisp.l
index 20b64af..fa2203a 100644
--- a/lisp.l
+++ b/lisp.l
@@ -9,9 +9,10 @@ int tcnt = 0;
%%
[[:space:]]+ { /* ignore whitespace */ }
";"[^\n]* { /* ignore comment */ }
-"(" { return LPAREN; }
-")" { return RPAREN; }
-"\." { return DOT; }
+"(" { return LPAREN; }
+")" { return RPAREN; }
+"\." { return DOT; }
+"'" { return QUOTE; }
[+-]?([0-9]+|([0-9]*\.[0-9]+))([eE][-+]?[0-9]+)? {
yylval.dval = atof(yytext);
@@ -32,7 +33,7 @@ int tcnt = 0;
return STRING;
}
-[^[:space:]\"().]+ {
+[^[:space:]\"()'.]+ {
yylval.strval = strdup(yytext);
return SYMBOL;
diff --git a/lisp.y b/lisp.y
index ffb9bf9..5a39640 100644
--- a/lisp.y
+++ b/lisp.y
@@ -15,40 +15,36 @@ int yyerror(const char *s);
}
%token <dval> NUMBER
%token <strval> STRING SYMBOL
-%token <ival> LPAREN RPAREN DOT
-%token <ival> PLUS MINUS MULT DIV
+%token <ival> LPAREN RPAREN DOT QUOTE
-%type <val> sexpr atom list list_items
+%type <val> expr atom list list_items
-%start sexprs
+%start exprs
%%
-sexprs: sexpr
+exprs: expr
{
value *v = eval(global_env, $1);
printf(";> ");
println_value(v);
}
- | sexprs sexpr
+ | exprs expr
{
value *v = eval(global_env, $2);
printf(";> ");
println_value(v);
};
-sexpr: atom
- | list
- | LPAREN sexpr DOT sexpr RPAREN
- {
- $$ = cons($2, $4);
- };
+expr: atom
+ | list
+ | LPAREN expr DOT expr RPAREN { $$ = cons($2, $4); }
+ | QUOTE expr { $$ = cons(make_symbol("quote"), cons($2, make_nil())); };
-list: LPAREN list_items RPAREN
- { $$ = $2; };
+list: LPAREN list_items RPAREN { $$ = $2; };
list_items: /* empty list */ { $$ = make_nil(); }
- | sexpr list_items { $$ = cons($1, $2); }
- | sexpr DOT sexpr { $$ = cons($1, $3); };
+ | expr list_items { $$ = cons($1, $2); }
+ | expr DOT expr { $$ = cons($1, $3); };
atom: NUMBER
{
diff --git a/main.c b/main.c
index 563d98a..2b0c00f 100644
--- a/main.c
+++ b/main.c
@@ -6,10 +6,26 @@
#include "lex.yy.h"
#include "lisp.tab.h"
-
env *global_env = NULL;
-int main(void) {
+
+void eval_file(const char *filename) {
+ FILE *f = fopen(filename, "r");
+ if (!f) {
+ fprintf(stderr, "could not open file: %s\n", filename);
+ return;
+ }
+
+ char line[1024];
+ while (fgets(line, sizeof(line), f)) {
+ if (*line == '\n' || *line == ';') continue; // skip empty lines or comments
+ yy_scan_string(line);
+ yyparse();
+ }
+ fclose(f);
+}
+
+int main(int argc, char **argv) {
// init global env
global_env = env_create(NULL);
env_define(global_env, "cons", make_builtin(builtin_cons));
@@ -21,6 +37,12 @@ int main(void) {
env_define(global_env, "*", make_builtin(builtin_mul));
env_define(global_env, "/", make_builtin(builtin_div));
env_define(global_env, "<=", make_builtin(builtin_le));
+
+ // evaluate files
+ for(int i = 1; i < argc; i++) {
+ eval_file(argv[i]);
+ }
+
// START REPL
char* line;
while ((line = readline("λ> ")) != NULL) {
diff --git a/test.c b/test.c
index 9dfe8c6..8622fe3 100644
--- a/test.c
+++ b/test.c
@@ -10,14 +10,14 @@ static int tests_failed = 0;
env *global_env = NULL;
-#define ASSERT(cond, msg) do { \
- tests_run++; \
- if (!(cond)) { \
- tests_failed++; \
+#define ASSERT(cond, msg) do { \
+ tests_run++; \
+ if (!(cond)) { \
+ tests_failed++; \
printf("FAIL: %s\n", msg); \
- } else { \
+ } else { \
printf("PASS: %s\n", msg); \
- } \
+ } \
} while (0)
void test_make_int() {