#include #include #include #include #include #include #include #define DBGTIME(tag,block) \ do { \ clock_t start=clock(); \ DBGTIMESTART(start,tag,block); \ } while(0) #define DBGTIMESTART(start,tag,block) \ do { \ if(params.verbose){ \ fprintf(stderr,"%s",(tag)); \ } \ {block} \ if(params.verbose){ \ fprintf(stderr," (%lfs)\n",(double)(clock()-start)/CLOCKS_PER_SEC); \ } \ } while(0) __attribute__((noreturn)) void outofmem(void){ fprintf(stderr,"Memory allocation error!\n"); exit(1); } int uniqid(void){ static int i=0; return i++; } void usage(const char *argv0){ fprintf(stderr, "Usage: %s [-h] [-m ] \n" "Reads a Brainfuck program from and saves the compiled executable\n" "in .\n" "Uses nasm for assembling and gcc for linking.\n" " -h Show help\n" " -m Specify amount of tape cells (bytes) for the BF code\n" " -v Show more info about the compile process\n", argv0); } __attribute__((noreturn)) void usage1(const char *argv0){ usage(argv0); exit(1); } typedef struct Params{ int memsize; const char *srcfname,*dstfname; bool verbose; } Params; Params params={30000,NULL,NULL,false}; void parseargs(int argc,char **argv){ if(argc<2)usage1(argv[0]); for(int i=1;i0&&shiftc<0){ int id=uniqid(); fprintf(asmf, "\tcmp [maxp], rbx\n" "\tjge skip%d\n" "\tmov [maxp], rbx\n" "skip%d:\n", id,id); } lastshiftc=shiftc;*/ if(shiftc==1)fprintf(asmf,"\tinc rbx ; 1 >\n"); else if(shiftc==-1)fprintf(asmf,"\tdec rbx ; 1 <\n"); else fprintf(asmf,"\tadd rbx, %d ; %d %c\n",shiftc,shiftc<0?-shiftc:shiftc,shiftc<0?'<':'>'); shiftc=0; } switch(c){ case '+': addc++; break; case '-': addc--; break; case '>': shiftc++; break; case '<': shiftc--; break; case '[':{ struct stackitem *ls=malloc(sizeof(struct stackitem)); if(!ls)outofmem(); ls->id=uniqid(); ls->next=loopstack; loopstack=ls; fprintf(asmf, "loop%d: ; [\n" "\tcmp byte [rbx], 0\n" "\tjz loop%d_end\n" "loop%d_body:\n", ls->id,ls->id,ls->id); break; } case ']':{ if(!loopstack){ fprintf(stderr,"Excess ']' in source\n"); exit(1); } fprintf(asmf, "\tcmp byte [rbx], 0 ; ]\n" "\tjnz loop%d_body\n" "loop%d_end:\n", loopstack->id,loopstack->id); struct stackitem *ls=loopstack->next; free(loopstack); loopstack=ls; break; } case '.': fprintf(asmf, "\tmov edi, 0 ; .\n" "\tmov dil, byte [rbx]\n" "\tcall _putchar\n" "\txor edi, edi\n" "\tcall _fflush\n"); break; case ',': fprintf(asmf, "\tcall _getchar ; ,\n" "\tmov byte [rbx], al\n"); break; case '0': fprintf(asmf,"\tmov byte [rbx], 0\n"); break; default: if(c)assert(false); //should've been stripped } } while(source[i++]); if(loopstack){ fprintf(stderr,"Excess '[' in source\n"); exit(1); } } void writeepilogue(FILE *asmf){ fprintf(asmf, "\n" "\tmov rdi, [buf] ; epilogue\n" "\tcall _free\n" "\n" /*"\tlea rdi, [formatstr] ;output last cell reached\n" "\tmov rsi, [maxp]\n" "\tsub rsi, [buf]\n" "\txor eax, eax\n" "\tcall _printf\n" "\n"*/ "\txor eax, eax\n" "\tjmp mainend\n" "\n" "nomem:\n" "\tmov edi, 2\n" "\tlea rsi, [nomemstr]\n" "\tmov rdx, nomemstr.len\n" "\tcall _write\n" "\tmov eax, 1\n" "\n" "mainend:\n" "\tpop rbx\n" "\tmov rsp, rbp\n" "\tpop rbp\n" "\tret\n" "\n" "\n" "section .data\n" "sectalign 8\n" "\n" "nomemstr: db \"Out of memory!\"\n" ".len: equ $-nomemstr\n" /*"\n" "formatstr: db \"Last cell reached: %%d\", 10, 0\n" "\n" "align 8, db 0\n" "maxp: dq 0\n"*/ "\n" "\n" "section .bss\n" "sectalign 8\n" "\n" "buf: resq 1\n"); } void readsource(FILE *f,char **sourcep){ int sz=1024; char *source=malloc(sz); if(!source)outofmem(); int i=0; while(true){ if(i==sz-1){ sz*=2; source=realloc(source,sz); if(!source)outofmem(); } char c=fgetc(f); if(feof(f))break; if(!strchr("+-><[].,",c))continue; source[i++]=c; } source[i]='\0'; *sourcep=source; } void optimise(char *source){ int j=0; #define COPY do {if(j %s\n",asmfname); DBGTIME("writeprologue",writeprologue(asmf);); DBGTIME("writeprogram",writeprogram(source,asmf);); DBGTIME("writeepilogue",writeepilogue(asmf);); fclose(asmf); /*char *b; asprintf(&b,"cat -n %s",asmfname); runcmd(b); free(b);*/ int ret=compilechain(asmfname,params.dstfname); unlink(asmfname); if(params.verbose)fprintf(stderr,"unlink(%s) (asmfname)\n",asmfname); return ret; }