एक ब्रेनफैक कंपाइलर लिखें


13

एक प्रोग्राम लिखें जो एक ब्रेनफक प्रोग्राम लेता है और इसे निष्पादन योग्य मशीन कोड पर संकलित करता है। आप x86, x86_64, jvm (java bytecode) या armv6 को लक्षित कर सकते हैं और निम्नलिखित निष्पादन योग्य प्रारूपों में से एक का उपयोग कर सकते हैं: ELF, a.out, class file, exe, com। निष्पादन योग्य लिनक्स या विंडोज (या जावा पर या तो) में काम करना चाहिए।

न तो आपका कार्यक्रम और न ही उत्पन्न निष्पादन योग्य कोई बाहरी कार्यक्रम (जैसे कि कोई अन्य संकलक, कोडांतरक या दुभाषिया) चला सकता है।

सबसे छोटा कोड जीतता है।



कोई भी मौका आपके पास मशीन कोड के लिए कोई स्रोत है? यह मेरा पहला मशीन कोड गोल्फ अभ्यास होगा यदि आप किसी भी संसाधन का उपयोग करते हैं जो मैं एक उदाहरण के रूप में उपयोग कर सकता हूं?
वैलेस्ट

@ Eliseod'Annunzio मेरे पास कोई विशेष संसाधन नहीं हैं, लेकिन आम तौर पर आप अपनी पसंद के मंच के लिए असेंबली भाषा में देखकर शुरू कर सकते हैं , और कुछ उदाहरणों को इकट्ठा / अलग कर सकते हैं। Google आपका दोस्त है :) एक लूओंग समय पहले मैंने मशीन कोड गोल्फिंग प्रतियोगिताओं के एक जोड़े में भाग लिया था, मैंने बहुत अच्छा नहीं किया था लेकिन मुझे याद है कि हम डॉस के लिए कॉम प्रारूप का उपयोग कर रहे थे, क्योंकि इसमें कोई अतिरिक्त हेडर और सामान नहीं था, बस कोड। शायद अन्य लोग अधिक लिंक और सुझाव दे सकते हैं।
एडित्सू ने छोड़ दिया क्योंकि एसई ईवीआईएल

जवाबों:


5

सी, 866 783 बाइट्स

चूंकि मेरा कोड 32 बिट ईएलएफ निष्पादन योग्य है, इसलिए मैं यह वादा नहीं कर सकता कि यह हर सेटअप पर काम करेगा। मेरे कंप्यूटर पर सेगफ़ॉल्टिंग को रोकने के लिए निष्पादन योग्य प्राप्त करने के लिए पर्याप्त ट्वीकिंग हुई।

इसे चलाने की कोशिश कर रहे किसी के लिए:

$ uname --all
Linux 4.4.0-24-generic #43-Ubuntu SMP Wed Jun 8 19:27:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

स्ट्रेन से एक ब्रेनफुक प्रोग्राम पढ़ा जाता है और संकलित ईएलएफ को स्टडआउट के लिए लिखा जाता है।

#define P *(t++)
#define C case
#define B break
char a[30000],b[65535],f,*t=b;*c[100];**d=c;main(g){P=188;t+=4;while((f=getchar())!=-1)switch(f){C'>':P=68;B;C'<':P=76;B;C'+':P=254;P=4;P=36;B;C'-':P=254;P=12;P=36;B;C'.':P=187;t+=4;P=137;P=225;P=186;P=1;t+=3;P=184;P=4;t+=3;P=205;P=128;B;C',':P=187;P=1;t+=3;P=137;P=225;P=186;P=1;t+=3;P=184;P=3;t+=3;P=205;P=128;B;C'[':P=138;P=4;P=36;P=133;P=192;P=15;P=132;t+=4;*d=(int*)t-1;d++;B;C']':P=138;P=4;P=36;P=133;P=192;P=15;P=133;t+=4;d--;g=((char*)(*d+1))-t;*((int*)t-1)=g;**d=-g;B;}P=184;P=1;t+=3;P=187;t+=4;P=205;P=128;*(int*)(b+1)=0x8048054+t-b;long long z[]={282579962709375,0,4295163906,223472812116,0,4297064500,4294967296,577727389698621440,36412867248128,30064779550,140720308490240};write(1,&z,84);write(1,b,t-b);write(1,a,30000);}

