lr/pnode.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(&current_node->tokens,cur_tok->str.buffer);\
tok_copy_nostr(vec_at(&current_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&&current_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(&current_node->tokens,);
break;
#undef checktype
#undef checktypesub
}
#undef descend
#undef pushcurrenttoken
#undef up
#undef globalcode
}
}