From cac651cd88f8da1e5957b0cc13fa25d79e1887fc Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Tue, 23 Aug 2016 20:58:50 +0200 Subject: Many things - two-letter AST union members - AST_QUOTED - AST_LAMBDA - an interpreter that works - function registering in the interpreter - some builtins --- interpreter.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 6 deletions(-) (limited to 'interpreter.c') diff --git a/interpreter.c b/interpreter.c index 333b8c9..05e5d2c 100644 --- a/interpreter.c +++ b/interpreter.c @@ -4,6 +4,7 @@ #include #include "interpreter.h" +#include "inter_builtins.h" #include "util.h" @@ -85,36 +86,148 @@ void inter_destroy(InterState *is){ static void intern_symbols(InterState *is,AST *ast){ switch(ast->type){ case AST_LIST: - for(int i=0;il.len;i++)intern_symbols(is,ast->l.nodes[i]); + for(int i=0;ili.len;i++)intern_symbols(is,ast->li.nodes[i]); break; case AST_SYMBOL:{ - if(ast->s.symid>=0&&ast->s.symidss.len&&strcmp(ast->s.name,is->ss.syms[ast->s.symid])==0){ + if(ast->sy.symid>=0&&ast->sy.symidss.len&&strcmp(ast->sy.name,is->ss.syms[ast->sy.symid])==0){ break; } int i; for(i=0;iss.len;i++){ - if(strcmp(is->ss.syms[i],ast->s.name)==0)break; + if(strcmp(is->ss.syms[i],ast->sy.name)==0)break; } if(iss.len){ - ast->s.symid=i; + ast->sy.symid=i; break; } if(is->ss.len==is->ss.sz){ is->ss.sz*=2; is->ss.syms=realloc(is->ss.syms,is->ss.sz,char*); } - is->ss.syms[is->ss.len++]=copystring(ast->s.name); + is->ss.syms[is->ss.len++]=copystring(ast->sy.name); break; } + case AST_QUOTED: + intern_symbols(is,ast->qu.ast); + break; + case AST_WORD: case AST_NUMBER: case AST_STRING: break; + + default: + assert(false); + } +} + +static const AST* find_var(const InterState *is,const char *name){ + int h=namehash(name,VMAP_HASHSZ); + for(const Scope *scope=is->scope;scope;scope=scope->next){ + for(const Vllist *ll=scope->vmap[h];ll;ll=ll->next){ + if(strcmp(name,ll->name)==0)return ll->value; + } + } + return NULL; +} + +InterRet ir_ast(AST *ast){ + InterRet ir={ast,NULL}; + return ir; +} + +InterRet ir_err(char *errstr){ + InterRet ir={NULL,errstr}; + return ir; +} + +InterRet ir_err_c(const char *errstr){ + return ir_err(copystring(errstr)); +} + +static InterRet interpret(InterState *is,const AST *ast){ + switch(ast->type){ + case AST_LIST:{ + if(ast->li.len==0){ + return ir_ast(ast_copy(ast)); + } + assert(ast->li.len>0); + AST *nodes[ast->li.len]; + for(int i=0;ili.len;i++){ + InterRet ir=interpret(is,ast->li.nodes[i]);; + if(ir.errstr){ + while(i-->0)ast_free(nodes[i]); + return ir; + } + nodes[i]=ir.ast; + } + + if(nodes[0]->type!=AST_LAMBDA){ + fprintf(stderr,"type = %d\n",nodes[0]->type); + return ir_err_c("First node in evaluated list not a function"); + } + +#define NOT_IMPLEMENTED false + if(nodes[0]->la.body)assert(NOT_IMPLEMENTED); + + return nodes[0]->la.cfunc(is,ast->li.len-1,nodes+1); + } + + case AST_SYMBOL: + return ir_ast(ast_copy(ast)); + + case AST_WORD:{ + const AST *cv=find_var(is,ast->wo.word); + if(cv)return ir_ast(ast_copy(cv)); + char *errstr; + asprintf(&errstr,"Unknown variable '%s'",ast->wo.word); + if(!errstr)outofmem(); + return ir_err(errstr); + } + + case AST_NUMBER: + return ir_ast(ast_copy(ast)); + + case AST_STRING: + return ir_ast(ast_copy(ast)); + + case AST_QUOTED: + return ir_ast(ast_copy(ast->qu.ast)); + + default: + assert(false); } } -void inter_runcode(InterState *is,AST *ast){ +void inter_register(InterState *is,const char *name,lambdafunc_t cfunc){ + assert(is->scope); + int h=namehash(name,VMAP_HASHSZ); + Vllist *ll=malloc(1,Vllist); + ll->name=copystring(name); + ll->value=ast_lambda(cfunc,NULL); + ll->next=is->scope->vmap[h]; + is->scope->vmap[h]=ll; +} + +void inter_register_prelude(InterState *is){ + inter_register(is,"do",builtin_do); + inter_register(is,"print",builtin_print); + inter_register(is,"+",builtin_sum); + inter_register(is,"-",builtin_difference); + inter_register(is,"*",builtin_product); + inter_register(is,"/",builtin_quotient); + inter_register(is,"%",builtin_remainder); + inter_register(is,"sum",builtin_sum); + inter_register(is,"difference",builtin_difference); + inter_register(is,"product",builtin_product); + inter_register(is,"quotient",builtin_quotient); + inter_register(is,"remainder",builtin_remainder); +} + +InterRet inter_runcode(InterState *is,AST *ast){ intern_symbols(is,ast); + + return interpret(is,ast); } -- cgit v1.2.3-54-g00ecf