Ungolfed

कोड के अनगुल्ड संस्करण में, आप एक बेहतर विचार प्राप्त कर सकते हैं कि क्या चल रहा है। गोल्फ कोड के अंत में वर्ण सरणी अनलॉल्फ कोड में ईएलएफ और प्रोग्राम हेडर का एन्कोडिंग है। यह कोड यह भी दर्शाता है कि प्रत्येक ब्रेनफक निर्देश को बाइटकोड में कैसे अनुवादित किया जाता है।

#include <linux/elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>

#define MAX_BIN_LEN 65535
#define MAX_JUMPS 100

unsigned int org = 0x08048000;



unsigned char move_right[] = {0x44};                              /*inc   esp         */

unsigned char move_left[]  = {0x4c};                              /*dec   esp         */

unsigned char inc_cell[]   = {0xfe,0x04,0x24};                    /*inc   [esp]       */

unsigned char dec_cell[]   = {0xfe,0x0c,0x24};                    /*dec   [esp]       */

unsigned char read_char[]  = {0xbb,0x00,0x00,0x00,0x00,           /*mov   ebx,  0     */
                              0x89,0xe1,                          /*mov   ecx,  esp   */
                              0xba,0x01,0x00,0x00,0x00,           /*mov   edx,  1     */
                              0xb8,0x03,0x00,0x00,0x00,           /*mov   eax,  3     */
                              0xcd,0x80};                         /*int   0x80        */

unsigned char print_char[] = {0xbb,0x01,0x00,0x00,0x00,           /*mov   ebx,  1     */
                              0x89,0xe1,                          /*mov   ecx,  esp   */
                              0xba,0x01,0x00,0x00,0x00,           /*mov   edx,  1     */
                              0xb8,0x04,0x00,0x00,0x00,           /*mov   eax,  4     */
                              0xcd,0x80};                         /*int   0x80        */


unsigned char loop_start[] = {0x8a,0x04,0x24,                     /*mov   eax,  [esp] */
                              0x85,0xc0,                          /*test  eax,  eax   */
                              0x0f,0x84,0x00,0x00,0x00,0x00};     /*je    int32_t     */

unsigned char loop_end[]   = {0x8a,0x04,0x24,                     /*mov   eax,  [esp] */
                              0x85,0xc0,                          /*test  eax,  eax   */
                              0x0f,0x85,0x00,0x00,0x00,0x00};     /*jne   int32_t     */

unsigned char call_exit[]  = {0xb8,0x01,0x00,0x00,0x00,           /*mov   eax,  1     */
                              0xbb,0x00,0x00,0x00,0x00,           /*mov   ebx,  0     */
                              0xcd,0x80};                         /*int   0x80        */
unsigned char prelude[]    = {0xbc,0x00,0x00,0x00,0x00};          /*mov   esp, int32_t*/

unsigned char tape[100];

