summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--grammar.peg12
-rw-r--r--ht.c78
-rw-r--r--ht.h22
-rw-r--r--read.c3
-rw-r--r--run.c97
-rw-r--r--run.h4
-rw-r--r--val.h39
8 files changed, 204 insertions, 57 deletions
diff --git a/Makefile b/Makefile
index e9c44a4..53062a0 100644
--- a/Makefile
+++ b/Makefile
@@ -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]*
diff --git a/ht.c b/ht.c
new file mode 100644
index 0000000..44132f5
--- /dev/null
+++ b/ht.c
@@ -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);
+ }
+ }
+}
+
+
+
diff --git a/ht.h b/ht.h
new file mode 100644
index 0000000..5aaffe7
--- /dev/null
+++ b/ht.h
@@ -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
diff --git a/read.c b/read.c
index 0fa6c47..5620607 100644
--- a/read.c
+++ b/read.c
@@ -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()));
}
diff --git a/run.c b/run.c
index eb65400..e4fa540 100644
--- a/run.c
+++ b/run.c
@@ -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");
diff --git a/run.h b/run.h
index 64484d8..155b59b 100644
--- a/run.h
+++ b/run.h
@@ -2,7 +2,9 @@
#define _run_h
#include "ast.h"
+#include "ht.h"
-int eval(AstNode a);
+
+int eval(Env *s, AstNode a);
#endif
diff --git a/val.h b/val.h
new file mode 100644
index 0000000..4560a1c
--- /dev/null
+++ b/val.h
@@ -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