U0 StreamPrint(U8 *fmt,...) {//Injects text into the compile stream. Used in #exe{} blocks. U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),*st; CLex *lx=Fs->last_lex; CStreamBlk *tempe=lx->last_stream_blk; if (tempe!=&lx->next_stream_blk) { st=MStrPrint("%s%s",tempe->body,buf); Free(tempe->body); tempe->body=st; } else PrintErr("No exe{} blk\n"); Free(buf); } U8 *LexStatement2Bin(CLex *lx,I64 *_type,I64 cmp_flags=0) {//Compile one lx statement to bin code. I64 size,i,j,k,*result=INVALID_PTR; CLexCodeCtrl *tempcbh; if (_type) *_type=RT_I64; Btr(&lx->flags,Lf_OPT_TRACE_PRESENT); if (lx->a_depth==2) LCCPush(lx); LCCInit(lx); if (!PrsStatement(lx,,,cmp_flags)) { if (lx->lcc.lcc_root.next!=&lx->lcc.lcc_root) { lx->lcc.lcc_root.last->ic_flags&=~ICF_NO_DEPEND_RESULT; LCCAdd(lx,IC_RETURN_VAL2,0,0); LCCAdd(lx,IC_RET,0,0); if (result=LCCCompile(lx,&size,NULL,_type)) { if (lx->flags&LF_AOT_COMPILE) { j=lx->a->ip; k=(size+7)>>3; for (i=0;ilcc.lcc_root.next); if (lx->a_depth==2) { tempcbh=LCCPopNoFree(lx); LCCAppend(lx,tempcbh); } return result; } CExe *CmpJoin(CLex *lx,I64 cmp_flags,U8 *map_name=NULL,U8 mapfile_drv=0) { CAOTCtrl *a,*old_a=lx->a; I64 i,j,l; U8 *buf; CAsmCodeBlk *tempc; CExeImportExport *tempe; Bool okay=TRUE; CLexHashTableContext *htc=MAlloc(sizeof(CLexHashTableContext)); CExe *result=CAlloc(sizeof(CExe)),*parent; if (parent=lx->exe) { result->parent_exe=parent; QueIns(result,parent->last); } else QueInit(result); lx->exe=result; result->next_ie=result->last_ie=&result->next_ie; lx->a=a=CAlloc(sizeof(CAOTCtrl)); lx->a_depth++; a->cb=CAlloc(sizeof(CAsmCodeBlk)); a->max_align_bits=0; a->module_org=INVALID_PTR; MemCpy(htc,&lx->htc,sizeof(CLexHashTableContext)); if (lx->htc.fun) lx->htc.glbl_hash_table=HashTableNew(128); else lx->htc.glbl_hash_table=HashTableNew(1024); if (lx->flags&LF_AOT_COMPILE) { lx->htc.define_hash_table=lx->htc.glbl_hash_table; if (lx->a_depth<=1) lx->htc.glbl_hash_table->next=cmp.asm_hash; else lx->htc.glbl_hash_table->next=htc->glbl_hash_table; } else lx->htc.glbl_hash_table->next=Fs->hash_table; lx->htc.hash_table_lst=lx->htc.local_hash_table=HashTableNew(16); lx->htc.local_hash_table->next=lx->htc.glbl_hash_table; lx->htc.local_var_lst=lx->htc.fun; //HolyC local vars lx->htc.fun=NULL; try { if (cmp_flags&CMPF_LEX_FIRST) Lex(lx); if (!(cmp_flags&CMPF_ONE_ASM_INS)) cmp_flags|=CMPF_PRS_SEMICOLON; if (lx->flags&LF_AOT_COMPILE) { while (lx->token!=TK_EOF) { buf=LexStatement2Bin(lx,NULL,cmp_flags); if (buf!=INVALID_PTR) { tempe=CAlloc(sizeof(CExeImportExport)); tempe->type=EIT_MAIN; tempe->ip=buf; QueIns(tempe,result->last_ie); } if (cmp_flags&CMPF_ASM_BLK) break; } } else PrsStatement(lx,,,cmp_flags); AsmGlblsResolve(lx,result); } catch { if (Fs->except_ch=='Compiler' && !(cmp_flags&CMPF_ASM_BLK)) { LexPutPos(lx); Fs->catch_except=TRUE; } okay=FALSE; } if (!okay) { if (lx->error_cnt<1) lx->error_cnt=1; lx->exe=result->parent_exe; Free(result); LinkedLstDel(a->cb); result=NULL; } else { if (map_name && !cmp.dont_write_to_dsk) Who("-r",lx->htc.glbl_hash_table,map_name,mapfile_drv); HashTableDel(lx->htc.local_hash_table); HashTableDel(lx->htc.glbl_hash_table); if (!a->num_ex_U8s) result->buf=NULL; else { if (lx->flags&LF_AOT_COMPILE) result->buf=MAlloc(a->num_ex_U8s); else { if (a->module_org==INVALID_PTR) result->buf=MAlloc(a->num_ex_U8s,Fs->code_heap); else result->buf=a->module_org; } result->ex_U8s=a->num_ex_U8s; tempc=a->cb; j=0; l=a->num_ex_U8s; while (tempc) { i=l; if (i>ASM_CODE_BLK_SIZE) i=ASM_CODE_BLK_SIZE; MemCpy(result->buf+j,tempc->body,i); j+=i; l-=i; tempc=tempc->next; } } LinkedLstDel(a->cb); result->abss=a->abss; result->heap_glbls=a->heap_glbls; result->max_align_bits=a->max_align_bits; result->module_org=a->module_org; } lx->exe=parent; MemCpy(&lx->htc,htc,sizeof(CLexHashTableContext)); Free(htc); Free(a); lx->a=old_a; lx->a_depth--; return result; } CExe *CmpBuf(U8 *buf,U8 *map_name=NULL, I64 *error_cnt=NULL, I64 *warning_cnt=NULL,U8 mapfile_drv=0) { CLex *lx; CExe *result=NULL; lx=LexNew(buf,LF_DONT_FREE_BUF); lx->flags|=LF_AOT_COMPILE; QueIns(lx,Fs->last_lex); result=CmpJoin(lx,CMPF_LEX_FIRST,map_name,mapfile_drv); if (error_cnt) *error_cnt=lx->error_cnt; if (warning_cnt) *warning_cnt=lx->warning_cnt; QueRem(lx); if (result) LexDel(lx); return result; } U0 CmpFixUpJITAsm(CLex *lx,CExe *tempx) { I64 i,ip2=tempx->buf+tempx->ip,*str=NULL; U8 *ptr; CLexCodeMisc *g_lb; CExeAbsAddr *tempa,*tempa1; CExeImportExport *tempe,*tempe1; CHashExport *tempex; tempa=tempx->abss; while (tempa) { tempa1=tempa->next; ptr=ip2+tempa->ip; nobound_switch (tempa->type) { case EAT_ADD_U8: *ptr(U8 *) +=ip2; break; case EAT_SUB_U8: *ptr(U8 *) -=ip2; break; case EAT_ADD_U16: *ptr(U16 *)+=ip2; break; case EAT_SUB_U16: *ptr(U16 *)-=ip2; break; case EAT_ADD_U32: *ptr(U32 *)+=ip2; break; case EAT_SUB_U32: *ptr(U32 *)-=ip2; break; case EAT_ADD_U64: *ptr(I64 *)+=ip2; break; case EAT_SUB_U64: *ptr(I64 *)-=ip2; break; } Free(tempa); tempa=tempa1; } tempe=tempx->next_ie; while (tempe!=&tempx->next_ie) { tempe1=tempe->next; if (tempe->str) { Free(str); str=tempe->str; } switch (tempe->type) { case EIT_REL32_EXPORT: case EIT_IMM32_EXPORT: case EIT_REL64_EXPORT: case EIT_IMM64_EXPORT: tempex=CAlloc(sizeof(CHashExport)); tempex->str=str; str=NULL; tempex->type=HTT_EXPORT_SYS_SYM|HTF_IMM; if (tempe->type==EIT_IMM32_EXPORT||tempe->type==EIT_IMM64_EXPORT) tempex->val=tempe->ip; else tempex->val=tempe->ip+ip2; tempex->src_link=tempe->src_link; tempe->src_link=NULL; HashAdd(tempex,Fs->hash_table); SysSymImportsResolve(tempex->str); break; case EIT_REL_I0...EIT_IMM_I64: if (tempe->str) { if (tempe->flags&EIF_GOTO_LABEL) { if(!(g_lb=LCCGoToLabelFind(lx,str))) "Unresolved Reference:%s\n",str; else { g_lb->use_cnt++; g_lb=OptLabelFwd(g_lb); i=g_lb->addr+tempx->buf; } tempex=NULL; } else { if (!(tempex=HashFind(str,Fs->hash_table,HTG_ALL-HTT_IMPORT_SYS_SYM))) "Unresolved Reference:%s\n",str; else { if (tempex->type & HTT_FUN) i=tempex(CHashFun *)->executable_addr; else if (tempex->type & HTT_GLBL_VAR) i=tempex(CHashGlblVar *)->data_addr; else i=tempex->val; } g_lb=NULL; } } if (tempex || g_lb) { ptr=tempe->ip+ip2; nobound_switch (tempe->type) { case EIT_REL_I0: case EIT_IMM_U0: break; case EIT_REL_I8: if (!(MIN_I8<=i-ptr-1<=MAX_I8)) LexExcept(lx,"branch out of range at "); *ptr(U8 *) =i-ptr-1; break; case EIT_IMM_U8: *ptr(U8 *) =i; break; case EIT_REL_I16: if (!(MIN_I16<=i-ptr-2<=MAX_I16)) LexExcept(lx,"branch out of range at "); *ptr(U16 *)=i-ptr-2; break; case EIT_IMM_U16: *ptr(U16 *)=i; break; case EIT_REL_I32: if (!(MIN_I32<=i-ptr-4<=MAX_I32)) LexExcept(lx,"branch out of range at "); *ptr(U32 *)=i-ptr-4; break; case EIT_IMM_U32: *ptr(U32 *)=i; break; case EIT_REL_I64: *ptr(I64 *)=i-ptr-8; break; case EIT_IMM_I64: *ptr(I64 *)=i; break; } } break; } Free(tempe->src_link); Free(tempe); tempe=tempe1; } Free(str); if (!lx->a_depth && Bt(&lx->opts,OPTf_COMPILE_TRACE)) Un(ip2,tempx->ex_U8s,64); QueRem(tempx); Free(tempx); } U0 CmpFixUpAOTAsm(CLex *lx,CExe *tempx) { CAOTCtrl *a=lx->a; I64 i,ip2=tempx->ip+lx->a->ip; U8 *ptr; CLexCodeMisc *g_lb=NULL; CExeAbsAddr *tempa,*tempa1; CExeImportExport *tempe,*tempe1; tempa=tempx->abss; while (tempa) { tempa1=tempa->next; tempa->next=a->abss; ptr=tempx->buf+tempx->ip+tempa->ip; nobound_switch (tempa->type) { case EAT_ADD_U8: *ptr(U8 *)+=ip2; break; case EAT_SUB_U8: *ptr(U8 *)-=ip2; break; case EAT_ADD_U16: *ptr(U16 *)+=ip2; break; case EAT_SUB_U16: *ptr(U16 *)-=ip2; break; case EAT_ADD_U32: *ptr(U32 *)+=ip2; break; case EAT_SUB_U32: *ptr(U32 *)-=ip2; break; case EAT_ADD_U64: *ptr(I64 *)+=ip2; break; case EAT_SUB_U64: *ptr(I64 *)-=ip2; break; } a->abss=tempa; tempa->ip+=ip2; tempa=tempa1; } tempe=tempx->next_ie; while (tempe!=&tempx->next_ie) { tempe1=tempe->next; QueRem(tempe); if (EIT_REL_I0<=tempe->type<=EIT_IMM_I64) { if (tempe->str) { if (tempe->flags&EIF_GOTO_LABEL) { if(!(g_lb=LCCGoToLabelFind(lx,tempe->str))) "Unresolved Reference:%s\n",tempe->str; else { g_lb->use_cnt++; g_lb=OptLabelFwd(g_lb); } } else g_lb=NULL; } } else g_lb=NULL; ptr=tempx->buf+tempx->ip+tempe->ip; if (g_lb) { i=g_lb->addr+tempx->buf; nobound_switch (tempe->type) { case EIT_REL_I0: case EIT_IMM_U0: break; case EIT_REL_I8: if (!(MIN_I8<=i-ptr-1<=MAX_I8)) LexExcept(lx,"branch out of range at "); *ptr(U8 *) =i-ptr-1; break; case EIT_IMM_U8: *ptr(U8 *) =i; break; case EIT_REL_I16: if (!(MIN_I16<=i-ptr-2<=MAX_I16)) LexExcept(lx,"branch out of range at "); *ptr(U16 *)=i-ptr-2; break; case EIT_IMM_U16: *ptr(U16 *)=i; break; case EIT_REL_I32: if (!(MIN_I32<=i-ptr-4<=MAX_I32)) LexExcept(lx,"branch out of range at "); *ptr(U32 *)=i-ptr-4; break; case EIT_IMM_U32: *ptr(U32 *)=i; break; case EIT_REL_I64: *ptr(I64 *)=i-ptr-8; break; case EIT_IMM_I64: *ptr(I64 *)=i; break; } Free(tempe->src_link); Free(tempe); } else { switch (tempe->type) { sub_switch_start: case EIT_REL32_EXPORT: case EIT_IMM32_EXPORT: case EIT_REL64_EXPORT: case EIT_IMM64_EXPORT: case EIT_IMM_U0: case EIT_IMM_U8: case EIT_IMM_U16: case EIT_IMM_U32: case EIT_IMM_I64: case EIT_REL_I0: break; case EIT_REL_I8: *ptr(U8 *) -=ip2; break; case EIT_REL_I16: *ptr(U16 *)-=ip2; break; case EIT_REL_I32: *ptr(U32 *)-=ip2; break; case EIT_REL_I64: *ptr(I64 *)-=ip2; break; sub_switch_end: tempe->ip+=ip2; break; } tempe->exe=NULL; QueIns(tempe,tempx->parent_exe->last_ie); } tempe=tempe1; } } I64 Cmp(U8 *filename,U8 *map_name=NULL,U8 *out_name=NULL,U8 mapfile_drv=0) {//AOT Compile CPP or PRJ file a and output BIN file. Returns err_cnt. U8 *ptr,*fbuf=NULL,*fbuf2=NULL,*fbuf3=NULL, *patch_table=MAlloc(0x20000); CExe *tempx; I64 i,cnt,size=0,error_cnt=0,warning_cnt=0,ex_U8s=0; CBinFile *bfh; CExeImportExport *tempe,*tempe1; CExeAbsAddr *tempa,*tempa1; CExeHeapGlblRef *temphgr,*temphgr1; CExeHeapGlbl *temphg,*temphg1; fbuf=DftExt(filename,"PRJ.Z"); fbuf2=MStrPrint("#include \"%s\"",fbuf); if (map_name) fbuf3=DftExt(map_name,"MAP.Z"); if (tempx=CmpBuf(fbuf2,fbuf3,&error_cnt,&warning_cnt,mapfile_drv)) { ex_U8s=tempx->ex_U8s; ptr=patch_table; //See $LK,"Load",A="MN:Load"$() cnt=0; tempa=tempx->abss; while (tempa) { if (!(tempa->type&1)) cnt++; tempa=tempa->next; } if (cnt) { *ptr++=EIT_ABS_ADDR; *ptr(U32 *)++=cnt; *ptr++=0; tempa=tempx->abss; while (tempa) { tempa1=tempa->next; if (!(tempa->type&1)) *ptr(U32 *)++ =tempa->ip; Free(tempa); tempa=tempa1; } } temphg=tempx->heap_glbls; while (temphg) { temphg1=temphg->next; cnt=0; temphgr=temphg->references; while (temphgr) { cnt++; temphgr=temphgr->next; } if (cnt) { *ptr++=EIT_DATA_HEAP; *ptr(U32 *)++=cnt; if (temphg->str) { i=StrLen(temphg->str); MemCpy(ptr,temphg->str,i+1); Free(temphg->str); ptr+=i+1; } else *ptr++=0; *ptr(I64 *)++=temphg->size; temphgr=temphg->references; while (temphgr) { temphgr1=temphgr->next; *ptr(U32 *)++=temphgr->ip; Free(temphgr); temphgr=temphgr1; } } Free(temphg); temphg=temphg1; } //Do exports first tempe=tempx->next_ie; while (tempe!=&tempx->next_ie) { tempe1=tempe->next; if (!tempe->type || EIT_REL32_EXPORT<=tempe->type<=EIT_IMM64_EXPORT) { QueRem(tempe); *ptr++=tempe->type; *ptr(U32 *)++=tempe->ip; if (tempe->str) { i=StrLen(tempe->str); MemCpy(ptr,tempe->str,i+1); Free(tempe->str); ptr+=i+1; } else *ptr++=0; Free(tempe->src_link); Free(tempe); } tempe=tempe1; } //Do imports second tempe=tempx->next_ie; while (tempe!=&tempx->next_ie) { tempe1=tempe->next; QueRem(tempe); *ptr++=tempe->type; if (tempe->exe) tempe->ip+=tempe->exe->ip2; *ptr(U32 *)++=tempe->ip; if (tempe->str) { i=StrLen(tempe->str); MemCpy(ptr,tempe->str,i+1); Free(tempe->str); ptr+=i+1; } else *ptr++=0; Free(tempe->src_link); Free(tempe); tempe=tempe1; } *ptr++=EIT_END; MemSet(ptr,0,16); i=ptr-patch_table; //Needs 16 ALIGN size=(sizeof(CBinFile)+ex_U8s+i+15)&-16; bfh=MAlloc(size); bfh->jmp=0xEB+256*(sizeof(CBinFile)-2); #assert sizeof(CBinFile)-2<=MAX_I8 bfh->reserved=0; bfh->bin_signature=BIN_SIGNATURE_VAL; bfh->module_org=tempx->module_org; bfh->module_align_bits=tempx->max_align_bits; bfh->patch_table_offset=sizeof(CBinFile)+ex_U8s; bfh->file_size=size; MemCpy(bfh(U8 *)+sizeof(CBinFile),tempx->buf,ex_U8s); MemCpy(bfh(U8 *)+sizeof(CBinFile)+ex_U8s,patch_table,size-ex_U8s-sizeof(CBinFile)); Free(fbuf2); if (out_name) fbuf2=DftExt(out_name,"BIN.Z"); else fbuf2=ChgExt(fbuf,"BIN.Z"); if (!cmp.dont_write_to_dsk) FileWrite(fbuf2,bfh,size); Free(bfh); Free(tempx->buf); QueDel(tempx); Free(tempx); } Free(patch_table); Free(fbuf); Free(fbuf2); Free(fbuf3); Print("Errs:%d Warns:%d Code:%X Size:%X\n",error_cnt,warning_cnt,ex_U8s,size); return error_cnt; } I64 ExePutS(U8 *buf,U8 *filename=NULL,Bool just_load=FALSE,CLexHashTableContext *htc=NULL) {//JIT Compile and execute text from a puts(""). I64 result; Bool okay=TRUE; CLex *lx; if (!filename) filename=dsk.temp_filename; lx=LexNew(buf,LF_DONT_FREE_BUF,filename); if (just_load) lx->flags|=LF_JUST_LOAD; if (Fs->last_lex!=&Fs->next_lex) { lx->opts=Fs->last_lex->opts; if (htc) { lx->flags=lx->flags &~LF_ASM_EXPRESSIONS | htc->old_flags&LF_ASM_EXPRESSIONS; MemCpy(&lx->htc,htc,sizeof(CLexHashTableContext)); } } QueIns(lx,Fs->last_lex); try { Lex(lx); result=ExeCmdLine(lx); } catch { if (Fs->except_ch=='Compiler' || Fs->except_ch=='Break') { Fs->catch_except=TRUE; okay=FALSE; result=0; } } QueRem(lx); if (okay) LexDel(lx); //TODO: can crash return result; } I64 ExePrint(U8 *fmt,...) {//JIT Compile and execute text from a printf(). I64 result; U8 *buf=StrPrintJoin(NULL,fmt,argc,argv); result=ExePutS(buf); Free(buf); return result; } I64 ExeFile(U8 *name,Bool just_load=FALSE) {//JIT Compile and execute a file. I64 result; U8 *name2=DftExt(name,"CPP.Z"), *st=MStrPrint("#include \"%s\";",name2); result=ExePutS(st,name,just_load); Free(st); Free(name2); return result; } I64 ExePutS2(U8 *buf,U8 *filename=NULL,Bool just_load=FALSE) {//throws exceptions I64 result; CLex *lx; if (!filename) filename=dsk.temp_filename; lx=LexNew(buf,LF_DONT_FREE_BUF,filename); if (just_load) lx->flags|=LF_JUST_LOAD; if (Fs->last_lex!=&Fs->next_lex) lx->opts=Fs->last_lex->opts; QueIns(lx,Fs->last_lex); Lex(lx); result=ExeCmdLine(lx); QueRem(lx); LexDel(lx); return result; } I64 ExePrint2(U8 *fmt,...) {//throws exceptions I64 result; U8 *buf=StrPrintJoin(NULL,fmt,argc,argv); result=ExePutS2(buf); Free(buf); return result; } I64 ExeFile2(U8 *name,Bool just_load=FALSE) {//throws exceptions I64 result; U8 *name2=DftExt(name,"CPP.Z"), *st=MStrPrint("#include \"%s\";",name2); result=ExePutS2(st,name,just_load); Free(st); Free(name2); return result; } I64 StreamExePrint(U8 *fmt,...) {//Suppose you want a value from the stream to be used in an #exe{} block... U8 *buf=StrPrintJoin(NULL,fmt,argc,argv); I64 result=0; CLexHashTableContext *htc; CLex *lx=Fs->last_lex; if (lx==&Fs->next_lex) PrintErr("Not Compiling\n"); else { if (!(lx->flags&LF_EXE_BLK)) LexExcept(lx,"StreamExePrint only allowed in AOT compiled #exe{} mode."); if (htc=lx->htc.next) result=ExePutS(buf,,,htc); } Free(buf); return result; } U0 CInit() { cmp.compiled_lines=0; cmp.dont_write_to_dsk=FALSE; CmpLoadDefines; CmpFillTables; MemSet(&cmp.ic_nop,0,sizeof(CIntermediateCode)); QueInit(&cmp.ic_nop); cmp.ic_nop.ic_class=cmp.internal_types[RT_I64]; cmp.ic_nop.ic_code=IC_NOP1; AsmHashLoad; UasmHashLoad; } CInit;