int main(){
    unsigned char text[MAX_BIN_LEN];
    unsigned char *txt_ptr = text;

    int32_t *loop_jmps[MAX_JUMPS];
    int32_t **loop_jmps_ptr = loop_jmps;

    Elf32_Off entry;

    entry = org + sizeof(Elf32_Ehdr) + 1 * sizeof(Elf32_Phdr);

    memcpy(txt_ptr,prelude,sizeof(prelude));
    txt_ptr += sizeof(prelude);
    char input;
    while((input = getchar()) != -1){
        switch(input){
            case '>':
                memcpy(txt_ptr,move_right,sizeof(move_right));
                txt_ptr += sizeof(move_right);
                break;
            case '<':
                memcpy(txt_ptr,move_left,sizeof(move_left));
                txt_ptr += sizeof(move_left);
                break;
            case '+':
                memcpy(txt_ptr,inc_cell,sizeof(inc_cell));
                txt_ptr += sizeof(inc_cell);
                break;
            case '-':
                memcpy(txt_ptr,dec_cell,sizeof(dec_cell));
                txt_ptr += sizeof(dec_cell);
                break;
            case '.':
                memcpy(txt_ptr,print_char,sizeof(print_char));
                txt_ptr += sizeof(print_char);
                break;
            case ',':
                memcpy(txt_ptr,read_char,sizeof(read_char));
                txt_ptr += sizeof(read_char);
                break;
            case '[':
                memcpy(txt_ptr,loop_start,sizeof(loop_start));
                txt_ptr += sizeof(loop_start);
                *loop_jmps_ptr = (int32_t*) txt_ptr - 1;
                loop_jmps_ptr++;
                break;
            case ']':
                memcpy(txt_ptr,loop_end,sizeof(loop_end));
                txt_ptr += sizeof(loop_end);
                loop_jmps_ptr--;
                int32_t offset = ((unsigned char*) (*loop_jmps_ptr + 1)) - txt_ptr;
                *((int32_t*)txt_ptr - 1) = offset;
                **loop_jmps_ptr = -offset;
                break;
        }
    }

    memcpy(txt_ptr,call_exit,sizeof(call_exit));
    txt_ptr += sizeof(call_exit);

    *(int32_t*)(text + 1) = entry + (txt_ptr - text);


    Elf32_Ehdr ehdr = {
        {0x7F,'E','L','F',ELFCLASS32,ELFDATA2LSB,EV_CURRENT,0,0,0,0,0,0,0,0,0},
        ET_EXEC,
        EM_386,
        EV_CURRENT,
        entry,
        sizeof(Elf32_Ehdr),
        0,
        0,
        sizeof(Elf32_Ehdr),
        sizeof(Elf32_Phdr),
        1,
        0,
        0,
        SHN_UNDEF,
    };

    Elf32_Phdr phdr = {
        PT_LOAD,
        0,
        org,
        org,
        sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) + (txt_ptr - text),
        sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) + (txt_ptr - text),
        PF_R | PF_X | PF_W,
        0x1000,
    };

    int out = open("a.out",O_CREAT|O_TRUNC|O_WRONLY,S_IRWXU);
    write(out,&ehdr,sizeof(Elf32_Ehdr));
    write(out,&phdr,sizeof(Elf32_Phdr));

    write(out,text,txt_ptr-text);
    write(out,tape,sizeof(tape));
    close(out);
}

सेल्फ मॉडिफ़ाइंग ब्रेनफ़क

बाइट्स को बचाने के लिए, मेरे संकलक के लिए टेप को किसी .bssखंड या उस जैसे कुछ भी फैंसी में आवंटित नहीं किया गया है। इसके बजाय, ब्रेनफक प्रोग्राम के संकलित बाइट कोड के बाद टेप को सीधे लिखे गए 30,000 नल बाइट्स हैं। यह जानने के बाद, और मेरे संकलक द्वारा बाइट कोड क्या है के बारे में पता होने का मतलब है कि आप रनटाइम पर बाइट कोड उत्पन्न या संशोधित कर सकते हैं। इस 'फीचर' का एक सरल चित्रण एक ब्रेनफक प्रोग्राम है जो अपना स्वयं का निकास मान सेट करता है।

 <<<<<<+ 

प्रोग्राम टेप के बाएं किनारे को बाइट कोड में इस बिंदु पर जाता है कि बाहर निकलने का कोड सामान्य रूप से 0. सेट है। इस बाइट को बढ़ाते हुए एक्ज़िट कोड को 0 के बजाय 1 पर सेट करने का कारण बनता है जब प्रोग्राम अंततः बाहर निकलता है। दृढ़ता के साथ, इसका उपयोग ब्रेनफक में सिस्टम स्तर की प्रोग्रामिंग करने के लिए किया जा सकता है।


