summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2016-08-12 21:14:11 +0200
committertomsmeding <tom.smeding@gmail.com>2016-08-12 21:14:11 +0200
commit1d274cdb2fa2cfe33397898358b5e77fe818a2fc (patch)
treeb0eb0075daf693cd25c958c0ee9ddfa065f3dcf6
parentbd9d359d64a3c6a9fbc509a6e3be6f66c6dbe940 (diff)
Functions
-rw-r--r--code.txt38
-rw-r--r--parser.c223
-rw-r--r--parser.h54
3 files changed, 210 insertions, 105 deletions
diff --git a/code.txt b/code.txt
index ce95b45..4a9abcf 100644
--- a/code.txt
+++ b/code.txt
@@ -1,21 +1,23 @@
-a = 1;
-b = !2;
-c = 1 + (- a - 3 + b > -1);
-b += 1;
-b = 3*(b//3-1);
-x = 1 + 1 + 1 + 1;
+def main(){
+ a = 1;
+ b = !2;
+ c = 1 + (- a - 3 + b > -1);
+ b += 1;
+ b = 3*(b//3-1);
+ x = 1 + 1 + 1 + 1;
-y = 1 > (1 > 1) == 1;
-kaas(1,2,"goeiemorgen\x99",sqrt(3**2+4**2));
-1 + 1 + 1;
-if (2 > 1) 1 - 1 - 1;
-1 / 1 / 1;
-1 ** 1 ** 1;
+ y = 1 > (1 > 1) == 1;
+ kaas(1,2,"goeiemorgen\x99",sqrt(3**2+4**2));
+ 1 + 1 + 1;
+ if (2 > 1) 1 - 1 - 1;
+ 1 / 1 / 1;
+ 1 ** 1 ** 1;
-if kaas
- doe(dingen);
-else if andere(kaas) {
- doe(andere,dingen);
-} else {
- print("rip");
+ if kaas
+ doe(dingen);
+ else if andere(kaas) {
+ doe(andere,dingen);
+ } else {
+ print("rip");
+ }
}
diff --git a/parser.c b/parser.c
index fa39168..6f2ce2d 100644
--- a/parser.c
+++ b/parser.c
@@ -42,6 +42,7 @@ static bool semicolon_needed_after(const AST *after){
case AST_BLOCK:
case AST_IF:
case AST_WHILE:
+ case AST_FUNC:
DBGF("false\n");
return false;
@@ -476,25 +477,25 @@ static AST* parseexpr_(const char *source,int *reslen,int minprec,int maxprec){
Token tok=nexttoken(&source,true);
DBG(printtoken(stderr,tok,"parseEXPR"));
if(tok.type==TT_ENDSTMT){
- DBGF(" (token undo)\n");
+ DBGF(" (token undo :%d)\n",__LINE__);
source=beforeop;
break;
}
if(tok.type==TT_SYM&&tok.len==1&&(tok.str[0]==')'||tok.str[0]==',')){
- DBGF(" (token undo)\n");
+ DBGF(" (token undo :%d)\n",__LINE__);
source=beforeop;
break;
}
if(tok.type!=TT_OP){
/*ast_free(tree);
return NULL;*/
- DBGF(" (token undo)\n");
+ DBGF(" (token undo :%d)\n",__LINE__);
source=beforeop;
break;
}
int prec=precedence_len(tok.str,tok.len);
if(prec<minprec){
- DBGF(" (token undo)\n");
+ DBGF(" (token undo :%d)\n",__LINE__);
source=beforeop;
break;
}
@@ -540,12 +541,110 @@ static AST* parseexpr(const char *source,int *reslen,int minprec,int maxprec){
depth++;
AST *r=parseexpr_(source,reslen,minprec,maxprec);
depth--;
- DBGF("\x1B[32mEXPR LEAVE <<< (%d)\x1B[0m\n",depth);
+ DBGF("\x1B[32mEXPR LEAVE <<< (%d) (-> %p)\x1B[0m\n",depth,r);
return r;
}
-static AST* parsestmt(const char *source,int *reslen){
- return parseexpr(source,reslen,0,INT_MAX);
+static AST* parsefunction(const char *source,int *reslen){
+ const char *origsource=source;
+
+ Token tok=nexttoken(&source,false);
+ if(tok.type!=TT_WORD||tok.len!=3||memcmp(tok.str,"def",3)!=0){
+ return NULL;
+ }
+ DBG(printtoken(stderr,tok,"func def "));
+ tok=nexttoken(&source,false);
+ if(tok.type!=TT_WORD)return NULL;
+ DBG(printtoken(stderr,tok,"func name"));
+
+ AST *func=malloc(sizeof(AST));
+ if(!func)outofmem();
+ func->type=AST_FUNC;
+ func->f.name=malloc(tok.len+1);
+ if(!func->f.name)outofmem();
+ memcpy(func->f.name,tok.str,tok.len);
+ func->f.name[tok.len]='\0';
+ func->f.nargs=0;
+ int argssz=2;
+ func->f.args=malloc(argssz*sizeof(char*));
+ if(!func->f.args)outofmem();
+ func->f.body=NULL;
+
+ tok=nexttoken(&source,false);
+ if(tok.type!=TT_SYM||tok.len!=1||tok.str[0]!='('){
+ ast_free(func);
+ return NULL;
+ }
+ DBG(printtoken(stderr,tok,"func(open"));
+ while(true){
+ tok=nexttoken(&source,false);
+ if(tok.type==TT_SYM&&tok.len==1&&tok.str[0]==')'){
+ DBG(printtoken(stderr,tok,"func)clse"));
+ break;
+ }
+ if(tok.type!=TT_WORD){
+ ast_free(func);
+ return NULL;
+ }
+ DBG(printtoken(stderr,tok,"func arg "));
+
+ if(func->f.nargs==argssz){
+ argssz*=2;
+ func->f.args=realloc(func->f.args,argssz*sizeof(char*));
+ if(!func->f.args)outofmem();
+ }
+
+ char *arg=malloc(tok.len+1);
+ if(!arg)outofmem();
+ memcpy(arg,tok.str,tok.len);
+ arg[tok.len]='\0';
+ func->f.args[func->f.nargs++]=arg;
+
+ tok=nexttoken(&source,false);
+ DBG(printtoken(stderr,tok,"func sep "));
+ if(tok.type!=TT_SYM||tok.len!=1||(tok.str[0]!=','&&tok.str[0]!=')')){
+ ast_free(func);
+ return NULL;
+ }
+ if(tok.str[0]==')')break;
+ }
+
+ int len;
+ func->f.body=parseexpr(source,&len,0,INT_MAX);
+ if(!func->f.body){
+ ast_free(func);
+ return NULL;
+ }
+ source+=len;
+
+ *reslen=source-origsource;
+ return func;
+}
+
+static AST* parseprogram(const char *source,int *reslen){
+ const char *origsource=source;
+ AST *prog=malloc(sizeof(AST));
+ if(!prog)outofmem();
+ prog->type=AST_PROGRAM;
+ prog->p.nfuncs=0;
+ int sz=2;
+ prog->p.funcs=malloc(sz*sizeof(AST*));
+ if(!prog->p.funcs)outofmem();
+ while(true){
+ const char *src=source;
+ Token tok=nexttoken(&src,false);
+ if(tok.type==TT_EOF)break;
+ int len;
+ AST *func=parsefunction(source,&len);
+ if(!func){
+ ast_free(prog);
+ return NULL;
+ }
+ prog->p.funcs[prog->p.nfuncs++]=func;
+ source+=len;
+ }
+ *reslen=source-origsource;
+ return prog;
}
static char* reportparseerror(const char *source){
@@ -583,45 +682,18 @@ static char* reportparseerror(const char *source){
}
AST* parse(const char *source,char **errmsg){
- AST *bl=malloc(sizeof(AST));
- if(!bl)outofmem();
- bl->type=AST_BLOCK;
- int sz=32;
- bl->b.len=0;
- bl->b.exprs=calloc(sz,sizeof(AST*));
- if(!bl->b.exprs)outofmem();
+ *errmsg=NULL;
int reslen;
- int cursor=0;
- while(true){
- if(bl->b.len==sz){
- sz*=2;
- bl->b.exprs=realloc(bl->b.exprs,sz*sizeof(AST*));
- if(!bl->b.exprs)outofmem();
- }
- AST *node=parsestmt(source+cursor,&reslen);
- if(!node){
- ast_free(bl);
- *errmsg=reportparseerror(source);
- return NULL;
- }
- bl->b.exprs[bl->b.len++]=node;
- cursor+=reslen;
- if(semicolon_needed_after(node)){
- const char *src=source+cursor;
- Token tok=nexttoken(&src,false);
- DBG(printtoken(stderr,tok,"parse "));
- if(tok.type!=TT_ENDSTMT){
- ast_free(bl);
- *errmsg=reportparseerror(source);
- return NULL;
- }
- cursor=src-source;
- }
- const char *src=source+cursor;
- Token tok=nexttoken(&src,false);
- if(tok.type==TT_EOF)break;
+ AST *pr=parseprogram(source,&reslen);
+ source+=reslen;
+ Token next=nexttoken(&source,false);
+ DBG(printtoken(stderr,next,"afterparse"));
+ if(next.type!=TT_EOF||!pr){
+ *errmsg=reportparseerror(source);
+ if(pr)ast_free(pr);
+ return NULL;
}
- return bl;
+ return pr;
}
static const char* charblock(char c,int n){
@@ -719,6 +791,26 @@ static void ast_debug_(FILE *stream,const AST *ast,int indent){
assert(NOT_IMPLEMENTED);
break;
+ case AST_FUNC:
+ fprintf(stream,"def %s(",ast->f.name);
+ for(int j=0;j<ast->f.nargs;j++){
+ if(j!=0)fputc(',',stream);
+ fprintf(stream,"%s",ast->f.args[j]);
+ }
+ fprintf(stream,") ");
+ ast_debug_(stream,ast->f.body,indent);
+ break;
+
+ case AST_PROGRAM:
+ for(int i=0;i<ast->p.nfuncs;i++){
+ if(i!=0){
+ fputc('\n',stream);
+ INDENT
+ }
+ ast_debug_(stream,ast->p.funcs[i],indent);
+ }
+ break;
+
default:
fprintf(stream,"AST_(??\?)");
break;
@@ -732,50 +824,55 @@ void ast_debug(FILE *stream,const AST *ast){
void ast_free(AST *ast){
switch(ast->type){
- case AST_BLOCK:{
+ case AST_BLOCK:
for(int i=0;i<ast->b.len;i++)if(ast->b.exprs[i])ast_free(ast->b.exprs[i]);
free(ast->b.exprs);
break;
- }
- case AST_OP:{
+ case AST_OP:
if(ast->o.left)ast_free(ast->o.left);
if(ast->o.right)ast_free(ast->o.right);
break;
- }
case AST_NUM:
break;
- case AST_STR:{
+ case AST_STR:
if(ast->s.str)free(ast->s.str);
break;
- }
- case AST_VAR:{
+ case AST_VAR:
if(ast->v.name)free(ast->v.name);
break;
- }
- case AST_CALL:{
+ case AST_CALL:
if(ast->c.func)free(ast->c.func);
for(int i=0;i<ast->c.nargs;i++)if(ast->c.args[i])ast_free(ast->c.args[i]);
free(ast->c.args);
break;
- }
- case AST_IF:{
- if(ast->i.cond)free(ast->i.cond);
- if(ast->i.thenb)free(ast->i.thenb);
- if(ast->i.elseb)free(ast->i.elseb);
+ case AST_IF:
+ if(ast->i.cond)ast_free(ast->i.cond);
+ if(ast->i.thenb)ast_free(ast->i.thenb);
+ if(ast->i.elseb)ast_free(ast->i.elseb);
break;
- }
- case AST_WHILE:{
- if(ast->w.cond)free(ast->w.cond);
- if(ast->w.body)free(ast->w.body);
+ case AST_WHILE:
+ if(ast->w.cond)ast_free(ast->w.cond);
+ if(ast->w.body)ast_free(ast->w.body);
+ break;
+
+ case AST_FUNC:
+ if(ast->f.name)free(ast->f.name);
+ for(int i=0;i<ast->f.nargs;i++)if(ast->f.args[i])free(ast->f.args[i]);
+ free(ast->f.args);
+ if(ast->f.body)ast_free(ast->f.body);
+ break;
+
+ case AST_PROGRAM:
+ for(int i=0;i<ast->p.nfuncs;i++)if(ast->p.funcs[i])ast_free(ast->p.funcs[i]);
+ free(ast->p.funcs);
break;
- }
}
free(ast);
}
diff --git a/parser.h b/parser.h
index dd378ae..caafe25 100644
--- a/parser.h
+++ b/parser.h
@@ -13,55 +13,59 @@ typedef enum ASTtype{
AST_CALL,
AST_IF,
AST_WHILE,
+ AST_FUNC,
+ AST_PROGRAM,
} ASTtype;
typedef struct AST AST;
-typedef struct ASTblock ASTblock;
-typedef struct ASTop ASTop;
-typedef struct ASTnum ASTnum;
-typedef struct ASTstr ASTstr;
-typedef struct ASTvar ASTvar;
-typedef struct ASTcall ASTcall;
-typedef struct ASTif ASTif;
-typedef struct ASTwhile ASTwhile;
-struct ASTblock{
+typedef struct ASTblock{
int len;
AST **exprs;
-};
-struct ASTop{
+} ASTblock;
+typedef struct ASTop{
const char *op; // Constant string, does not need to be freed
AST *left,*right;
-};
-struct ASTnum{
+} ASTop;
+typedef struct ASTnum{
bool isint;
union {
int64_t i;
double d;
};
-};
-struct ASTstr{
+} ASTnum;
+typedef struct ASTstr{
int len; // Excludes terminating null char
char *str; // May contain null chars before terminating null char
-};
-struct ASTvar{
+} ASTstr;
+typedef struct ASTvar{
char *name;
-};
-struct ASTcall{
+} ASTvar;
+typedef struct ASTcall{
char *func;
int nargs;
AST **args;
-};
-struct ASTif{
+} ASTcall;
+typedef struct ASTif{
AST *cond;
AST *thenb,*elseb;
-};
-struct ASTwhile{
+} ASTif;
+typedef struct ASTwhile{
AST *cond;
AST *body;
-};
+} ASTwhile;
+typedef struct ASTfunc{
+ char *name;
+ int nargs;
+ char **args;
+ AST *body;
+} ASTfunc;
+typedef struct ASTprogram{
+ int nfuncs;
+ AST **funcs;
+} ASTprogram;
typedef struct AST{
ASTtype type;
@@ -74,6 +78,8 @@ typedef struct AST{
ASTcall c;
ASTif i;
ASTwhile w;
+ ASTfunc f;
+ ASTprogram p;
};
} AST;