-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7fdad74
Showing
221 changed files
with
3,387 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# minilisp | ||
My toy lisp interpreters | ||
|
||
# Reference | ||
[怎样写一个解释器](http://www.jianshu.com/p/509505d3bd50) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# miniLisp | ||
just a simple lisp interpreter written in c | ||
|
||
## Compile | ||
```bash | ||
$ cd src | ||
$ make | ||
``` | ||
|
||
## Usage | ||
```bash | ||
$ ./minilisp # REPL | ||
$ ./minilisp [program1.lsp program2.lsp ...] | ||
``` | ||
|
||
## Test | ||
``` | ||
$ ./test.sh | ||
``` | ||
|
||
# Reference | ||
[怎样写一个解释器](http://www.jianshu.com/p/509505d3bd50) |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
minilisp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
all: main.c parser.c structs.c eval.c init.c | ||
gcc -o minilisp main.c parser.c structs.c eval.c init.c | ||
|
||
test: all | ||
./test.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#ifndef ENV_H | ||
#define ENV_H | ||
|
||
static void ext_env(char* symbol, lval val, Env *env) { | ||
Env e = malloc(sizeof(struct Env)); | ||
e->value = val; | ||
e->symbol = strdup(symbol); | ||
e->next = *env; | ||
*env = e; | ||
} | ||
|
||
static void print_env(Env env) { | ||
puts("---start---"); | ||
while(env) { | ||
printf("%s, ", env->symbol); | ||
println_lval(env->value); | ||
env = env->next; | ||
} | ||
puts("---end---"); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include "structs.h" | ||
#include "lval.h" | ||
#include "env.h" | ||
|
||
extern Builtin builtin; | ||
|
||
void typeCheck(lval v, enum L_TYPE type) { | ||
if (v->type != type) { | ||
#ifdef RICHDEBUG | ||
printf("expecting: %d, %d given.\n", type, v->type); | ||
#endif | ||
puts("Type error!"); | ||
exit(-1); | ||
} | ||
} | ||
|
||
static lval lval_symbol(expr e, Env *env) { | ||
Builtin fb = builtin; | ||
while(fb && strcmp(e->symbol, fb->name) != 0) { | ||
fb = fb->next; | ||
} | ||
if (fb) { | ||
lval val = malloc(sizeof(l_val)); | ||
val->type = fb->type; | ||
val->value = fb->value; | ||
return val; | ||
} else { | ||
Env fe = *env; | ||
while(fe && strcmp(e->symbol, fe->symbol) != 0) { | ||
fe = fe->next; | ||
} | ||
if (fe) { | ||
return dup_lval(fe->value); | ||
} else { | ||
printf("variable %s not defined\n", e->symbol); | ||
return NULL; | ||
} | ||
} | ||
} | ||
|
||
static int is_arithmetic(int value) { | ||
return value == FUNC_ADD || value == FUNC_SUB || | ||
value == FUNC_MUL || value == FUNC_DIV || | ||
value == FUNC_MOD; | ||
} | ||
|
||
static int is_cmp(int value) { | ||
return value == FUNC_LT || value == FUNC_GT || | ||
value == FUNC_EQ || value == FUNC_LE || | ||
value == FUNC_GE; | ||
} | ||
|
||
int arg_check(int expected, int given, int mode) { | ||
if (mode == CHK_EXACT && given != expected) { | ||
printf("Error: wrong number of arguments " | ||
"(expected: %d got: %d)\n", expected, given); | ||
return 0; | ||
} else if (mode == CHK_ATLEAST && given < expected) { | ||
printf("Error: wrong number of arguments " | ||
"(at least: %d got: %d)\n", expected, given); | ||
return 0; | ||
} | ||
return 1; | ||
} | ||
|
||
static lval call_function(lval func, expr e, Env *env) { | ||
int i, cmp; | ||
lval val, tmp; | ||
if (func->value == FUNC_PRINT) { | ||
arg_check(1, e->len - 1, CHK_ATLEAST); | ||
for(i=1;i<e->len;++i) { | ||
val = eval(e->child[i], env); | ||
print_lval(val); | ||
} | ||
putchar('\n'); | ||
free(func); | ||
return NULL; | ||
} else if (func->value == FUNC_NOT) { | ||
arg_check(1, e->len - 1, CHK_EXACT); | ||
val = dup_lval(eval(e->child[1], env)); | ||
val->value = !val->value; | ||
free(func); | ||
return val; | ||
} else if (func->value == FUNC_SUB && e->len == 2) { | ||
val = dup_lval(eval(e->child[1], env)); | ||
val->value = -val->value; | ||
free(func); | ||
return val; | ||
} else if (e->len < 3) { | ||
return func; | ||
} else { | ||
val = eval(e->child[1], env); | ||
if (is_arithmetic(func->value) || is_cmp(func->value)) { | ||
typeCheck(val, L_NUMBER); | ||
} | ||
tmp = NULL; | ||
if (is_arithmetic(func->value)) { | ||
val->type = L_NUMBER; | ||
} else { | ||
val->type = L_BOOL; | ||
cmp = val->value; | ||
if (!(func->value == FUNC_OR||func->value == FUNC_AND)) { | ||
val->value = 1; | ||
} | ||
} | ||
for(i=2;i<e->len;++i) { | ||
free(tmp); | ||
tmp = eval(e->child[i], env); | ||
switch(func->value) { | ||
case FUNC_ADD: | ||
case FUNC_SUB: | ||
case FUNC_MUL: | ||
case FUNC_DIV: | ||
case FUNC_MOD: | ||
typeCheck(val, L_NUMBER); | ||
typeCheck(tmp, L_NUMBER); | ||
break; | ||
case FUNC_LT : | ||
case FUNC_LE : | ||
case FUNC_EQ : | ||
case FUNC_GT : | ||
case FUNC_GE : | ||
typeCheck(tmp, L_NUMBER); | ||
break; | ||
case FUNC_AND: | ||
case FUNC_OR: | ||
typeCheck(val, L_BOOL); | ||
typeCheck(tmp, L_BOOL); | ||
break; | ||
} | ||
switch(func->value) { | ||
case FUNC_ADD: val->value += tmp->value; break; | ||
case FUNC_SUB: val->value -= tmp->value; break; | ||
case FUNC_MUL: val->value *= tmp->value; break; | ||
case FUNC_DIV: val->value /= tmp->value; break; | ||
case FUNC_MOD: val->value %= tmp->value; break; | ||
case FUNC_LT : val->value &= cmp < tmp->value; break; | ||
case FUNC_LE : val->value &= cmp <= tmp->value; break; | ||
case FUNC_EQ : val->value &= cmp == tmp->value; break; | ||
case FUNC_GT : val->value &= cmp > tmp->value; break; | ||
case FUNC_GE : val->value &= cmp >= tmp->value; break; | ||
case FUNC_AND: val->value &= tmp->value; break; | ||
case FUNC_OR : val->value |= tmp->value; break; | ||
} | ||
} | ||
free(tmp); | ||
free(func); | ||
return val; | ||
} | ||
free(func); | ||
return NULL; | ||
} | ||
|
||
static lval call_syntax(lval func, expr e, Env *env) { | ||
lval val, choice; | ||
Env find, env_save; | ||
switch(func->value) { | ||
case SYNTAX_IF: | ||
choice = eval(e->child[1], env); | ||
if (choice->value) { | ||
val = eval(e->child[2], env); | ||
} else { | ||
val = eval(e->child[3], env); | ||
} | ||
free(choice); | ||
free(func); | ||
return val; | ||
case SYNTAX_LET: | ||
find = *env; | ||
while(find && strcmp(e->child[1]->symbol, find->symbol)) { | ||
find=find->next; | ||
} | ||
if (find) { | ||
free(find->value); | ||
find->value = eval(e->child[2], env); | ||
} else { | ||
ext_env(e->child[1]->symbol, eval(e->child[2], env), env); | ||
find = *env; | ||
} | ||
if (find->value->type == L_CLOSURE) { | ||
ext_env(find->symbol, find->value, &find->value->env); | ||
} | ||
free(func); | ||
return NULL; | ||
case SYNTAX_LAMBDA: | ||
free(func); | ||
return lval_closure(e, *env); | ||
default: | ||
printf("undefined syntax %d\n", func->value); | ||
free(func); | ||
return NULL; | ||
} | ||
} | ||
|
||
static lval call_closure(lval func, expr e, Env *env) { | ||
int i; | ||
lval val, arg; | ||
expr arglist = func->e->child[1]; | ||
Env old_env = func->env; | ||
if (arglist->len == e->len-1) { | ||
for(i=0;i<arglist->len;++i) { | ||
arg = eval(e->child[i+1], env); | ||
ext_env(arglist->child[i]->symbol, arg, &func->env); | ||
} | ||
val = NULL; | ||
for(i=2;i<func->e->len;++i) { | ||
free(val); | ||
val = eval(func->e->child[i], &func->env); | ||
} | ||
free(func); | ||
return val; | ||
} else { | ||
printf("Error: wrong number of arguments " | ||
"(expected: %d got: %d)\n", arglist->len, e->len-1); | ||
free(func); | ||
return NULL; | ||
} | ||
} | ||
|
||
static lval lval_list(expr e, Env *env) { | ||
lval func = eval(e->child[0], env); | ||
if (e->len == 1) { | ||
if (func->type == L_CLOSURE && func->e->child[1]->len == 0) { | ||
return call_closure(func, e, env); | ||
} | ||
return func; | ||
} else { | ||
switch(func->type) { | ||
case L_FUNCTION: return call_function(func, e, env); | ||
case L_SYNTAX : return call_syntax(func, e, env); | ||
case L_CLOSURE : return call_closure(func, e, env); | ||
default: | ||
printf("Error: "); | ||
print_lval(func); | ||
puts(" is not a function"); | ||
free(func); | ||
return NULL; | ||
} | ||
} | ||
} | ||
|
||
lval eval(expr e, Env *env) { | ||
if (!(e == NULL || (e->type == S_LIST && e->len == 0))) { | ||
switch(e->type) { | ||
case S_NUMBER: return lval_number(e->value); | ||
case S_BOOL : return lval_bool(e->value); | ||
case S_SYMBOL: return lval_symbol(e, env); | ||
case S_LIST : return lval_list(e, env); | ||
} | ||
} | ||
return NULL; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <regex.h> | ||
#include "structs.h" | ||
|
||
Builtin builtin; | ||
|
||
static void add_builtin(char* name, int type, int value) { | ||
Builtin b = malloc(sizeof(struct Builtin)); | ||
b->name = name; | ||
b->type = type; | ||
b->value = value; | ||
b->next = builtin; | ||
builtin = b; | ||
} | ||
|
||
void init_builtin() { | ||
add_builtin("+", L_FUNCTION, FUNC_ADD); | ||
add_builtin("-", L_FUNCTION, FUNC_SUB); | ||
add_builtin("*", L_FUNCTION, FUNC_MUL); | ||
add_builtin("/", L_FUNCTION, FUNC_DIV); | ||
add_builtin("%", L_FUNCTION, FUNC_MOD); | ||
add_builtin("mod", L_FUNCTION, FUNC_MOD); | ||
add_builtin("<", L_FUNCTION, FUNC_LT); | ||
add_builtin("<=", L_FUNCTION, FUNC_LE); | ||
add_builtin("=", L_FUNCTION, FUNC_EQ); | ||
add_builtin(">", L_FUNCTION, FUNC_GT); | ||
add_builtin(">=", L_FUNCTION, FUNC_GE); | ||
add_builtin("or", L_FUNCTION, FUNC_OR); | ||
add_builtin("and", L_FUNCTION, FUNC_AND); | ||
add_builtin("not", L_FUNCTION, FUNC_NOT); | ||
add_builtin("print", L_FUNCTION, FUNC_PRINT); | ||
add_builtin("print-num", L_FUNCTION, FUNC_PRINT); | ||
add_builtin("print-bool", L_FUNCTION, FUNC_PRINT); | ||
add_builtin("if", L_SYNTAX , SYNTAX_IF); | ||
add_builtin("let", L_SYNTAX , SYNTAX_LET); | ||
add_builtin("define", L_SYNTAX , SYNTAX_LET); | ||
add_builtin("fun", L_SYNTAX , SYNTAX_LAMBDA); | ||
add_builtin("lambda", L_SYNTAX , SYNTAX_LAMBDA); | ||
} | ||
|
||
regex_t preg_int; | ||
regmatch_t pmatch; | ||
|
||
void init_regex() { | ||
if (regcomp(&preg_int, "[-+]?[0-9]+", REG_EXTENDED | REG_ICASE)) { | ||
puts("regex fail"); | ||
} | ||
} |
Oops, something went wrong.