अच्छा; आपके कोड में वास्तव में 865 बाइट्स हैं (आपको फ़ाइल के अंत में एक नई पंक्ति की आवश्यकता नहीं है)। इसके अलावा, आप चार चर घोषणाओं को मर्ज कर सकते हैं। मुझे आश्चर्य है कि अगर वह लंबी सरणी भी संकुचित हो सकती है, क्योंकि इसमें कई शून्य हैं।
एडित्सू ने छोड़ दिया क्योंकि SE

@aditsu मैं हेडर सरणी के लिए कुछ बेहतर एन्कोडिंग खोजने पर काम कर रहा हूं। C किसी भी कम्प्रेशन लाइब्रेरियों में निर्मित नहीं होता है, इसलिए ज़िप करना प्रश्न से बाहर लगता है। सबसे अच्छी बात यह है कि मैं long long intइसके बजाय एक सरणी के रूप में एन्कोडिंग है char। निश्चित रूप से मेरे लिए मेरी कुछ चर घोषणाओं को पूरा करने की गुंजाइश है। मैं देखूंगा कि मैं वहां कितना पहुंच सकता हूं और अपना जवाब अपडेट कर सकता हूं।
आख-मोपर्क 13

मैं RLE के कुछ रूप के बारे में सोच रहा था, लेकिन .. जो कुछ भी काम करता है :)
विज्ञापन छोड़ दिया क्योंकि SE EVIL

आप 4 बाइट्स के लिए 4 घोषणापत्र (यह gcc के साथ काम करता है, कम से कम) के लिए '577727389698621440' को '4105 * pow (2,47)' से बदल सकते हैं (~ कम से कम काम करता है) ~
Maliao49

13

पायथन, 1974 चार्ट

import sys
s='\x11\x75\x30\xbc\x08\x4b\x03\x3c'
k=[]
for c in sys.stdin.read():
 if'>'==c:s+='\x84\x01\x01'
 if'<'==c:s+='\x84\x01\xff'
 if'+'==c:s+='\x2a\x1b\x5c\x33\x04\x60\x91\x54'
 if'-'==c:s+='\x2a\x1b\x5c\x33\x04\x64\x91\x54'
 if'['==c:k+=[len(s)];s+='\x2a\x1b\x33\x99\x00\x00'
 if']'==c:a=k[-1];k=k[:-1];d=len(s)-a;s=s[:a+4]+'%c%c'%(d>>8,d&255)+s[a+6:]+'\xa7%c%c'%(-d>>8&255,-d&255)
 if','==c:s+='\x2a\x1b\xb2\x00\x02\xb6\x00\x03\x91\x54'
 if'.'==c:s+='\xb2\x00\x04\x59\x2a\x1b\x33\xb6\x00\x05\xb6\x00\x06'
