diff options
Diffstat (limited to 'parser.c')
-rw-r--r-- | parser.c | 223 |
1 files changed, 160 insertions, 63 deletions
@@ -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); } |