summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--ast.c18
-rw-r--r--ast.h3
-rw-r--r--grammar.peg17
-rw-r--r--read.c19
-rw-r--r--read.h9
-rw-r--r--run.c126
-rw-r--r--run.h8
-rw-r--r--test.bþ3
9 files changed, 188 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index 1e6f6ef..e9c44a4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-CS=parser.c ast.c
-HS=ast.h parser.h
-CFLAGS=-Wall -Wpedantic
+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
badthing: $(CS) $(HS)
$(CC) $(CFLAGS) -o badthing $(CS)
diff --git a/ast.c b/ast.c
index ee2f0ab..2443283 100644
--- a/ast.c
+++ b/ast.c
@@ -60,18 +60,30 @@ AstNode astnode_new_symbol(char *s) {
void astnode_disp(AstNode *a) {
switch (a->ty) {
case AST_NUM:
- printf("n:%d ",a->as.num);
+ printf("%s:%d ",ast_ty_to_str(a->ty),a->as.num);
break;
case AST_LIST:;
AstVec *v = &a->as.list;
- printf("l:(");
+ printf("%s:(",ast_ty_to_str(a->ty));
for (int i = 0; i < v->len; i++) {
astnode_disp(&v->vals[i]);
}
printf(")");
break;
case AST_SYMBOL:;
- printf("s:%s ",a->as.str);
+ printf("%s:%s ",ast_ty_to_str(a->ty), a->as.str);
break;
}
}
+
+const char* ty_names[] = {
+ "list", "num", "symbol"
+};
+const char *ast_ty_to_str(AstTy ty) {
+ if (ty >= AST_TY_LAST || ty < 0) {
+ return "???";
+ } else {
+ return ty_names[ty];
+ }
+}
+
diff --git a/ast.h b/ast.h
index 3647a7b..b3e9d75 100644
--- a/ast.h
+++ b/ast.h
@@ -9,6 +9,7 @@ typedef enum {
AST_NUM,
AST_SYMBOL,
} AstTy;
+#define AST_TY_LAST AST_SYMBOL+1
struct _astnode;
typedef struct _astnode AstNode;
@@ -39,6 +40,8 @@ AstNode astnode_new_symbol(char *s);
void astnode_disp(AstNode *a);
+const char *ast_ty_to_str(AstTy ty);
+
#endif
diff --git a/grammar.peg b/grammar.peg
index 12847e5..5d1dad8 100644
--- a/grammar.peg
+++ b/grammar.peg
@@ -7,6 +7,7 @@
%common {
#include "ast.h"
+#include "run.h"
}
%value "AstNode"
@@ -22,24 +23,10 @@ list <- { $$ = astnode_new_list(); }
)*
')' _
-number <- < [0-9]+ > _ (! ident_char) { $$ = astnode_new_num(atoi($1)); }
+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]*
-%%
-int main() {
- pcc_context_t *ctx = pcc_create(NULL);
- AstNode ret;
- memset(&ret, 0, sizeof ret);
- pcc_parse(ctx, &ret);
-
- astnode_disp(&ret);
- putchar('\n');
-
- pcc_destroy(ctx);
- return 0;
-}
-
diff --git a/read.c b/read.c
new file mode 100644
index 0000000..0fa6c47
--- /dev/null
+++ b/read.c
@@ -0,0 +1,19 @@
+#include <string.h>
+#include <stdio.h>
+
+#include "read.h"
+#include "run.h"
+
+AstNode read() {
+ AstNode ret;
+ memset(&ret, 0, sizeof ret);
+ pcc_context_t *ctx = pcc_create(NULL);
+ pcc_parse(ctx, &ret);
+ pcc_destroy(ctx);
+ return ret;
+}
+
+int main() {
+ for(;;) printf("%d\n",eval(read()));
+}
+
diff --git a/read.h b/read.h
new file mode 100644
index 0000000..80f0261
--- /dev/null
+++ b/read.h
@@ -0,0 +1,9 @@
+#ifndef _read_h
+#define _read_h
+
+#include "parser.h"
+#include "ast.h"
+
+AstNode read();
+
+#endif
diff --git a/run.c b/run.c
new file mode 100644
index 0000000..eb65400
--- /dev/null
+++ b/run.c
@@ -0,0 +1,126 @@
+#include "run.h"
+#include "ast.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)])
+
+// n is max index
+#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) {
+ CK_LEN("+",l,2);
+ return eval(l.vals[1]) + eval(l.vals[2]);
+}
+static int func_id(AstVec l) {
+ CK_LEN("id",l,1);
+ return eval(l.vals[1]);
+}
+static int func_minus(AstVec l) {
+ CK_LEN("-",l,2);
+ return eval(l.vals[1]) - eval(l.vals[2]);
+}
+static int func_mult(AstVec l) {
+ CK_LEN("*",l,2);
+ return eval(l.vals[1]) * eval(l.vals[2]);
+}
+static int func_div(AstVec l) {
+ CK_LEN("/",l,2);
+ return eval(l.vals[1]) / eval(l.vals[2]);
+}
+static int func_print(AstVec l) {
+ CK_LEN("print",l,1);
+ int v = eval(l.vals[1]);
+ printf("%d\n",v);
+ return v;
+}
+
+typedef int (*builtin_func)(AstVec);
+typedef struct {
+ char *name;
+ builtin_func func;
+} BuiltinDesc;
+
+BuiltinDesc builtins[] = {
+ { "+", func_plus },
+ { "-", func_minus },
+ { "*", func_mult },
+ { "/", func_div },
+ { "id", func_id },
+ { "print", func_print },
+ { NULL, NULL },
+};
+
+static int call_builtin(char *name, AstVec arglist) {
+ for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) {
+ if (0 == strcmp(bd->name, name)) {
+ return bd->func(arglist);
+ }
+ }
+ printf("couldn't find builtin fn %s\n",name);
+ return 0;
+}
+
+
+int eval(AstNode a) {
+ switch (a.ty) {
+ case AST_SYMBOL:
+ printf("cant yet read variable [%s]\n", a.as.str);
+ return 0;
+ break;
+ case AST_NUM:
+ return a.as.num;
+ break;
+ case AST_LIST:;
+ AstVec l = a.as.list;
+ if (l.len < 1) {
+ printf("can't execute empty list\n");
+ return 0;
+ }
+ AstNode *first = &l.vals[0];
+ if (first->ty != AST_SYMBOL) {
+ printf("first element of list must be symbol\n");
+ return 0;
+ }
+ return call_builtin(first->as.str, l);
+ break;
+ default:
+ printf("???\n");
+ return 0;
+ }
+}
+
diff --git a/run.h b/run.h
new file mode 100644
index 0000000..64484d8
--- /dev/null
+++ b/run.h
@@ -0,0 +1,8 @@
+#ifndef _run_h
+#define _run_h
+
+#include "ast.h"
+
+int eval(AstNode a);
+
+#endif
diff --git a/test.bþ b/test.bþ
new file mode 100644
index 0000000..c791a5d
--- /dev/null
+++ b/test.bþ
@@ -0,0 +1,3 @@
+(print
+ (+ (id 2)
+ (- (print 5) 3)))