s+='\xb1'
n=len(s)
sys.stdout.write('\xca\xfe\xba\xbe\x00\x03\x00-\x00+\n\x00\x08\x00\x13\t\x00\x14\x00\x15\n\x00\x16\x00\x17\t\x00\x14\x00\x18\n\x00\x19\x00\x1a\n\x00\x19\x00\x1b\x07\x00\x1c\x07\x00\x1d\x01\x00\x06<init>\x01\x00\x03()V\x01\x00\x04Code\x01\x00\x0fLineNumberTable\x01\x00\x04main\x01\x00\x16([Ljava/lang/String;)V\x01\x00\nExceptions\x07\x00\x1e\x01\x00\nSourceFile\x01\x00\x06B.java\x0c\x00\t\x00\n\x07\x00\x1f\x0c\x00 \x00!\x07\x00"\x0c\x00#\x00$\x0c\x00%\x00&\x07\x00\'\x0c\x00(\x00)\x0c\x00*\x00\n\x01\x00\x01B\x01\x00\x10java/lang/Object\x01\x00\x13java/io/IOException\x01\x00\x10java/lang/System\x01\x00\x02in\x01\x00\x15Ljava/io/InputStream;\x01\x00\x13java/io/InputStream\x01\x00\x04read\x01\x00\x03()I\x01\x00\x03out\x01\x00\x15Ljava/io/PrintStream;\x01\x00\x13java/io/PrintStream\x01\x00\x05write\x01\x00\x04(I)V\x01\x00\x05flush\x00!\x00\x07\x00\x08\x00\x00\x00\x00\x00\x02\x00\x01\x00\t\x00\n\x00\x01\x00\x0b\x00\x00\x00\x1d\x00\x01\x00\x01\x00\x00\x00\x05*\xb7\x00\x01\xb1\x00\x00\x00\x01\x00\x0c\x00\x00\x00\x06\x00\x01\x00\x00\x00\x03\x00\t\x00\r\x00\x0e\x00\x02\x00\x0b\x00\x00'+'%c%c'%((n+60)>>8,(n+60)&255)+'\x00\x04\x00\x03\x00\x00'+'%c%c'%(n>>8,n&255)+s+'\x00\x00\x00\x01\x00\x0c\x00\x00\x00*\x00\n\x00\x00\x00\x05\x00\x06\x00\x06\x00\x08\x00\t\x00\x0b\x00\x0b\x00\x13\x00\r\x00\x1d\x00\x0f\x00&\x00\x11\x00,\x00\x12\x002\x00\x14\x008\x00\x15\x00\x0f\x00\x00\x00\x04\x00\x01\x00\x10\x00\x01\x00\x11\x00\x00\x00\x02\x00\x12')

नीचे java bytecode के अनुवाद हैं। स्थानीय 0 एक बाइट सरणी है जो टेप का प्रतिनिधित्व करता है, स्थानीय 1 डेटा पॉइंटर है।

>  iinc 1,+1
<  iinc 1,-1
+  aload_0;iload_1;dup2;baload;iconst_1;iadd;i2b;bastore
-  aload_0;iload_1;dup2;baload;iconst_1;isub;i2b;bastore
[  aload_0;iload_1;baload;ifeq xx xx
]  goto xx xx
,  aload_0;iload_1;getstatic #2;invokevirtual #3;i2b;bastore
.  getstatic #4;dup;aload_0;iload_1;baload;invokevirtual #5;invokevirtual #6

xx xxऑफसेट मिलान ब्रैकेट तक पहुंचने के लिए कर रहे हैं। # 2 है System.in, # 3 है read(), # 4 है System.out, # 5 है write(), और # 6 है flush()

प्रस्तावना एक 30000 बाइट सरणी आवंटित करता है और टेप की स्थिति को 0 से प्रारंभ करता है।

अंत में विशाल आवरण एक डमी B.javaफ़ाइल को प्रत्येक ओपकोड (सही स्थिर तालिकाओं और अन्य कबाड़ की पीढ़ी उत्पन्न करने के लिए) के लिए कोड के साथ उत्पन्न किया गया था , फिर उस पर नाजुक सर्जरी का प्रदर्शन किया।

इसे वैसे ही चलाएं

python bfc.py < input.b > B.class
java B

के साथ जुदा

javap -c B

मुझे यकीन है कि यह कुछ और गोल्फ हो सकता है। मुझे खुशी है कि यह काम करता है ...


1
Sys आयात * से उपयोग करें और फिर दोनों sys को हटाकर 2 वर्णों को बंद करें।
टिमटेक

2
आप उस बाइनरी डेटा को एनकोड करने के लिए बेस 64 का उपयोग कर सकते हैं और कुछ बाइट्स से दाढ़ी बना सकते हैं
tecywiz121

3

16-बिट x86 असेंबली कोड, 104 बाइट्स

यह कोड 2014 का है, लेकिन मुझे अभी यह कार्य मिला है।

