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 && GetOption(OPTf_WARN_UNUSED_EXTERN)) { 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); MemCpy64(htc,&cc->htc,sizeof(CLexHashTableContext)/8); 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); MemCpy64(&cc->htc,htc,sizeof(CLexHashTableContext)/8); 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; }