diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | grammar.peg | 12 | ||||
-rw-r--r-- | ht.c | 78 | ||||
-rw-r--r-- | ht.h | 22 | ||||
-rw-r--r-- | read.c | 3 | ||||
-rw-r--r-- | run.c | 97 | ||||
-rw-r--r-- | run.h | 4 | ||||
-rw-r--r-- | val.h | 39 |
8 files changed, 204 insertions, 57 deletions
@@ -1,6 +1,6 @@ -CS=parser.c ast.c run.c read.c -HS=parser.h ast.h run.h read.h -CFLAGS=-Wall -Wpedantic -Werror=implicit-function-declaration +CS=parser.c ast.c run.c read.c ht.c +HS=parser.h ast.h run.h read.h ht.h +CFLAGS=-O3 -Wall -Wpedantic -Werror=implicit-function-declaration badthing: $(CS) $(HS) $(CC) $(CFLAGS) -o badthing $(CS) diff --git a/grammar.peg b/grammar.peg index 5d1dad8..c74c6f6 100644 --- a/grammar.peg +++ b/grammar.peg @@ -3,11 +3,21 @@ #include <stdlib.h> #include <string.h> +/* +static const char *dbg_str[] = { "Evaluating rule", "Matched rule", "Abandoning rule" }; +#define PCC_DEBUG(auxil, event, rule, level, pos, buffer, length) \ + fprintf(stderr, "%*s%s %s @%zu [%.*s]\n", (int)((level) * 2), "", dbg_str[event], rule, pos, (int)(length), buffer) + + +*/ } + + %common { #include "ast.h" #include "run.h" + } %value "AstNode" @@ -27,6 +37,6 @@ number <- < [0-9]+ > (! ident_char) _ { $$ = astnode_new_num(atoi($1)); } symbol <- < ident_char+ > _ { $$ = astnode_new_symbol(strdup($1)); } ident_char <- [-_a-zA-Z'+*0-9] -_ <- [ \t]* +_ <- [ \t\n]* @@ -0,0 +1,78 @@ +#include "ht.h" + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#define FNV_BASIS 0x811c9dc5 +#define FNV_PRIME 0x01000193 + +// fnv-1a +static uint32_t hash(char *s) { + uint32_t h = FNV_BASIS; + for(;;) { + h ^= *s; + h *= FNV_PRIME; + if (*s == '\0') break; + s++; + } + return h; +} + +Ht ht_new() { + Ht h; + h.len = 0; + for (int i = 0; i < HT_SIZE; i++) { + h.b[i] = (HtEntry){ .k = NULL, .v=0 }; + } + return h; +} + +void ht_put(Ht *h, char *k, int v) { + uint32_t hv = hash(k); + int start = hv%HT_SIZE; + for (int cur = start; cur != start - 1; cur = (cur+1)%HT_SIZE) { + HtEntry *ent = &h->b[cur]; + if (ent->k == NULL) { + printf(" p %d\n",cur); + ent->k = strdup(k); + ent->v = v; + h->len++; + break; + } else if (0 == strcmp(k, ent->k)) { + printf(" r %d\n",cur); + ent->v = v; + break; + } else { + printf(" n %d\n",cur); + } + } +} + +int ht_get(Ht *h, char *k, int *v) { + uint32_t hv = hash(k); + int start = hv%HT_SIZE; + for (int cur = start; cur != start - 1; cur = (cur+1)%HT_SIZE) { + HtEntry *ent = &h->b[cur]; + if (ent->k == NULL) { + return 0; // not found + } else if (0 == strncmp(ent->k, k, 80)) { + *v = ent->v; + return 1; + } + } + return 0; // exhausted +} + +void ht_dump(Ht *h) { + printf("#%d:\n",h->len); + for (int i = 0; i < HT_SIZE; i++) { + HtEntry ent = h->b[i]; + if (ent.k != NULL) { + printf(" %s:%d\n",ent.k,ent.v); + } + } +} + + + @@ -0,0 +1,22 @@ +#ifndef _ht_h +#define _ht_h + +#define HT_SIZE 128 + +typedef struct { + char *k; + int v; +} HtEntry; + +typedef struct { + int len; + HtEntry b[HT_SIZE]; +} Ht; + +typedef Ht Env; + +Ht ht_new(); +void ht_put(Ht *h, char *k, int v); +int ht_get(Ht *h, char *k, int *v); + +#endif @@ -14,6 +14,7 @@ AstNode read() { } int main() { - for(;;) printf("%d\n",eval(read())); + Ht e = ht_new(); + for (;;) printf("%d\n",eval(&e, read())); } @@ -1,39 +1,10 @@ #include "run.h" #include "ast.h" +#include "ht.h" #include <stdio.h> #include <string.h> -// static int valueof(AstNode *a) { -// if (a->ty != AST_NUM) { -// printf("i need a number\n"); -// return -1; -// } else { -// return a->as.num; -// } -// } - -// void run_thing(AstNode *a) { -// if (a->ty != AST_LIST) -// printf("can only run a list\n"); -// else if (a->as.list.len < 3) -// printf("need at least 3 elements\n"); -// else { -// AstNode *fn = &a->as.list.vals[0]; -// if (fn->ty != AST_SYMBOL) -// printf("first el needs to be symbol\n"); -// else if (strcmp(fn->as.str, "+")) -// printf("can only run +\n"); -// else { -// int v1 = valueof(&a->as.list.vals[1]); -// int v2 = valueof(&a->as.list.vals[2]); -// printf("=> %d\n",v1+v2); -// } -// } -// } - -int eval (AstNode a); - // return pointer to nth subnode of AST_LIST node *l. // doesn't check that l is a list, or that it has at least n elems. #define NTH(l,n) (&(l)->as.list.vals[(n)]) @@ -42,34 +13,51 @@ int eval (AstNode a); #define CK_LEN(s, l, n) do { if(l.len-1 != n) { \ printf("%s fn requires exactly %d args (%ld provided)",\ s, n, l.len-1); return 0; } } while(0); -static int func_plus(AstVec l) { +static int func_plus(Env *s, AstVec l) { CK_LEN("+",l,2); - return eval(l.vals[1]) + eval(l.vals[2]); + return eval(s, l.vals[1]) + eval(s, l.vals[2]); } -static int func_id(AstVec l) { +static int func_id(Env *s, AstVec l) { CK_LEN("id",l,1); - return eval(l.vals[1]); + return eval(s, l.vals[1]); } -static int func_minus(AstVec l) { +static int func_minus(Env *s, AstVec l) { CK_LEN("-",l,2); - return eval(l.vals[1]) - eval(l.vals[2]); + return eval(s, l.vals[1]) - eval(s, l.vals[2]); } -static int func_mult(AstVec l) { +static int func_mult(Env *s, AstVec l) { CK_LEN("*",l,2); - return eval(l.vals[1]) * eval(l.vals[2]); + return eval(s, l.vals[1]) * eval(s, l.vals[2]); } -static int func_div(AstVec l) { +static int func_div(Env *s, AstVec l) { CK_LEN("/",l,2); - return eval(l.vals[1]) / eval(l.vals[2]); + return eval(s, l.vals[1]) / eval(s, l.vals[2]); } -static int func_print(AstVec l) { +static int func_print(Env *s, AstVec l) { CK_LEN("print",l,1); - int v = eval(l.vals[1]); + int v = eval(s, l.vals[1]); printf("%d\n",v); return v; } +static int func_set(Env *s, AstVec l) { + CK_LEN("set", l, 2); + if (l.vals[1].ty != AST_SYMBOL) { + printf("can only assign to symbols"); + return 0; + } + int v = eval(s, l.vals[2]); + printf(" %p set %s %d\n", (void*)s, l.vals[1].as.str, v); + ht_put(s, l.vals[1].as.str, v); + return v; +} +static int func_do(Env *s, AstVec l) { + for (int i = 1; i < l.len; i++) { + eval(s, l.vals[i]); + } + return 0; +} -typedef int (*builtin_func)(AstVec); +typedef int (*builtin_func)(Env*, AstVec); typedef struct { char *name; builtin_func func; @@ -82,25 +70,32 @@ BuiltinDesc builtins[] = { { "/", func_div }, { "id", func_id }, { "print", func_print }, + { "set", func_set }, + { "do", func_do }, + { NULL, NULL }, }; -static int call_builtin(char *name, AstVec arglist) { +static int call_builtin(Env *s, char *name, AstVec arglist) { for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) { if (0 == strcmp(bd->name, name)) { - return bd->func(arglist); + return bd->func(s, arglist); } } printf("couldn't find builtin fn %s\n",name); return 0; } - -int eval(AstNode a) { +int eval(Env *s, AstNode a) { switch (a.ty) { - case AST_SYMBOL: - printf("cant yet read variable [%s]\n", a.as.str); - return 0; + case AST_SYMBOL:; + int v; + if (ht_get(s, a.as.str, &v)) { + return v; + } else { + printf("unset variable %s\n",a.as.str); + return 0; + } break; case AST_NUM: return a.as.num; @@ -116,7 +111,7 @@ int eval(AstNode a) { printf("first element of list must be symbol\n"); return 0; } - return call_builtin(first->as.str, l); + return call_builtin(s, first->as.str, l); break; default: printf("???\n"); @@ -2,7 +2,9 @@ #define _run_h #include "ast.h" +#include "ht.h" -int eval(AstNode a); + +int eval(Env *s, AstNode a); #endif @@ -0,0 +1,39 @@ +#ifndef _val_h +#define _val_h + +#include <stdbool.h> + +struct _val; +typedef struct _val Val; +struct _obj; +typedef struct _obj Obj; + + +typedef enum { + TY_NUM, + TY_BOOL, + TY_NIL, +} ValTy; + +struct _val { + ValTy ty; + union { + double d; + bool b; + Obj *o; + } as; +}; + +struct _obj { + // some gc shit + int foo; +}; + + +#define IS_NUM(x) (x.ty == TY_NUM) +#define IS_BOOL(x) (x.ty == TY_BOOL) +#define IS_NIL(x) (x.ty == NIL) + + + +#endif |