templeos-info/public/Wb/Compiler/PrsStmt.HC

1223 lines
33 KiB
HolyC
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

CHashClass *PrsClass(CCmpCtrl *cc,I64 keyword,I64 fsp_flags,Bool is_extern)
{
CHashClass *tmpc,*base_class;
if (cc->token!=TK_IDENT)
LexExcept(cc,"Expecting identifier at ");
if (is_extern) {
tmpc=PrsClassNew;
tmpc->str=cc->cur_str;
cc->cur_str=NULL;
HashAdd(tmpc,cc->htc.glbl_hash_table);
LBts(&tmpc->flags,Cf_EXTERN);
HashSrcFileSet(cc,tmpc);
Lex(cc);
} else {
if (cc->flags&CCF_AOT_COMPILE)
tmpc=HashFind(cc->cur_str,cc->htc.glbl_hash_table,HTT_CLASS);
else
tmpc=HashSingleTableFind(cc->cur_str,cc->htc.glbl_hash_table,HTT_CLASS);
if (tmpc) {
if (!Bt(&tmpc->flags,Cf_EXTERN))
tmpc=NULL;
else if (tmpc->use_cnt<3)
UnusedExternWarning(cc,tmpc);
}
if (tmpc) {
Free(tmpc->src_link);
tmpc->src_link=NULL;
Free(tmpc->idx);
tmpc->idx=NULL;
} else {
tmpc=PrsClassNew;
tmpc->str=cc->cur_str;
cc->cur_str=NULL;
HashAdd(tmpc,cc->htc.glbl_hash_table);
}
LBtr(&tmpc->flags,Cf_EXTERN);
if (fsp_flags&FSF_PUBLIC)
tmpc->type|=HTF_PUBLIC;
tmpc->use_cnt=0;
if (cc->last_U16=='\n')
HashSrcFileSet(cc,tmpc,-1);
else
HashSrcFileSet(cc,tmpc,0);
if (Lex(cc)==':') {
if (Lex(cc)!=TK_IDENT || !(base_class=cc->hash_entry) ||
!(base_class->type&HTT_CLASS))
LexExcept(cc,"Invalid class at ");
if (Lex(cc)==',')
LexExcept(cc,"Only one base class allowed at this time at ");
tmpc->base_class=base_class;
tmpc->size+=base_class->size;
}
if (keyword==KW_UNION)
PrsVarLst(cc,tmpc,PRS0_NULL|PRS1_CLASS|PRSF_UNION);
else
PrsVarLst(cc,tmpc,PRS0_NULL|PRS1_CLASS);
tmpc->size+=tmpc->neg_offset;
}
return tmpc;
}
CHashFun *PrsFunJoin(CCmpCtrl *cc,CHashClass *tmp_return,
U8 *name,I64 fsp_flags)
{
CMemberLst *tmpm,*header_lst;
CAOTCtrl *aotc=cc->aotc;
CHashClass *header_return;
CHashFun *tmpf;
I64 header_arg_cnt;
if (name) {//if not fun_ptr
if (cc->flags&CCF_AOT_COMPILE) {
if ((tmpf=HashFind(name,cc->htc.glbl_hash_table,HTT_FUN)) &&
tmpf->type & HTF_IMPORT)
tmpf=NULL;
} else
if ((tmpf=HashSingleTableFind(name,cc->htc.glbl_hash_table,HTT_FUN)) &&
!Bt(&tmpf->flags,Cf_EXTERN))
tmpf=NULL;
if (tmpf && tmpf->use_cnt<3)
UnusedExternWarning(cc,tmpf);
} else
tmpf=NULL;
if (tmpf) {
tmpf->used_reg_mask=REGG_CLOBBERED+REGG_SAVED+REGG_STK_TMP;
Free(tmpf->src_link);
tmpf->src_link=NULL;
Free(tmpf->idx);
tmpf->idx=NULL;
Free(name);
header_arg_cnt=tmpf->arg_cnt;
header_lst=tmpf->member_lst_and_root;
header_return=tmpf->return_class;
tmpf->member_lst_and_root=NULL;
ClassMemberLstDel(tmpf);
} else {
tmpf=PrsFunNew;
header_return=NULL;
tmpf->used_reg_mask=REGG_CLOBBERED+REGG_SAVED+REGG_STK_TMP;
tmpf->clobbered_reg_mask=REGG_CLOBBERED+REGG_STK_TMP;
tmpf->str=name;
if (cc->flags&CCF_AOT_COMPILE)
tmpf->exe_addr=aotc->rip;
else
tmpf->exe_addr=&UndefinedExtern;
LBts(&tmpf->flags,Cf_EXTERN);
tmpf->flags|=fsp_flags&FSG_FUN_FLAGS1;
if (name) //if not fun_ptr
HashAdd(tmpf,cc->htc.glbl_hash_table);
}
BEqu(&tmpf->type,HTf_PUBLIC,fsp_flags&FSF_PUBLIC);
tmpf->return_class=tmp_return;
tmpf->use_cnt=0;
HashSrcFileSet(cc,tmpf);
PrsVarLst(cc,tmpf,PRS0_NULL|PRS1_FUN_ARG);
tmpf->arg_cnt=tmpf->member_cnt;
if (0<tmpf->arg_cnt<<3<=I16_MAX && !Bt(&tmpf->flags,Ff_DOT_DOT_DOT))
LBts(&tmpf->flags,Ff_RET1);
tmpm=tmpf->member_lst_and_root;
while (tmpm) {
tmpm->offset+=16; //RBP+RETURN
tmpm=tmpm->next;
}
tmpf->size=0;
if (header_return) {
if (GetOption(OPTf_WARN_HEADER_MISMATCH)) {
if (tmpf->return_class!=header_return) {
PrintWarn("Fun Header return mismatch '%s'\n",tmpf->str);
cc->warning_cnt++;
}
if (!MemberLstCmp(tmpf->member_lst_and_root,header_lst,header_arg_cnt)) {
PrintWarn("Fun header args mismatch '%s'\n",tmpf->str);
cc->warning_cnt++;
}
}
MemberLstDel(header_lst);
}
return tmpf;
}
U0 PrsFun(CCmpCtrl *cc,CHashClass *tmp_return,U8 *name,I64 fsp_flags)
{
CMemberLst *tmpm;
CCodeMisc *saved_leave_label;
I64 i,j,size,*r;
Bool old_trace;
cc->fun_lex_file=cc->lex_include_stk;
cc->min_line=cc->max_line=cc->lex_include_stk->line_num;
cc->flags&=~CCF_NO_REG_OPT;
cc->htc.local_var_lst=cc->htc.fun=PrsFunJoin(cc,tmp_return,name,fsp_flags);
COCPush(cc);
Btr(&cc->flags,CCf_PASS_TRACE_PRESENT);
COCInit(cc);
ICAdd(cc,IC_ENTER,0,0);
saved_leave_label=cc->lb_leave;
cc->lb_leave=COCMiscNew(cc,CMT_LABEL);
cc->flags&=~CCF_HAS_RETURN;
PrsStmt(cc,,,0);
if (cc->max_line<cc->min_line)
cc->max_line=cc->min_line;
if (cc->htc.fun->return_class->size && !(cc->flags&CCF_HAS_RETURN))
LexWarn(cc,"Function should return val ");
ICAdd(cc,IC_LABEL,cc->lb_leave,0);
cc->lb_leave=saved_leave_label;
ICAdd(cc,IC_LEAVE,0,cc->htc.fun->return_class);
cc->htc.fun->size&=~7;
if (cc->flags&CCF_AOT_COMPILE) {
cc->htc.fun->exe_addr=cc->aotc->rip;
cc->htc.fun->type|=HTF_EXPORT|HTF_RESOLVE;
r=COCCompile(cc,&size,&cc->htc.fun->dbg_info,NULL);
if (r) {
j=(size+7)>>3;
for (i=0;i<j;i++)
AOTStoreCodeU64(cc,r[i]);
Free(r);
}
} else {
old_trace=Btr(&cc->opts,OPTf_TRACE);
cc->htc.fun->exe_addr=COCCompile(
cc,&size,&cc->htc.fun->dbg_info,NULL);
if (old_trace) {
Bts(&cc->opts,OPTf_TRACE);
Un(cc->htc.fun->exe_addr,size,64);
}
SysSymImportsResolve(cc->htc.fun->str);
}
LBtr(&cc->htc.fun->flags,Cf_EXTERN);
COCPop(cc);
tmpm=cc->htc.fun->member_lst_and_root;
while (tmpm) {
if (tmpm->flags & MLF_NO_UNUSED_WARN) {
if (tmpm->use_cnt>1&&StrCmp(tmpm->str,"_anon_"))
PrintWarn("Unneeded no_warn\n $$LK,\"FL:%s,%d\"$$'%s' in '%s'\n",
cc->lex_include_stk->full_name,cc->lex_include_stk->line_num,
tmpm->str,cc->htc.fun->str);
} else if (!tmpm->use_cnt && GetOption(OPTf_WARN_UNUSED_VAR))
PrintWarn("Unused var\n $$LK,\"FL:%s,%d\"$$'%s' in '%s'\n",
cc->lex_include_stk->full_name,cc->lex_include_stk->line_num,
tmpm->str,cc->htc.fun->str);
tmpm=tmpm->next;
}
cc->htc.local_var_lst=cc->htc.fun=cc->fun_lex_file=NULL;
}
U0 PrsGlblVarLst(CCmpCtrl *cc,I64 saved_mode,CHashClass *saved_tmpc,
I64 saved_val,I64 fsp_flags)
{
I64 i,j,mode,k,val;
U8 *st;
CHashExport *tmpex;
CHashGlblVar *tmpg;
CAOTCtrl *aotc=cc->aotc;
CAOTHeapGlbl *tmphg;
CHashClass *tmpc;
CHashFun *tmpf,*tmpf_fun_ptr;
CArrayDim tmpad;
Bool has_alias,undef_array_size,is_array;
while (TRUE) {
tmpc=PrsType(cc,&saved_tmpc,&saved_mode,NULL,&st,
&tmpf_fun_ptr,&tmpex,&tmpad,fsp_flags);
if (!st) return;
if (tmpad.next)
is_array=TRUE;
else if (tmpad.total_cnt<0) {
is_array=TRUE;
tmpc--;
} else
is_array=FALSE;
val=saved_val;
mode=saved_mode;
if (tmpex && mode&255==PRS0_EXTERN && !(cc->flags&CCF_AOT_COMPILE) &&
tmpex->type&HTT_EXPORT_SYS_SYM) {
val=tmpex->val;
mode=PRS0__EXTERN|PRS1_NOT_REALLY__EXTERN;
}
if (cc->token=='(') {
switch (mode&255) {
case PRS0__INTERN:
tmpf=PrsFunJoin(cc,tmpc,st,fsp_flags);
tmpf->exe_addr=val;
Bts(&tmpf->flags,Ff_INTERNAL);
LBtr(&tmpf->flags,Cf_EXTERN);
return;
case PRS0__EXTERN:
if (!(fsp_flags&FSF__) && !(mode&PRS1_NOT_REALLY__EXTERN))
LexExcept(cc,"Expecting label with underscore at ");
tmpf=PrsFunJoin(cc,tmpc,st,fsp_flags);
tmpf->exe_addr=val;
SysSymImportsResolve(tmpf->str);
LBtr(&tmpf->flags,Cf_EXTERN);
if (saved_mode&255==PRS0__EXTERN)
LBts(&tmpf->flags,Ff__EXTERN);
if (cc->flags&CCF_AOT_COMPILE)
tmpf->type|=HTF_RESOLVE;
return;
case PRS0_EXTERN:
PrsFunJoin(cc,tmpc,st,fsp_flags);
return;
case PRS0__IMPORT:
if (!(fsp_flags&FSF__))
LexExcept(cc,"Expecting label with underscore at ");
case PRS0_IMPORT:
if (!(cc->flags&CCF_AOT_COMPILE))
LexExcept(cc,"import not needed at ");
else {
tmpf=PrsFunJoin(cc,tmpc,st,fsp_flags);
tmpf->type|=HTF_IMPORT;
if (mode&255==PRS0__IMPORT)
tmpf->import_name=StrNew(val);
else
tmpf->import_name=StrNew(st);
}
return;
default:
PrsFun(cc,tmpc,st,fsp_flags);
return;
}
} else {
if (tmpad.total_cnt<0) {
i=0;
undef_array_size=TRUE;
} else {
i=tmpad.total_cnt;
undef_array_size=FALSE;
}
if (tmpf_fun_ptr)
j=sizeof(U8 *);
else
j=tmpc->size;
j*=i;
has_alias=FALSE;
tmphg=NULL;
switch (mode&255) {
case PRS0__EXTERN:
if (cc->flags&CCF_AOT_COMPILE) {
tmpg=CAlloc(sizeof(CHashGlblVar));
tmpg->data_addr_rip=val;
tmpg->type=HTT_GLBL_VAR | HTF_EXPORT;
} else {
tmpg=CAlloc(sizeof(CHashGlblVar),Fs->code_heap);
tmpg->data_addr=val;
tmpg->type=HTT_GLBL_VAR;
}
tmpg->flags|=GVF_ALIAS;
break;
case PRS0__IMPORT:
case PRS0_IMPORT:
if (!(cc->flags&CCF_AOT_COMPILE))
LexExcept(cc,"import not needed at ");
else {
tmpg=CAlloc(sizeof(CHashGlblVar));
tmpg->type=HTT_GLBL_VAR | HTF_IMPORT;
if (mode&255==PRS0__IMPORT)
tmpg->import_name=StrNew(val);
else
tmpg->import_name=StrNew(st);
}
break;
case PRS0_EXTERN:
if (cc->flags&CCF_AOT_COMPILE) {
tmpg=CAlloc(sizeof(CHashGlblVar));
tmpg->type=HTT_GLBL_VAR;
} else {
tmpg=CAlloc(sizeof(CHashGlblVar),Fs->code_heap);
tmpg->type=HTT_GLBL_VAR|HTF_UNRESOLVED;
}
break;
default:
if (cc->flags&CCF_AOT_COMPILE) {
if (Bt(&cc->opts,OPTf_GLBLS_ON_DATA_HEAP)) {
if (cc->token=='=')
LexExcept(cc,"Can't init glbl var on data heap in AOT module ");
tmpg=CAlloc(sizeof(CHashGlblVar));
tmphg=tmpg->heap_glbl=CAlloc(sizeof(CAOTHeapGlbl));
tmphg->size=j;
tmphg->str=StrNew(st);
tmphg->next=aotc->heap_glbls;
aotc->heap_glbls=tmphg;
tmpg->flags=GVF_DATA_HEAP;
tmpg->type=HTT_GLBL_VAR; //TODO: HTF_EXPORT
if (tmpex && tmpex->type & HTT_GLBL_VAR) //TODO!! extern
LexExcept(cc,"Feature not implemented ");
} else {
tmpg=CAlloc(sizeof(CHashGlblVar));
if (cc->token=='=')
tmpg->data_addr=CAlloc(j);
if (tmpc->size>=8) //align
while (aotc->rip&7)
AOTStoreCodeU8(cc,0);
else if (tmpc->size==4)
while (aotc->rip&3)
AOTStoreCodeU8(cc,0);
else if (tmpc->size==2)
while (aotc->rip&1)
AOTStoreCodeU8(cc,0);
tmpg->data_addr_rip=aotc->rip;
tmpg->type=HTT_GLBL_VAR | HTF_EXPORT;
if (tmpex && tmpex->type & HTT_GLBL_VAR)
has_alias=TRUE;
for (k=0;k<j;k++)
AOTStoreCodeU8(cc,0); //Init AOT glbl to zero.
}
} else {
if (Bt(&cc->opts,OPTf_GLBLS_ON_DATA_HEAP)) {
tmpg=CAlloc(sizeof(CHashGlblVar),Fs->code_heap);
tmpg->data_addr=MAlloc(j);
tmpg->flags=GVF_DATA_HEAP;
} else {
tmpg=CAlloc(sizeof(CHashGlblVar),Fs->code_heap);
tmpg->data_addr=MAlloc(j,Fs->code_heap);
}
tmpg->type=HTT_GLBL_VAR;
if (tmpex && tmpex->type&HTT_GLBL_VAR &&
tmpex->type&HTF_UNRESOLVED &&
MHeapCtrl(tmpex)==MHeapCtrl(tmpg))
has_alias=TRUE;
if (sys_var_init_flag)
MemSet(tmpg->data_addr,sys_var_init_val,j);
}
}
tmpg->dim.next=tmpad.next;
if (fsp_flags&FSF_PUBLIC)
tmpg->type|=HTF_PUBLIC;
tmpg->var_class=tmpc;
tmpg->str=st;
tmpg->size=j;
tmpg->dim.total_cnt=i;
tmpg->use_cnt=0;
if (cc->last_U16=='\n')
HashSrcFileSet(cc,tmpg,-1);
else
HashSrcFileSet(cc,tmpg,0);
if (mode&255==PRS0_IMPORT || mode&255==PRS0__IMPORT)
tmpg->flags|=GVF_IMPORT;
if (mode&255==PRS0_EXTERN)
tmpg->flags|=GVF_EXTERN;
if (tmpf_fun_ptr) {
tmpg->fun_ptr=tmpf_fun_ptr;
tmpg->flags|=GVF_FUN;
}
if (is_array)
tmpg->flags|=GVF_ARRAY;
HashAdd(tmpg,cc->htc.glbl_hash_table);
if (!(cc->flags&CCF_AOT_COMPILE) && !(tmpg->flags&GVF_EXTERN))
SysSymImportsResolve(tmpg->str);
if (cc->token=='=') {
if (undef_array_size) {
LexPush(cc);
LexPush(cc);
Lex(cc);
PrsGlblInit(cc,tmpg,1);
LexPopNoRestore(cc);
tmpg->size=tmpg->dim.total_cnt*tmpc->size;
if (tmphg)
tmphg->size=tmpg->size;
if (cc->flags&CCF_AOT_COMPILE)
for (k=0;k<tmpg->size;k++)
AOTStoreCodeU8(cc,0);
else
if (sys_var_init_flag)
MemSet(tmpg->data_addr,sys_var_init_val,k);
LexPopRestore(cc);
}
LexPush(cc);
Lex(cc);
PrsGlblInit(cc,tmpg,2);
if (cc->flags&CCF_AOT_COMPILE)
for (k=0;k<tmpg->size;k++)
AOTStoreCodeU8At(cc,tmpg->data_addr_rip+k,tmpg->data_addr[k]);
LexPopNoRestore(cc);
}
if (has_alias) {
if (tmpex(CHashGlblVar *)->use_cnt<2) {
PrintWarn("Unused extern '%s'\n",tmpex(CHashGlblVar *)->str);
cc->warning_cnt++;
}
tmpex(CHashGlblVar *)->flags|=GVF_ALIAS;
tmpex(CHashGlblVar *)->data_addr=tmpg->data_addr;
tmpex(CHashGlblVar *)->data_addr_rip=tmpg->data_addr_rip;
}
if (cc->token==',')
Lex(cc);
else {
if (cc->token!=';')
LexExcept(cc,"Missing ';' at");
Lex(cc);
return;
}
}
}
}
U0 PrsIf(CCmpCtrl *cc,I64 try_cnt,CCodeMisc *lb_break)
{
CCodeMisc *lb,*lb1;
I64 k;
if (cc->token!='(')
LexExcept(cc,"Expecting '(' at ");
Lex(cc);
if (!PrsExpression(cc,NULL,FALSE))
throw('Compiler');
if (cc->token!=')')
LexExcept(cc,"Missing ')' at ");
Lex(cc);
lb=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_BR_ZERO,lb,0);
PrsStmt(cc,try_cnt,lb_break);
k=PrsKeyWord(cc);
if (k==KW_ELSE) {
Lex(cc);
lb1=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_JMP,lb1,0);
ICAdd(cc,IC_LABEL,lb,0);
PrsStmt(cc,try_cnt,lb_break);
ICAdd(cc,IC_LABEL,lb1,0);
} else
ICAdd(cc,IC_LABEL,lb,0);
}
U0 PrsWhile(CCmpCtrl *cc,I64 try_cnt)
{
CCodeMisc *lb,*lb_done;
if (cc->token!='(')
LexExcept(cc,"Expecting '(' at ");
Lex(cc);
lb=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_LABEL,lb,0);
if (!PrsExpression(cc,NULL,FALSE))
throw('Compiler');
if (cc->token!=')')
LexExcept(cc,"Missing ')' at ");
Lex(cc);
lb_done=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_BR_ZERO,lb_done,0);
PrsStmt(cc,try_cnt,lb_done);
ICAdd(cc,IC_JMP,lb,0);
ICAdd(cc,IC_LABEL,lb_done,0);
}
U0 PrsDoWhile(CCmpCtrl *cc,I64 try_cnt)
{
CCodeMisc *lb,*lb_done;
lb=COCMiscNew(cc,CMT_LABEL);
lb_done=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_LABEL,lb,0);
PrsStmt(cc,try_cnt,lb_done);
if (PrsKeyWord(cc)!=KW_WHILE)
LexExcept(cc,"Missing 'while' at");
if (Lex(cc)!='(')
LexExcept(cc,"Expecting '(' at ");
Lex(cc);
if (!PrsExpression(cc,NULL,FALSE))
throw('Compiler');
if (cc->token!=')')
LexExcept(cc,"Missing ')' at ");
ICAdd(cc,IC_BR_NOT_ZERO,lb,0);
ICAdd(cc,IC_LABEL,lb_done,0);
if (Lex(cc)!=';')
LexExcept(cc,"Missing ';' at");
Lex(cc);
}
U0 PrsFor(CCmpCtrl *cc,I64 try_cnt)
{
CCodeCtrl *tmpcbh;
CCodeMisc *lb,*lb_done;
if (cc->token!='(')
LexExcept(cc,"Expecting '(' at ");
Lex(cc);
PrsStmt(cc,try_cnt);
lb=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_LABEL,lb,0);
if (!PrsExpression(cc,NULL,FALSE))
throw('Compiler');
lb_done=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_BR_ZERO,lb_done,0);
if (cc->token!=';')
LexExcept(cc,"Missing ';' at");
Lex(cc);
COCPush(cc);
COCInit(cc);
if (cc->token!=')')
PrsStmt(cc,try_cnt,NULL,0);
COCPush(cc);
tmpcbh=COCPopNoFree(cc);
COCPop(cc);
if (cc->token!=')')
LexExcept(cc,"Missing ')' at ");
Lex(cc);
PrsStmt(cc,try_cnt,lb_done);
COCAppend(cc,tmpcbh);
ICAdd(cc,IC_JMP,lb,0);
ICAdd(cc,IC_LABEL,lb_done,0);
}
class CSubSwitch {
CSubSwitch *next,*last;
CCodeMisc *lb_start,*lb_break;
};
class CSwitchCase {
CSwitchCase *next;
CCodeMisc *label;
I64 val;
CSubSwitch *ss;
};
U0 PrsSwitch(CCmpCtrl *cc,I64 try_cnt)
{
CSwitchCase *header=NULL,*tmps,*tmps1; //Leaks on except
CSubSwitch head,*tmpss; //Leaks on except
CCodeMisc *lb_dft,*lb_fwd_case,*mc_jt,*lb_entry,**jmp_table;
CIntermediateCode *tmpi_sub,*tmpi_cmp,*tmpi_jmp,*tmpi_start;
Bool dft_found=FALSE,nobound;
I64 i,k_start=I64_MIN,k_end,lo=I64_MAX,hi=I64_MIN,range;
if (cc->token=='(')
nobound=FALSE;
else if (cc->token=='[')
nobound=TRUE;
else
LexExcept(cc,"Expecting '(' or '[' at ");
Lex(cc);
QueInit(&head);
head.last->lb_break=COCMiscNew(cc,CMT_LABEL);
head.last->lb_break->use_cnt++;
lb_dft=COCMiscNew(cc,CMT_LABEL);
lb_dft->use_cnt++;
mc_jt=COCMiscNew(cc,CMT_JMP_TABLE);
mc_jt->begin=COCMiscNew(cc,CMT_LABEL);
mc_jt->begin->use_cnt++;
if (!PrsExpression(cc,NULL,FALSE))
throw('Compiler');
tmpi_sub=ICAdd(cc,IC_IMM_I64,0,cmp.internal_types[RT_I64]);
ICAdd(cc,IC_SUB,0,cmp.internal_types[RT_I64]);
tmpi_cmp=ICAdd(cc,IC_IMM_I64,0,cmp.internal_types[RT_I64]);
if (nobound) {
ICAdd(cc,IC_NOBOUND_SWITCH,mc_jt,0);
if (cc->token!=']')
LexExcept(cc,"Missing ']' at ");
} else {
ICAdd(cc,IC_SWITCH,mc_jt,0);
if (cc->token!=')')
LexExcept(cc,"Missing ')' at ");
}
if (Lex(cc)!='{')
LexExcept(cc,"Expecting '{' at ");
Lex(cc);
ICAdd(cc,IC_LABEL,mc_jt->begin,0);
while (TRUE) {
while (cc->token && cc->token!='}') {
sw_cont:
switch (PrsKeyWord(cc)) {
case KW_END:
goto sw_sub_end;
case KW_START:
if (Lex(cc)==':')
Lex(cc);
else
LexExcept(cc,"Expecting ':' at ");
tmpss=MAlloc(sizeof(CSubSwitch));
QueIns(tmpss,head.last);
head.last->lb_break=COCMiscNew(cc,CMT_LABEL);
head.last->lb_break->use_cnt++;
lb_fwd_case=COCMiscNew(cc,CMT_LABEL);
tmpi_jmp=ICAdd(cc,IC_JMP,lb_fwd_case,0);
tmpss->lb_start=COCMiscNew(cc,CMT_LABEL);
tmpi_start=ICAdd(cc,IC_LABEL,tmpss->lb_start,0);
while (cc->token && cc->token!='}') {
switch (PrsKeyWord(cc)) {
case KW_END:
OptFree(tmpi_jmp);
goto sw_sub_end;
case KW_START:
case KW_CASE:
case KW_DFT:
if (cc->coc.coc_head.last==tmpi_start) {
OptFree(tmpi_jmp);
tmpss->lb_start=NULL;
} else {
ICAdd(cc,IC_RET,0,0);
ICAdd(cc,IC_LABEL,lb_fwd_case,0);
ICAdd(cc,IC_SUB_CALL,tmpss->lb_start,0);//In case fall-thru
}
goto sw_cont;
default:
PrsStmt(cc,try_cnt);
}
}
break;
case KW_CASE:
if (head.next!=&head) {
lb_fwd_case=COCMiscNew(cc,CMT_LABEL);
tmpi_jmp=ICAdd(cc,IC_JMP,lb_fwd_case,0);//In case fall-thru
}
Lex(cc);
lb_entry=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_LABEL,lb_entry,0);
lb_entry->use_cnt++;
if (head.next!=&head) {
tmpss=head.next;
while (tmpss!=&head) {
if (tmpss->lb_start)
ICAdd(cc,IC_SUB_CALL,tmpss->lb_start,0);
tmpss=tmpss->next;
}
ICAdd(cc,IC_LABEL,lb_fwd_case,0);
}
if (cc->token==':') {
if (k_start==I64_MIN)
k_start=0;
else
k_start++;
} else
k_start=LexExpressionI64(cc);
if (k_start<lo) lo=k_start;
if (k_start>hi) hi=k_start;
if (cc->token==':') {
Lex(cc);
tmps=MAlloc(sizeof(CSwitchCase));
tmps->label=lb_entry;
tmps->val=k_start;
tmps->next=header;
header=tmps;
} else if (cc->token==TK_ELLIPSIS) {
Lex(cc);
k_end=LexExpressionI64(cc);
if (cc->token==':') {
Lex(cc);
if (k_end<lo) lo=k_end;
if (k_end>hi) hi=k_end;
if (k_start>k_end)
SwapI64(&k_start,&k_end);
for (i=k_start;i<=k_end;i++) {
tmps=MAlloc(sizeof(CSwitchCase));
tmps->label=lb_entry;
tmps->val=i;
tmps->next=header;
header=tmps;
}
k_start=k_end;
} else
LexExcept(cc,"Expecting ':' at ");
} else
LexExcept(cc,"Expecting ':' at ");
break;
case KW_DFT:
if (head.next!=&head) {
lb_fwd_case=COCMiscNew(cc,CMT_LABEL);
tmpi_jmp=ICAdd(cc,IC_JMP,lb_fwd_case,0);//In case fall-thru
}
Lex(cc);
ICAdd(cc,IC_LABEL,lb_dft,0);
if (cc->token==':')
Lex(cc);
else
LexExcept(cc,"Expecting ':' at ");
if (head.next!=&head) {
tmpss=head.next;
while (tmpss!=&head) {
if (tmpss->lb_start)
ICAdd(cc,IC_SUB_CALL,tmpss->lb_start,0);
tmpss=tmpss->next;
}
ICAdd(cc,IC_LABEL,lb_fwd_case,0);
}
dft_found=TRUE;
break;
default:
PrsStmt(cc,try_cnt,head.last->lb_break);
}
}
sw_sub_end:
tmpss=head.last;
ICAdd(cc,IC_LABEL,tmpss->lb_break,0);
if (tmpss==&head) {
if (cc->token!='}')
LexExcept(cc,"Missing '}' at ");
Lex(cc);
break;
} else {
QueRem(tmpss);
Free(tmpss);
if (PrsKeyWord(cc)!=KW_END)
LexExcept(cc,"Missing 'end' at ");
if (Lex(cc)==':')
Lex(cc);
else
LexExcept(cc,"Expecting ':' at ");
}
}
if (!dft_found)
ICAdd(cc,IC_LABEL,lb_dft,0);
if (0<lo<=16)
lo=0;
range=hi-lo+1;
if (lo>hi || !(0<range<=0xFFFF))
LexExcept(cc,"switch range error at ");
jmp_table=MAlloc((sizeof(CCodeMisc *)*range+0x1FF)&~0x1FF);
MemSetI64(jmp_table,lb_dft,range);
tmpi_sub->ic_data=lo;
tmpi_cmp->ic_data=range;
tmps=header;
while (tmps) {
tmps1=tmps->next;
if (jmp_table[tmps->val-lo]!=lb_dft)
LexExcept(cc,"Duplicate case at ");
else
jmp_table[tmps->val-lo]=tmps->label;
Free(tmps);
tmps=tmps1;
}
mc_jt->dft=lb_dft;
mc_jt->jmp_table=jmp_table;
mc_jt->range=range;
}
U0 PrsNoWarn(CCmpCtrl *cc)
{
CMemberLst *tmpm;
while (cc->token==TK_IDENT) {
if (!(tmpm=cc->local_var_entry))
LexExcept(cc,"Expecting local var at ");
tmpm->flags|=MLF_NO_UNUSED_WARN;
if (Lex(cc)==',')
Lex(cc);
else if (cc->token!=';')
LexExcept(cc,"Expecting ',' at ");
}
}
U0 PrsStreamBlk(CCmpCtrl *cc)
{
CLexHashTableContext *htc=MAlloc(sizeof(CLexHashTableContext));
CStreamBlk *tmpe=MAlloc(sizeof(CStreamBlk));
tmpe->body=StrNew("");
QueIns(tmpe,cc->last_stream_blk);
COCPush(cc);
QueInit(&cc->coc.coc_next_misc);
MemCpy(htc,&cc->htc,sizeof(CLexHashTableContext));
htc->old_flags=cc->flags;
cc->htc.next=htc;
cc->htc.fun=cc->htc.local_var_lst=NULL;
cc->htc.define_hash_table=cc->htc.hash_table_lst=
cc->htc.glbl_hash_table=cc->htc.local_hash_table=Fs->hash_table;
cc->flags=cc->flags & ~(CCF_ASM_EXPRESSIONS|CCF_AOT_COMPILE) | CCF_EXE_BLK;
if (cc->token=='{')
Lex(cc);
else
LexExcept(cc,"Missing '}' at ");
while (cc->token && cc->token!='}')
ExeCmdLine(cc);
MemCpy(&cc->htc,htc,sizeof(CLexHashTableContext));
cc->flags=cc->flags&~CCF_EXE_BLK |
htc->old_flags & (CCF_ASM_EXPRESSIONS|CCF_EXE_BLK|CCF_AOT_COMPILE);
Free(htc);
COCPop(cc);
QueRem(tmpe);
if (*tmpe->body)
LexIncludeStr(cc,"StreamBlk",tmpe->body,FALSE);
else
Free(tmpe->body);
Free(tmpe);
Lex(cc); //Skip '}'
}
U0 PrsTryBlk(CCmpCtrl *cc,I64 try_cnt)
{
CCodeMisc *lb_catch,*lb_done,*lb_untry;
CHashClass *tmpc=cmp.internal_types[RT_PTR];
CHashFun *tmp_try=HashFind("SysTry",cc->htc.hash_table_lst,HTT_FUN),
*tmp_untry=HashFind("SysUntry",cc->htc.hash_table_lst,HTT_FUN);
if (!tmp_try || !tmp_untry)
LexExcept(cc,"Missing header for SysTry() and SysUntry() at ");
cc->flags|=CCF_NO_REG_OPT; //TODO:Currently no reg vars in funs with try/catch
lb_catch=COCMiscNew(cc,CMT_LABEL);
lb_done =COCMiscNew(cc,CMT_LABEL);
lb_untry=COCMiscNew(cc,CMT_LABEL);
ICAdd(cc,IC_CALL_START,0,0);
ICAdd(cc,IC_GET_LABEL,lb_untry,tmpc,ICF_PUSH_RES);
ICAdd(cc,IC_GET_LABEL,lb_catch,tmpc,ICF_PUSH_RES);
if (Bt(&tmp_try->flags,Cf_EXTERN)) {
cc->abs_cnts.externs++;
if (cc->flags&CCF_AOT_COMPILE)
ICAdd(cc,IC_CALL_IMPORT,tmp_try,tmpc);
else
ICAdd(cc,IC_CALL_INDIRECT2,&tmp_try->exe_addr,tmpc);
} else
ICAdd(cc,IC_CALL,tmp_try->exe_addr,tmpc);
if ((Bt(&tmp_try->flags,Ff_RET1) ||
Bt(&tmp_try->flags,Ff_ARGPOP)) && !Bt(&tmp_try->flags,Ff_NOARGPOP))
ICAdd(cc,IC_ADD_RSP1,16,tmpc);
else
ICAdd(cc,IC_ADD_RSP,16,tmpc);
ICAdd(cc,IC_CALL_END,0,tmpc);
ICAdd(cc,IC_END_EXP,0,0,ICF_RES_NOT_USED);
PrsStmt(cc,try_cnt+1);
ICAdd(cc,IC_LABEL,lb_untry,0);
ICAdd(cc,IC_CALL_START,0,0);
if (Bt(&tmp_untry->flags,Cf_EXTERN)) {
cc->abs_cnts.externs++;
if (cc->flags&CCF_AOT_COMPILE)
ICAdd(cc,IC_CALL_IMPORT,tmp_untry,tmpc);
else
ICAdd(cc,IC_CALL_INDIRECT2,&tmp_untry->exe_addr,tmpc);
} else
ICAdd(cc,IC_CALL,tmp_untry->exe_addr,tmpc);
ICAdd(cc,IC_CALL_END,0,tmpc);
ICAdd(cc,IC_END_EXP,0,0,ICF_RES_NOT_USED);
ICAdd(cc,IC_JMP,lb_done,0);
if (PrsKeyWord(cc)!=KW_CATCH)
LexExcept(cc,"Missing 'catch' at");
Lex(cc);
ICAdd(cc,IC_LABEL,lb_catch,0);
PrsStmt(cc,try_cnt+1);
ICAdd(cc,IC_RET,0,tmpc);
ICAdd(cc,IC_LABEL,lb_done,0);
}
Bool PrsStmt(CCmpCtrl *cc,I64 try_cnt=0,
CCodeMisc *lb_break=NULL,I64 cmp_flags=CMPF_PRS_SEMICOLON)
{
I64 i,fsp_flags=0;
CHashExport *tmpex;
CCodeMisc *g_lb;
U8 *import_name;
CHashFun *tmp_untry;
CAOT *tmpaot;
if (cmp_flags&CMPF_ONE_ASM_INS) {
if (cc->flags&CCF_AOT_COMPILE || cc->aot_depth)
PrsAsmBlk(cc,CMPF_ONE_ASM_INS);
else if (tmpaot=CmpJoin(cc,CMPF_ASM_BLK|CMPF_ONE_ASM_INS))
CmpFixUpJITAsm(cc,tmpaot);
fsp_flags=FSF_ASM;
} else
while (TRUE) {
while (cc->token==',')
Lex(cc);
if (cc->token=='{') {
Lex(cc);
while (cc->token!='}' && cc->token!=TK_EOF)
PrsStmt(cc,try_cnt,lb_break);
if (cc->lex_include_stk==cc->fun_lex_file)
cc->max_line=cc->lex_include_stk->line_num;
if (Lex(cc)!=',') goto sm_done;
} else if (cc->token==';') {
if (cmp_flags&CMPF_PRS_SEMICOLON)
Lex(cc);
if (cc->token!=',') goto sm_done;
} else {
if (cc->token==TK_IDENT) {
if (tmpex=cc->hash_entry) {
if (tmpex->type & HTT_KEYWORD) {
i=tmpex(CHashGeneric *)->user_data0;
switch [i] {
case KW_KWS_NUM-1: //nobound switch
default: //A keyword that is not valid here is just a symbol.
goto sm_not_keyword_afterall;
start:
case KW_ASM:
if (cc->htc.fun) {
if (tmpaot=CmpJoin(cc,CMPF_ASM_BLK))
ICAdd(cc,IC_ASM,tmpaot,0);
Lex(cc); //Skip '}' of asm{}
} else {
if (cc->flags&CCF_AOT_COMPILE || cc->aot_depth) {
Lex(cc);
PrsAsmBlk(cc,0);
if (cc->flags&CCF_AOT_COMPILE && cc->aot_depth==1)
Lex(cc); //Skip '}' of asm{}
} else {
if (tmpaot=CmpJoin(cc,CMPF_ASM_BLK))
CmpFixUpJITAsm(cc,tmpaot);
Lex(cc); //Skip '}' of asm{}
}
fsp_flags=FSF_ASM;
}
break;
start:
Lex(cc);
case KW_LOCK:
cc->lock_cnt++;
PrsStmt(cc,try_cnt);
cc->lock_cnt--;
break;
case KW_TRY:
PrsTryBlk(cc,try_cnt);
break;
case KW_IF:
PrsIf(cc,try_cnt,lb_break);
break;
case KW_FOR:
PrsFor(cc,try_cnt);
break;
case KW_WHILE:
PrsWhile(cc,try_cnt);
break;
case KW_DO:
PrsDoWhile(cc,try_cnt);
break;
case KW_SWITCH:
PrsSwitch(cc,try_cnt);
break;
end:
end:
if (cc->token!=',') goto sm_done;
break;
start:
if (cc->htc.fun)
LexExcept(cc,"Not allowed in fun");
Lex(cc);
case KW__EXTERN:
if (Bt(&cc->opts,OPTf_EXTERNS_TO_IMPORTS))
goto sm_underscore_import;
if (cc->token!=TK_IDENT || !(tmpex=cc->hash_entry) ||
!(tmpex->type & HTT_EXPORT_SYS_SYM))
LexExcept(cc,"Expecting system sym at ");
if (*cc->cur_str=='_')
fsp_flags|=FSF__;
i=tmpex->val;
Lex(cc);
if (cc->token!=TK_IDENT || !(tmpex=cc->hash_entry) ||
!(tmpex->type & (HTT_CLASS|HTT_INTERNAL_TYPE)))
LexExcept(cc,"Expecting type at ");
Lex(cc);
PrsGlblVarLst(cc,PRS0__EXTERN|PRS1_NULL,tmpex,i,fsp_flags);
break;
case KW__IMPORT:
sm_underscore_import:
if (cc->token!=TK_IDENT)
LexExcept(cc,"Expecting system sym at ");
if (*cc->cur_str=='_')
fsp_flags|=FSF__;
import_name=cc->cur_str;
cc->cur_str=0;
if (Lex(cc)!=TK_IDENT || !(tmpex=cc->hash_entry) ||
!(tmpex->type & (HTT_CLASS|HTT_INTERNAL_TYPE)))
LexExcept(cc,"Expecting type at ");
Lex(cc);
PrsGlblVarLst(cc,PRS0__IMPORT|PRS1_NULL,tmpex,
import_name,fsp_flags);
Free(import_name);
break;
case KW_EXTERN:
if (cc->token!=TK_IDENT)
LexExcept(cc,"Expecting type at ");
tmpex=cc->hash_entry;
i=PrsKeyWord(cc);
if (i==KW_CLASS||i==KW_UNION) {
Lex(cc);
PrsClass(cc,i,fsp_flags,TRUE);
fsp_flags&=FSF_ASM;
goto sm_semicolon;
}
if (!tmpex ||
!(tmpex->type & (HTT_CLASS|HTT_INTERNAL_TYPE)))
LexExcept(cc,"Expecting type at ");
if (Bt(&cc->opts,OPTf_EXTERNS_TO_IMPORTS))
goto sm_import;
Lex(cc);
PrsGlblVarLst(cc,PRS0_EXTERN|PRS1_NULL,tmpex,0,fsp_flags);
break;
case KW_IMPORT:
if (cc->token!=TK_IDENT || !(tmpex=cc->hash_entry) ||
!(tmpex->type & (HTT_CLASS|HTT_INTERNAL_TYPE)))
LexExcept(cc,"Expecting type at ");
sm_import:
Lex(cc);
PrsGlblVarLst(cc,PRS0_IMPORT|PRS1_NULL,tmpex,0,fsp_flags);
break;
case KW__INTERN:
i=LexExpressionI64(cc);
if (cc->token!=TK_IDENT || !(tmpex=cc->hash_entry) ||
!(tmpex->type & (HTT_CLASS|HTT_INTERNAL_TYPE)))
LexExcept(cc,"Expecting type at ");
Lex(cc);
PrsGlblVarLst(cc,PRS0__INTERN|PRS1_NULL,tmpex,i,fsp_flags);
break;
end:
fsp_flags&=FSF_ASM;
break;
start:
case KW_STATIC:
fsp_flags=FSF_STATIC|fsp_flags&FSF_ASM;
break;
case KW_INTERRUPT:
fsp_flags=FSF_INTERRUPT|FSF_NOARGPOP|
fsp_flags&(FSG_FUN_FLAGS2|FSF_ASM);
break;
case KW_HASERRCODE:
fsp_flags=FSF_HASERRCODE|fsp_flags&(FSG_FUN_FLAGS2|FSF_ASM);
break;
case KW_ARGPOP:
fsp_flags=FSF_ARGPOP|fsp_flags&(FSG_FUN_FLAGS2|FSF_ASM);
break;
case KW_NOARGPOP:
fsp_flags=FSF_NOARGPOP|fsp_flags&(FSG_FUN_FLAGS2|FSF_ASM);
break;
case KW_PUBLIC:
fsp_flags=FSF_PUBLIC|fsp_flags&(FSG_FUN_FLAGS2|FSF_ASM);
break;
end:
Lex(cc);
break;
case KW_RETURN:
if (!cc->htc.fun)
LexExcept(cc,"Not in fun. Can't return a val ");
if (try_cnt) {
tmp_untry=HashFind("SysUntry",
cc->htc.hash_table_lst,HTT_FUN);
for (i=0;i<try_cnt;i++) {
if (Bt(&tmp_untry->flags,Cf_EXTERN)) {
cc->abs_cnts.externs++;
if (cc->flags&CCF_AOT_COMPILE)
ICAdd(cc,IC_CALL_IMPORT,
tmp_untry,cmp.internal_types[RT_PTR]);
else
ICAdd(cc,IC_CALL_INDIRECT2,
&tmp_untry->exe_addr,
cmp.internal_types[RT_PTR]);
} else
ICAdd(cc,IC_CALL,tmp_untry->exe_addr,
cmp.internal_types[RT_PTR]);
}
}
if (Lex(cc)!=';') {
if (!cc->htc.fun->return_class->size)
LexWarn(cc,"Function should NOT return val ");
if (!PrsExpression(cc,NULL,FALSE))
throw('Compiler');
ICAdd(cc,IC_RETURN_VAL,0,cc->htc.fun->return_class);
cc->flags|=CCF_HAS_RETURN;
} else if (cc->htc.fun->return_class->size)
LexWarn(cc,"Function should return val ");
ICAdd(cc,IC_JMP,cc->lb_leave,0);
goto sm_semicolon;
case KW_GOTO:
if (Lex(cc)!=TK_IDENT)
LexExcept(cc,"Expecting identifier at ");
if (!(g_lb=COCGoToLabelFind(cc,cc->cur_str))) {
g_lb=COCMiscNew(cc,CMT_GOTO_LABEL);
g_lb->str=cc->cur_str;
cc->cur_str=NULL;
}
g_lb->use_cnt++;
ICAdd(cc,IC_JMP,g_lb,0);
Lex(cc);
goto sm_semicolon;
case KW_BREAK:
Lex(cc);
if (!lb_break)
LexExcept(cc,"'break' not allowed\n");
ICAdd(cc,IC_JMP,lb_break,0);
goto sm_semicolon;
case KW_NO_WARN:
Lex(cc);
PrsNoWarn(cc);
goto sm_semicolon;
case KW_UNION:
case KW_CLASS:
Lex(cc);
tmpex=PrsClass(cc,i,fsp_flags,FALSE);
if (!cc->htc.fun && cc->token!=';') {
PrsGlblVarLst(cc,PRS0_NULL|PRS1_NULL,tmpex,0,fsp_flags);
fsp_flags&=FSF_ASM;
break;
} else {
fsp_flags&=FSF_ASM;
goto sm_semicolon;
}
}
} else {//Ident, found in hash table, not keyword
sm_not_keyword_afterall:
if (tmpex->type & (HTT_CLASS|HTT_INTERNAL_TYPE)) {
if (cc->htc.fun) {
if (fsp_flags&FSF_STATIC)
PrsVarLst(cc,cc->htc.fun,PRS0_NULL|PRS1_STATIC_LOCAL_VAR);
else
PrsVarLst(cc,cc->htc.fun,PRS0_NULL|PRS1_LOCAL_VAR);
if (cc->token=='}') goto sm_done;
} else {
Lex(cc);
PrsGlblVarLst(cc,PRS0_NULL|PRS1_NULL,tmpex,0,fsp_flags);
}
} else {
if (tmpex->type & (HTT_OPCODE|HTT_ASM_KEYWORD)) {
if (cc->htc.fun) {
if (tmpaot=CmpJoin(cc,CMPF_ASM_BLK|CMPF_ONE_ASM_INS))
ICAdd(cc,IC_ASM,tmpaot,0);
} else
LexExcept(cc,"Use Asm Blk at ");
if (cc->token!=',') goto sm_done;
} else
goto sm_prs_exp;
}
fsp_flags&=FSF_ASM;
}
} else {//Ident, not in hash table
if (cc->local_var_entry)
goto sm_prs_exp;
if (!(g_lb=COCGoToLabelFind(cc,cc->cur_str))) {
g_lb=COCMiscNew(cc,CMT_GOTO_LABEL);
g_lb->str=cc->cur_str;
cc->cur_str=NULL;
} else if (g_lb->flags&CMF_DEFINED)
LexExcept(cc,"Duplicate goto label at ");
g_lb->flags|=CMF_DEFINED;
ICAdd(cc,IC_LABEL,g_lb,0);
if (Lex(cc)==':') //skip cur_str
Lex(cc); //skip colon
else
LexExcept(cc,"Undefined identifier at ");
if (!cc->htc.fun)
LexExcept(cc,"No global labels at ");
if (cc->token!=',') goto sm_done;
}
} else if (cc->token==TK_STR||cc->token==TK_CHAR_CONST) {
PrsFunCall(cc,NULL,FALSE,NULL);
goto sm_semicolon;
} else if (cc->token!=TK_EOF) {//Non-cur_str symbol, num or something
sm_prs_exp:
if (!PrsExpression(cc,NULL,TRUE))
throw('Compiler');
sm_semicolon:
if (cmp_flags&CMPF_PRS_SEMICOLON) {
if (cc->token==';')
Lex(cc);
else if (cc->token!=',')
LexExcept(cc,"Missing ';' at");
}
if (cc->token!=',') goto sm_done;
} else
goto sm_done; //TK_EOF
}
}
sm_done:
return fsp_flags&FSF_ASM;
}