;compliant version, non-commands are ignored, but 104 bytes long

[bits 16]  
[org 0x100]  
; assume bp=091e used  
; assume di=fffe  
; assume si=0100  
; assume dx=cs (see here)  
; assume cx=00ff  
; assume bx=0000  
; assume ax=0000 used (ah)  
; assume sp=fffe  
start:
        mov al, code_nothing - start  
code_start:
        mov ch, 0x7f ; allow bigger programs  
        mov bx, cx  
        mov di, cx  
        rep stosb  
        mov bp, find_right + start - code_start ;cache loop head for smaller compiled programs  
        jmp code_start_end  
find_right:
        pop si  
        dec si  
        dec si ;point to loop head  
        cmp [bx], cl  
        jne loop_right_end  
loop_right:
        lodsb  
        cmp al, 0xD5 ; the "bp" part of "call bp" (because 0xFF is not unique, watch for additional '[')  
        jne loop_left  
        inc cx  
loop_left:
        cmp al, 0xC3 ; ret (watch for ']')  
        jne loop_right  
        loop loop_right ;all brackets matched when cx==0  
        db 0x3c ;cmp al, xx (mask push)  
loop_right_end:
        push si  
        lodsw ; skip "call" or dummy "dec" instruction, depending on context  
        push si  
code_sqright:
        ret  
code_dec:
        dec byte [bx]  
code_start_end:
        db '$' ;end DOS string, also "and al, xx"  
code_inc:
        inc byte [bx]  
        db '$'  
code_right:
        inc bx ;al -> 2  
code_nothing:
        db '$'  
code_left:
        dec bx  
        db '$'  
code_sqleft:
        call bp  
        db '$'  
; create lookup table  
real_start:
        inc byte [bx+'<'] ;point to code_left  
        dec byte [bx+'>'] ;point to code_right  
        mov byte [bx+'['], code_sqleft - start  
        mov byte [bx+']'], code_sqright - start  
        lea sp, [bx+45+2] ;'+' + 4 (2b='+', 2c=',', 2d='-', 2e='.')  
        push (code_dec - start) + (code_dot - start) * 256  
        push (code_inc - start) + (code_comma - start) * 256  
pre_write:
        mov ah, code_start >> 8  
        xchg dx, ax  
; write  
        mov ah, 9  
        int 0x21  
; read  
code_comma:
        mov dl, 0xff  
        db 0x3d ; cmp ax, xxxx (mask mov)  
code_dot:
        mov dl, [bx]  
        mov ah, 6  
        int 0x21  
        mov [bx], al  
        db '$'  
        db 0xff ; parameter for '$', doubles as test for zero  
; switch  
        xlatb  
        jne pre_write  
  ; next two lines can also be removed  
  ; if the program ends with extra ']'  
  ; and then we are at 100 bytes... :-)  
the_end:
        mov dl, 0xC3  
        int 0x21  
        int 0x20 

क्या आप सुनिश्चित हैं कि यह एक दुभाषिया नहीं है ?
एडित्सो ने छोड़ दिया क्योंकि एसई ईवीआईएल

1
नहीं, यह बिल्कुल एक संकलक है। "bf.com <hello.bf> out.com", फिर out.com निष्पादन योग्य होगा।
पीटर फेर्री

1
ठीक है, क्या आप यह समझा सकते हैं कि इसे कैसे संकलित किया जाए और इसमें क्या ओएस काम करता है? मैं इसे अभी तक नहीं चला सका हूं।
aditsu छोड़ दिया क्योंकि SE

YASM के साथ इकट्ठा, MS-DOS में (DOSBox के माध्यम से) ठीक है।
पीटर फेर

1
'<' और '>' से बचने की जरूरत है। वैसे भी, 32-बिट विंडोज में एक डॉस कंसोल है जहां चलेगा, और "कॉम" स्पष्ट रूप से अनुमत प्रारूपों में से एक है।
पीटर फैरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.