diff options
| -rw-r--r-- | lisp.l | 9 | ||||
| -rw-r--r-- | lisp.y | 28 | ||||
| -rw-r--r-- | main.c | 26 | ||||
| -rw-r--r-- | test.c | 12 |
4 files changed, 47 insertions, 28 deletions
@@ -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; @@ -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 { @@ -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) { @@ -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() { |
