diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | ast.c | 18 | ||||
-rw-r--r-- | ast.h | 3 | ||||
-rw-r--r-- | grammar.peg | 17 | ||||
-rw-r--r-- | read.c | 19 | ||||
-rw-r--r-- | read.h | 9 | ||||
-rw-r--r-- | run.c | 126 | ||||
-rw-r--r-- | run.h | 8 | ||||
-rw-r--r-- | test.bþ | 3 |
9 files changed, 188 insertions, 21 deletions
@@ -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) @@ -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]; + } +} + @@ -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; -} - @@ -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())); +} + @@ -0,0 +1,9 @@ +#ifndef _read_h +#define _read_h + +#include "parser.h" +#include "ast.h" + +AstNode read(); + +#endif @@ -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; + } +} + @@ -0,0 +1,8 @@ +#ifndef _run_h +#define _run_h + +#include "ast.h" + +int eval(AstNode a); + +#endif @@ -0,0 +1,3 @@ +(print + (+ (id 2) + (- (print 5) 3))) |