summaryrefslogtreecommitdiff
path: root/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'parser.c')
-rw-r--r--parser.c223
1 files changed, 160 insertions, 63 deletions
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);
}