331 lines
9.0 KiB
C
331 lines
9.0 KiB
C
#include<stdio.h>
|
|
#include<stdlib.h>
|
|
#include"str.h"
|
|
#include"vec.h"
|
|
#include"pnode.h"
|
|
#include"tok.h"
|
|
#include"mem.h"
|
|
#include"state.h"
|
|
|
|
const char*partype_names[]={"PNONE","PEMPTY","PEXPRESSION","PSTATEMENT","PASSIGNMENT","PIF","PCOMMENT","PBLOCK","PWHILE","PVARDECL","PFUNDECL","PRET","PCALL","PASM","PEXTERN",NULL};
|
|
|
|
Parser parser_new(void)
|
|
{
|
|
Parser p={
|
|
.root=pnode_new(),
|
|
.mode=0,
|
|
};
|
|
return p;
|
|
}
|
|
|
|
void parser_free(Parser*p)
|
|
{
|
|
pnode_free(&p->root);
|
|
}
|
|
|
|
PNode pnode_new(void)
|
|
{
|
|
PNode n={
|
|
.pnodes=vec_new(sizeof(PNode)),
|
|
.tokens=vec_new(sizeof(Tok)),
|
|
.vars=vec_new(sizeof(Var)),
|
|
.funcs=vec_new(sizeof(Func)),
|
|
.parentnode=NULL,
|
|
.type=PEMPTY,
|
|
.firstline=0,
|
|
.stacksize=0,
|
|
};
|
|
|
|
return n;
|
|
}
|
|
|
|
void pnode_free(PNode*n)
|
|
{
|
|
if(!n)return;
|
|
|
|
if(n->tokens.buffer)
|
|
{
|
|
for(size_t i=0;i<n->tokens.size;++i)
|
|
tok_free(vec_at(&n->tokens,i,Tok*));
|
|
}
|
|
vec_free(&n->tokens);
|
|
|
|
if(n->vars.buffer)
|
|
{
|
|
for(size_t i=0;i<n->vars.size;++i)
|
|
var_free(vec_at(&n->vars,i,Var*));
|
|
}
|
|
vec_free(&n->vars);
|
|
|
|
if(n->funcs.buffer)
|
|
{
|
|
for(size_t i=0;i<n->funcs.size;++i)
|
|
var_free(vec_at(&n->funcs,i,Var*));
|
|
}
|
|
vec_free(&n->funcs);
|
|
|
|
if(n->funcs.buffer)
|
|
vec_free(&n->funcs);
|
|
|
|
for(size_t i=0;i<n->pnodes.size;++i)
|
|
pnode_free(vec_at(&n->pnodes,i,PNode*));
|
|
vec_free(&n->pnodes);
|
|
|
|
}
|
|
|
|
PNode*pnode_pushnode(PNode*n)
|
|
{
|
|
PNode t=pnode_new();
|
|
if(!n)return NULL;
|
|
|
|
vec_push(&n->pnodes,&t);
|
|
vec_at(&n->pnodes,n->pnodes.size-1,PNode*)->parentnode=n;
|
|
return vec_at(&n->pnodes,n->pnodes.size-1,PNode*);
|
|
}
|
|
|
|
void pnode_print(PNode*n,size_t lvl)
|
|
{
|
|
const bool usecolor=true;
|
|
|
|
for(size_t i=0;i<lvl;++i)
|
|
printf(" ");
|
|
printf("%p: (c:%lu/%lu) (t:%lu/%lu) %lu:",
|
|
n,
|
|
n->pnodes.size,
|
|
n->pnodes.capacity,
|
|
n->tokens.size,
|
|
n->tokens.capacity,
|
|
(n->tokens.size>0)?(vec_at(&n->tokens,0,const Tok*)->line):(0)
|
|
);
|
|
|
|
// Print tokens
|
|
printf(" [");
|
|
for(size_t i=0;i<n->tokens.size;++i)
|
|
{
|
|
if(usecolor)
|
|
printf("'%s%s%s'",
|
|
lextype_colors[vec_at(&n->tokens,i,const Tok*)->type],
|
|
vec_at(&n->tokens,i,Tok*)->str.buffer,
|
|
"\033[0m"
|
|
);
|
|
else
|
|
printf("'%s'",vec_at(&n->tokens,i,Tok*)->str.buffer);
|
|
if(i<n->tokens.size-1)
|
|
printf(", ");
|
|
}
|
|
printf("]");
|
|
|
|
printf(" %s\n",partype_names[n->type]);
|
|
|
|
++lvl;
|
|
|
|
if(n->pnodes.size>0)
|
|
{
|
|
for(size_t i=0;i<n->pnodes.size;++i)
|
|
pnode_print(vec_at(&n->pnodes,i,PNode*),lvl);
|
|
}
|
|
}
|
|
|
|
void pnode_print_brief(PNode*n,size_t lvl)
|
|
{
|
|
const bool usecolor=true;
|
|
|
|
for(size_t i=0;i<lvl;++i)
|
|
printf(" ");
|
|
|
|
if(n->tokens.size>0)
|
|
printf("%lu: ",vec_at(&n->tokens,0,Tok*)->line);
|
|
printf("%s: ",partype_names[n->type]);
|
|
|
|
// Print tokens
|
|
for(size_t i=0;i<n->tokens.size;++i)
|
|
{
|
|
//printf("%s",vec_at(&n->tokens,i,Tok*)->str.buffer);
|
|
if(usecolor)
|
|
printf("%s%s%s",
|
|
lextype_colors[vec_at(&n->tokens,i,Tok*)->type],
|
|
vec_at(&n->tokens,i,Tok*)->str.buffer,
|
|
"\033[0m"
|
|
);
|
|
else
|
|
printf("%s",vec_at(&n->tokens,i,Tok*)->str.buffer);
|
|
}
|
|
printf("\n");
|
|
|
|
++lvl;
|
|
|
|
if(n->pnodes.size>0)
|
|
for(size_t i=0;i<n->pnodes.size;++i)
|
|
pnode_print_brief(vec_at(&n->pnodes,i,PNode*),lvl);
|
|
}
|
|
|
|
// Parse Vec of Tok
|
|
void parser_parse(Parser*pnode,Vec*tokens)
|
|
{
|
|
PNode*current_node=NULL;
|
|
Tok*cur_tok=NULL;
|
|
if(!pnode||!tokens)return;
|
|
|
|
pnode->root.type=PEMPTY;
|
|
|
|
for(size_t i=0;i<tokens->size;++i)
|
|
{
|
|
if(!current_node)current_node=&pnode->root;
|
|
cur_tok=vec_at(tokens,i,Tok*);
|
|
// descend(newmode) Finalize current parser node, reset current mode/state
|
|
// newmode mode to set
|
|
#define descend(newmode) do{--i;current_node=pnode_pushnode(current_node);current_node->type=newmode;pnode->mode=newmode;current_node->firstline=cur_tok->line;}while(0)
|
|
|
|
// pushcurrenttoken() Add cur_tok to to current_node tokens
|
|
#define pushcurrenttoken() do{vec_pushta(¤t_node->tokens,cur_tok->str.buffer);\
|
|
tok_copy_nostr(vec_at(¤t_node->tokens,current_node->tokens.size-1,Tok*),\
|
|
vec_at(tokens,i,Tok*));}while(0)
|
|
|
|
// up() Set current_node to parent node if exists
|
|
#define up() do{if(current_node&¤t_node->parentnode)current_node=current_node->parentnode;}while(0)
|
|
|
|
// checktype(tokentype) True if cur_tok is of tokentype
|
|
// tokentype Token/lexeme type
|
|
#define checktype(tokentype) if(cur_tok->type==tokentype)
|
|
|
|
// checktypesub(tokentype,subtype) True if cur_tok is of tokentype and subtype
|
|
// tokentype Token/lexeme type
|
|
// tokensubtype Token/lexeme subtype
|
|
#define checktypesub(tokentype,tokensubtype) if(cur_tok->type==tokentype&&cur_tok->subtype==tokensubtype)
|
|
|
|
// globalcode() True if PNode is in global scope
|
|
#define globalcode() do{if(current_node->parentnode==NULL)err_log("%u: statement not inside function declaration",cur_tok->line);}while(0)
|
|
switch(pnode->mode)
|
|
{
|
|
|
|
case PNONE:
|
|
while(current_node->parentnode&&(current_node->parentnode->type==PIF||
|
|
current_node->parentnode->type==PWHILE))
|
|
up();
|
|
up();
|
|
switch(cur_tok->type)
|
|
{
|
|
|
|
case LKEYWORD:
|
|
if(strcmp("if",cur_tok->str.buffer)==0){globalcode();++i;descend(PIF);}
|
|
else if(strcmp("ret",cur_tok->str.buffer)==0){globalcode();++i;descend(PRET);}
|
|
else if(strcmp("while",cur_tok->str.buffer)==0){globalcode();++i;descend(PWHILE);}
|
|
else if(strcmp("let",cur_tok->str.buffer)==0){globalcode();++i;descend(PVARDECL);}
|
|
else if(strcmp("fn",cur_tok->str.buffer)==0){++i;descend(PFUNDECL);}
|
|
else if(strcmp("asm",cur_tok->str.buffer)==0){++i;descend(PASM);}
|
|
else if(strcmp("ext",cur_tok->str.buffer)==0){++i;descend(PEXTERN);}
|
|
break;
|
|
|
|
case LOPERATOR:
|
|
if(cur_tok->subtype==LLCBRACE)
|
|
{
|
|
if(!current_node->parentnode)
|
|
err_log("%u: code block does not have parent",cur_tok->line);
|
|
++i;pnode->mode=PNONE;descend(PBLOCK);
|
|
}
|
|
else if(cur_tok->subtype==LRCBRACE){
|
|
if(current_node->parentnode==NULL)
|
|
err_log("%u: unmatched '}'",cur_tok->line);
|
|
up();
|
|
}
|
|
break;
|
|
|
|
// Expressions
|
|
case LCOMMENT:descend(PCOMMENT);break;
|
|
case LIDENTIFIER:
|
|
case LINTEGER:
|
|
case LFLOAT:
|
|
default:
|
|
{
|
|
globalcode();
|
|
descend(PEXPRESSION);break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case PCOMMENT:pushcurrenttoken();pnode->mode=PNONE;break;
|
|
|
|
case PIF:
|
|
pushcurrenttoken();
|
|
if(cur_tok->type==LOPERATOR&&cur_tok->subtype==LRPAREN){
|
|
++i;pnode->mode=PNONE;descend(PEXPRESSION);break;}
|
|
break;
|
|
|
|
case PWHILE:
|
|
pushcurrenttoken();
|
|
if(cur_tok->type==LOPERATOR&&cur_tok->subtype==LRPAREN){
|
|
++i;pnode->mode=PNONE;descend(PEXPRESSION);break;}
|
|
break;
|
|
|
|
case PASM:
|
|
pushcurrenttoken();
|
|
checktypesub(LOPERATOR,LENDSTATEMENT){pnode->mode=PNONE;break;}
|
|
//if(cur_tok->type==LOPERATOR&&cur_tok->subtype==LRPAREN){
|
|
//++i;pnode->mode=PNONE;descend(PEXPRESSION);break;}
|
|
break;
|
|
|
|
case PBLOCK:
|
|
checktypesub(LOPERATOR,LRCBRACE){up();pnode->mode=PNONE;break;}
|
|
descend(PEXPRESSION);
|
|
break;
|
|
|
|
case PVARDECL:
|
|
checktypesub(LOPERATOR,LENDSTATEMENT){pnode->mode=PNONE;break;}
|
|
checktypesub(LOPERATOR,LRCBRACE){up();pnode->mode=PNONE;break;}
|
|
pushcurrenttoken();
|
|
break;
|
|
|
|
case PCALL:
|
|
case PRET:
|
|
checktypesub(LOPERATOR,LENDSTATEMENT){pnode->mode=PNONE;break;}
|
|
pushcurrenttoken();
|
|
break;
|
|
|
|
case PFUNDECL:
|
|
checktypesub(LOPERATOR,LENDSTATEMENT){pnode->mode=PNONE;break;}
|
|
checktypesub(LOPERATOR,LLCBRACE){pnode->mode=PBLOCK;descend(PEXPRESSION);break;}
|
|
checktypesub(LOPERATOR,LRCBRACE){up();pnode->mode=PNONE;break;}
|
|
checktypesub(LOPERATOR,LRPAREN){pushcurrenttoken();++i;descend(PEXPRESSION);break;}
|
|
pushcurrenttoken();
|
|
break;
|
|
|
|
// Default Grammar Rule:
|
|
// TODO: The default case needs more sophisticated grammar rules
|
|
// And we should also split cases apart
|
|
case PEXPRESSION:
|
|
case PASSIGNMENT:
|
|
default:
|
|
|
|
checktype(LCOMMENT){current_node->type=PCOMMENT;pnode->mode=PCOMMENT;--i;break;}
|
|
else checktypesub(LOPERATOR,LENDSTATEMENT){
|
|
if(current_node->parentnode->type==PIF)up();
|
|
else if(current_node->parentnode->type==PWHILE)up();
|
|
pnode->mode=PNONE;break;
|
|
}
|
|
else checktypesub(LOPERATOR,LASSIGN){pnode->mode=PASSIGNMENT;current_node->type=PASSIGNMENT;}
|
|
else checktypesub(LOPERATOR,LLCBRACE){pnode->mode=PBLOCK;current_node->type=PBLOCK;break;}
|
|
else checktypesub(LOPERATOR,LRCBRACE){pnode->mode=PNONE;up();break;}
|
|
else if(cur_tok->type==LKEYWORD){
|
|
if(strcmp("if",cur_tok->str.buffer)==0){pnode->mode=PIF;current_node->type=PIF;break;}
|
|
else if(strcmp("while",cur_tok->str.buffer)==0){pnode->mode=PWHILE;current_node->type=PWHILE;break;}
|
|
else if(strcmp("let",cur_tok->str.buffer)==0){pnode->mode=PVARDECL;current_node->type=PVARDECL;break;}
|
|
else if(strcmp("ret",cur_tok->str.buffer)==0){pnode->mode=PRET;current_node->type=PRET;break;}
|
|
else if(strcmp("fn",cur_tok->str.buffer)==0){pnode->mode=PFUNDECL;current_node->type=PFUNDECL;break;}
|
|
else if(strcmp("asm",cur_tok->str.buffer)==0){pnode->mode=PASM;current_node->type=PASM;break;}
|
|
else if(strcmp("ext",cur_tok->str.buffer)==0){pnode->mode=PEXTERN;current_node->type=PEXTERN;break;}
|
|
}
|
|
pushcurrenttoken();
|
|
//vec_pushta(¤t_node->tokens,);
|
|
break;
|
|
#undef checktype
|
|
#undef checktypesub
|
|
|
|
}
|
|
#undef descend
|
|
#undef pushcurrenttoken
|
|
#undef up
|
|
#undef globalcode
|
|
}
|
|
}
|