En Küçük Bayt Kodu Yorumlayıcı / VM


17

Büyük Afiş - JIT Derlendi (Düşük iyidir)

  1. es1024 - 81.2 puan (çalışan bir derleyici dahil!)
  2. Kieth Randall - 116 puan
  3. Ell - 121 puan

Büyük Afiş - Yorumlandı (Düşük iyidir)

  1. Martin Büttner - 706654 puan (yaklaşık 2 saat).
  2. criptych - 30379 puan (97 saniye)

Göreviniz, kabul etmeyi seçerseniz, mümkün olan en küçük bayt kodu yorumlayıcısını / VM'yi yazmaktır. VM / yorumlayıcı, aşağıda belirtilen dille küçük bir CISC mimarisi kullanır (işlemler boyut olarak değişebilir). Tamamlandığında, doğru çıktının yazdırıldığını kanıtlamak için 3 CPU kaydının değerini yazdırmanız gerekir (3,126,900,366).

Derleyici

Kendi testlerinizi yapmak istiyorsanız, aşağıda bir derleyici yayınlanır. Testlerinizi cevabınızla birlikte göndermekten çekinmeyin.

"VM" Özellikler

VM'de 3 adet 32 ​​bit imzasız integral kaydı vardır: R0, R1, R2. Onaltılık biçimde 0x00, 0x01 ve 0x02 olarak temsil edilirler.

Aşağıdaki işlemler desteklenmelidir:

Biçim [ad] [... işlenenler ...], [onaltılık op kodu] [... işlenenler tekrarlandı ...]

  • YÜKLE [kayıt] [4 bayt değer], 0x00 [kayıt] [4 bayt değer]
  • PUSH [kayıt], 0x02 [kayıt]
  • POP [kayıt], 0x03 [kayıt]
  • ADD [kayıt, 1 bayt] [kayıt, 1 bayt], 0x04 [kayıt] [kayıt]
  • SUB [kayıt, 1 bayt] [kayıt, 1 bayt], 0x05 [kayıt] [kayıt]
  • MUL [kayıt, 1 bayt] [kayıt, 1 bayt], 0x06 [kayıt] [kayıt]
  • DIV [kayıt, 1 bayt] [kayıt, 1 bayt], 0x07 [kayıt] [kayıt]
  • JMP [kod satırı, 4 bayt], 0x08 [4 bayt kod satırı numarası]
  • CMP [kayıt, 1 bayt] [kayıt, 1 bayt], 0x09 [kayıt] [kayıt]
  • BRANCHLT [kod satırı, 4 bayt], 0x0a [4 bayt kod satırı numarası]

Bazı notlar:

  • Yukarıdaki matematik işlemleri, çıktıyı ilk kayda yerleştirerek 2 kaydın değerlerini toplar.
  • Karşılaştırma operatörü olan CMP, 2 yazmaçın değerlerini karşılaştırmalı ve çıktıyı, şube talimatlarında ileride kullanılmak üzere bazı dahili bayraklarda (uygulamaya özel olabilir) depolamalıdır.
  • BRANCH CMP'den önce çağrılırsa, BRANCHEQ çağrılmadıkça "VM" dallanmamalıdır.
  • PUSH / POP şaşırtıcı bir şekilde yığından sayıları itin veya pop.
  • Jump ve Branch operatörleri, ikili bir adrese değil, belirli bir işleme (kod satırı) atlar.
  • Şube işlemleri karşılaştırmayı yapmaz. Aksine, yürütmek için çıktıyı son karşılaştırmadan alırlar.
  • Şube ve Jump işleçleri sıfır tabanlı bir satır numarası dizinleme sistemi kullanır. (Örneğin, JMP 0 ilk satıra atlar)
  • Tüm işlemler sıfıra taşan ve tamsayı taşmasına istisna atmayan imzasız sayılar üzerinde gerçekleştirilmelidir.
  • Sıfıra bölmeye izin verilmez ve bu nedenle programın davranışı tanımlanmaz. Şunları yapabilirsiniz (örneğin) ...
    • Programın çökmesi.
    • VM'nin yürütülmesini sonlandırın ve geçerli durumuna döndürün.
    • "ERR: Bölme 0" mesajını göster.
  • Programın sonlandırılması, talimat göstergesinin programın sonuna geldiği zaman tanımlanır (boş olmayan bir program olduğu varsayılabilir).

Çıktı Çıktı tam olarak bu olmalıdır (yeni satırlar dahil)

R0 3126900366
R1 0
R2 10000    

Puanlar Puanlar aşağıdaki formüle göre hesaplanır:Number Of Characters * (Seconds Needed To Run / 2)

Farklı zamanlara neden olan donanım farklılıklarından kaçınmak için, her test ubuntu sunucusunda veya Windows 8'de bilgisayarımda (i5-4210u, 8GB ram) çalıştırılacaktır, bu nedenle yalnızca Dual G5'te derlenen bazı deli-egzotik çalışma zamanlarını kullanmamaya çalışın Tam 762,66 mb boş RAM ile Mac Pro.

Özel bir çalışma zamanı / dil kullanıyorsanız, lütfen bunun için bir bağlantı gönderin.

Test programı

Fikir buradan geldi , bu yüzden programlarının biraz değiştirilmiş bir sürümünü kullanacağız.

Program için doğru çıktı: 3.126.900.366

C dilinde:

int s, i, j;
for (s = 0, i = 0; i < 10000; i++) {
    for (j = 0; j < 10000; j++)
        s += (i * j) / 3;
}

Kodda: [R0, s'yi temsil eder, R1, j, R2, i]

LOAD R0 0
LOAD R2 0 <--outer loop value
LOAD R1 0 <--inner loop value
     --Begin inner loop--
PUSH R1 <--push inner loop value to the stack
MUL R1 R2 <--(i*j)
PUSH R2
LOAD R2 3
DIV R1 R2 <-- / 3
POP R2
ADD R0 R1 <-- s+=
POP R1
PUSH R2 
LOAD R2 1
ADD R1 R2 <--j++
POP R2
PUSH R2
LOAD R2 10000
CMP R1 R2 <-- j < 10000
POP R2
BRANCHLT 3 <--Go back to beginning inner loop
--Drop To outer loop--
LOAD R1 1
ADD R2 R1 <--i++
LOAD R1 10000
CMP R2 R1 <-- i < 10000
LOAD R1 0 <--Reset inner loop
BRANCHLT 2

İkili / onaltılı olarak:

0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x02 0x00 0x00 0x00 0x00
0x00 0x01 0x00 0x00 0x00 0x00
0x02 0x01
0x06 0x01 0x02
0x02 0x02
0x00 0x02 0x00 0x00 0x00 0x03
0x07 0x01 0x02
0x03 0x02
0x04 0x00 0x01
0x03 0x01
0x02 0x02
0x00 0x02 0x00 0x00 0x00 0x01
0x04 0x01 0x02
0x03 0x02
0x02 0x02
0x00 0x02 0x00 0x00 0x27 0x10
0x09 0x01 0x02
0x03 0x02
0x0a 0x00 0x00 0x00 0x03
0x00 0x01 0x00 0x00 0x00 0x01
0x04 0x02 0x01
0x00 0x01 0x00 0x00 0x27 0x10
0x09 0x02 0x01
0x00 0x01 0x00 0x00 0x00 0x00
0x0a 0x00 0x00 0x00 0x02

Bonus Puanlar (Efektler çarpımsal olarak uygulanır) Örneğin, eğer üçü için de hak kazanırsanız, ((karakterler * 0.50) * 0.75) * 0.90

  • Tercüman aslında bir JIT derleyicisi ise% 50 azalma
  • Herhangi bir döngü açma / anlamlı optimizasyon uygularsa% 25 azalma.
  • VM'yi aşağıdakilerle genişletirseniz% 10 azalma
    • BRANCHEQ [kod satırı, 4 bayt] (Eşitse şube - opcode 0x0b)
    • BRANCHGT [kod satırı, 4 bayt] (Şundan büyükse şube - opcode 0x0c)
    • BRANCHNE [kod satırı, 4 bayt] (Eşit değilse şube - opcode 0x0d)
    • RLOAD [register 1] [register 2] (kayıt 2 değerini kayıt 1 - opcode 0x01'e taşıyın).

İzin verilmeyen

  • Test vakasının programa hazırlanması yasaktır. Bayt kodunu STDIN'den veya bir dosyadan kabul etmelisiniz (Hangisi önemli değil).
  • Programı çalıştırmadan çıktıyı iade etme.
  • VM gereksinimini aldatmayı düşünebileceğiniz başka herhangi bir yol.

Neden izin verilmediğini söylediğiniz şeyleri caydırmak için birkaç test programı daha eklemiyorsunuz? Bir VM ise, bayt kodu belirtiminde yazılmış herhangi bir şeyi çalıştırabilmelidir, değil mi?
Kasran

Bunu bu gece yapmaya çalışacağım. Derleyiciyi şu anda yazıyorum.
Renkli Tek Renkli


1
CMPDaha küçük veya eşitlik kontrolü var mı ? Ve sonucuna ne olur?
es1024

1
MULve DIVayrıca daha az belirtiliyor. İmzalanmalı veya imzalanmamalı mı? Çarpma taşması durumunda ne olur?
feersum

Yanıtlar:


8

C, 752 (bayrakları tanımlamak için 589 + 163) * 0.5 (JIT) * 0.9 (uzantılar) * (0.75 optimizasyon) * (0.64 saniye / 2) = 81.216

C[S],J[S],i,j,k,y,c,X,Y,Z;char*R,a,b[9];main(x){R=mmap(0,S,6,34,-1,0);N=85;while(scanf("%c%s%*[ R]%d%*[ R]%d",&a,b,&x,&y)&&~getchar())a-=65,a-1?a-15?a-9?a?a-2?a-3?a-11?a-12?a-17?(N=41,v):(N=137,v):(N=137,u,N=247,g(H,4),N=139,u):(y?N=189+x,s(y):(N=51,g(G,G))):(N=137,u,N=247,g(H,6),N=139,u):(N=57,v,s(0xFC8A9F),--j):(N=1,v):(N=233,J[k++]=i,s(x)):b[1]-80?N=85+x:(N=93+x):(c=b[5],s(0x0F9EE78A),N=(c-69?c-71?c-76?1:8:11:0)+132,J[k++]=i,s(x)),C[++i]=j;U(E8,X)U(F0,Y)U(F8,Z)s(50013);i=j;while(k--)j=C[J[k]]+1,R[j-1]-233&&(j+=4),s(C[*(int*)(R+j)]-j-4);((int(*)())R)();printf("%u %u %u\n",X,Y,Z);}

Kodu alır (LOAD R0 vb.), İzleyen karakterler, tek boşluk, ortada boş satır yok, yorum yok, vb.

Bu daha sonra 80386 bayt koduna dönüştürülür ve yürütülür.

0Bir sicile yükleme xor, sicil yerine sicil ile movgirilir.0 , oluşturulan bayt kodunda üç bayt daha kısa olan ve çok az daha hızlı olabilen sicile girmek girilmesi .

Şununla derleyin:

gcc -m32 -D"g(a,b)=(N=192|b<<3|a)"-D"s(b)=(*(int*)(R+j)=b,j+=4)"-DN=R[j++]-D"G=((x+1)|4)"
-D"H=((y+1)|4)"-DS=9999-D"u=g(0,G)"-D"v=g(G,H)"-D"U(b,c)=s(0xA3##b##89),--j,s(&c);"
bytecode.c -o bytecode

POSIX uyumlu işletim sistemi gereklidir.

Giriş STDIN'den okunur ( ./bytecode < filebir dosyadan akış yapmak için kullanın ).

Test programı için sonuç bayt kodu:

; start
 0:   55                      push   %ebp
; LOAD R0 0
 1:   33 ed                   xor    %ebp,%ebp
; LOAD R2 0
 3:   33 ff                   xor    %edi,%edi
; LOAD R1 0
 5:   33 f6                   xor    %esi,%esi
; PUSH $1
 7:   56                      push   %esi
; MUL R1 R2
 8:   89 f0                   mov    %esi,%eax
 a:   f7 e7                   mul    %edi
 c:   8b f0                   mov    %eax,%esi
; PUSH R2
 e:   57                      push   %edi
; LOAD R2 3
 f:   bf 03 00 00 00          mov    $0x3,%edi
; DIV R1 R2
14:   89 f0                   mov    %esi,%eax
16:   f7 f7                   div    %edi
18:   8b f0                   mov    %eax,%esi
; POP R2
1a:   5f                      pop    %edi
; ADD R0 R1
1b:   01 f5                   add    %esi,%ebp
; POP R1
1d:   5e                      pop    %esi
; PUSH R2
1e:   57                      push   %edi
; LOAD R2 1
1f:   bf 01 00 00 00          mov    $0x1,%edi
; ADD R1 R2
24:   01 fe                   add    %edi,%esi
; POP R2
26:   5f                      pop    %edi
; PUSH R2
27:   57                      push   %edi
; LOAD R2 10000
28:   bf 10 27 00 00          mov    $0x2710,%ed
; CMP R1 R2
2d:   39 fe                   cmp    %edi,%esi
2f:   9f                      lahf
30:   8a fc                   mov    %ah,%bh
; POP R2
32:   5f                      pop    %edi
; BRANCHLT 3
33:   8a e7                   mov    %bh,%ah
35:   9e                      sahf
36:   0f 8c cb ff ff ff       jl     0x7
; LOAD R1 1
3c:   be 01 00 00 00          mov    $0x1,%esi
; ADD R2 R1
41:   01 f7                   add    %esi,%edi
; LOAD R1 10000
43:   be 10 27 00 00          mov    $0x2710,%es
; CMP R2 R1
48:   39 f7                   cmp    %esi,%edi
4a:   9f                      lahf
4b:   8a fc                   mov    %ah,%bh
; LOAD R1 0
4d:   33 f6                   xor    %esi,%esi
; BRANCHLT 2
4f:   8a e7                   mov    %bh,%ah
51:   9e                      sahf
52:   0f 8c ad ff ff ff       jl     0x5
; copy R0 to X
58:   89 e8                   mov    %ebp,%eax
5a:   a3 28 5b 42 00          mov    %eax,0x425b
; copy R1 to Y
5f:   89 f0                   mov    %esi,%eax
61:   a3 38 55 44 00          mov    %eax,0x4455
; copy R2 to Z
66:   89 f8                   mov    %edi,%eax
68:   a3 40 55 44 00          mov    %eax,0x4455
; exit
6d:   5d                      pop    %ebp
6e:   c3                      ret

Ungolfed:

C[9999],J[9999],i,j,k,y,c,X,Y,Z;
char *R,a,b[9];
main(x){
    // 6 is PROC_WRITE|PROC_EXEC
    // 34 is MAP_ANON|MAP_PRIVATE
    R=mmap(0,'~~',6,34,-1,0);

    N=0x55;
    while(scanf("%c%s%*[ R]%d%*[ R]%d",&a,b,&x,&y)&&~getchar())
        a-=65,
        a-1? // B[RANCH**]
            a-15? // P[USH/OP]
                a-9? // J[MP]
                    a? // A[DD]
                        a-2? // C[MP]
                            a-3? // D[IV]
                                a-11? // L[OAD]
                                    a-12? // M[UL]
                                        a-17? // R[LOAD]
                                            // SUB
                                            (N=0x29,g(G,H))
                                        :(N=0x89,g(G,H))
                                    :(N=0x89,g(0,G),N=0xF7,g(H,4),N=0x8B,g(0,G))
                                :(y?N=0xBD+x,s(y):(N=0x33,g(G,G)))
                            :(N=0x89,g(0,G),N=0xF7,g(H,6),N=0x8B,g(0,G))
                        :(N=0x39,g(G,H),s(0xfc8a9f),--j)
                    :(N=0x1,g(G,H))
                :(N=0xE9,J[k++]=i,s(x))
            :b[1]-80? 
                N=0x55+x // PUSH
            :(N=0x5D+x) // POP
        :(c=b[5],s(0x0f9ee78a),N=(
        c-69? // EQ
            c-71? // GT
                c-76? // LT
                    1 // NE
                :8
            :11
        :0
        )+0x84,J[k++]=i,s(x)),
        C[++i]=j
        ;
    // transfer registers to X,Y,Z
    s(0xA3E889),--j,s(&X);
    s(0xA3F089),--j,s(&Y);
    s(0xA3F889),--j,s(&Z);

    // pop and ret
    s(0xC35D);

    i=j;
    // fix distances for jmp/branch**
    while(k--)
        j=C[J[k]]+1,R[j-1]-0xE9&&(j+=4),
        s(C[*(int*)(R+j)]-j-4);

    // call
    ((int(*)())R)();

    // output
    printf("%u %u %u\n",X,Y,Z);
}

Vay. Keşke derleyiciyi VM'ye dahil etmek için bir bonus eklemiş olsaydım.
Renkli Tek Renkli

15 çalıştırmada çalışma başına ortalama .67 saniye.
Renkli Tek Renkli

Xoring'in bir optimizasyon olduğuna katılmıyorum. Akıllı kod boyutu akıllıca olsa da, xoring, VM'nin performans özelliklerini değiştirmez (yanlışsam beni düzeltin). Optimizasyon ile kastettiğim, giriş kodundaki talimatları değiştirmek veya kaldırmak (örneğin yedek POP ... PUSH kaldırmak) veya bir satırda 2 talimat gerçekleştirmek kaydı yüklemek, böylece biri kaldırılabilir, vb.
Renkli Tek Renkli

EDIT: Aslında, bu bir optimizasyon: 15 koşu üzerinde çalışma başına 0.64 saniyeye düştü. Ben kodu kısaltarak (veya gereksiz bellek erişim kaldırır) önbellek thrashing veya bir şey önler sanırım?
Renkli Tek Renkli

@ColorfullyMonochrome Bazı mimariler, bir kaydın kendisine xoring ile sunulduğunda, aslında talimatı yürütmez, ancak sadece kaydı sıfırlar.
es1024

7

C, Puan = 854 bayt × (~ 0,8 sn / 2) × 0,5 [JIT] × 0,9 [Uzantılar = = 154 bayt sn

#define G getchar()
#define L for(i=0;i<3;++i)
#define N*(int*)
#define M(x)"P\x8a\xe7\x9e\xf"#x"    KL"
*T[1<<20],**t=T,*F[1<<20],**f=F,R[3],r[]={1,6,7};char*I[]={"L\xb8    GGJH","I\x8b\xc0HHGH","H\x50GG","H\x58GG","I\3\xc0HHGH","I\53\xc0HHGH","M\x8b\xc0\xf7\xe0\x8b\xc0IHLGJ","O\63\xd2\x8b\xc0\xf7\xf0\x8b\xc0IJNGL","L\xe9    KH","L\73\xc0\x9f\x8a\xfcHHGH",M(\x82),M(\x84),M(\x87),M(\x85)},C[1<<24],*c=C;main(i,o,l,g){N c=0xb7ec8b60;c[4]=70;c+=5;while((o=G)>=0){char*s=I[o];l=*s-'G';memcpy(c,s+1,l);for(s+=l+1;o=*s++;){o-='G';if(o<3){g=r[G];c[*s++-'G']|=g<<3*(o&1);if(o>1)c[*s++-'G']|=g<<3;}else{if(o>3)*f++=c+*s-'G';for(i=4;i;--i)c[*s-'G'+i-1]=G;++s;}}*t++=c;c+=l;}*t=c;while(f>F)--f,**f=(int)T[**f]-(int)*f-4;L N&c[7*i]=0x5893e|r[i]<<19,N&c[3+7*i]=R+i;N&c[21]=0xc361e58b;mprotect((int)C>>12<<12,1<<24,7);((void(*)())C)();L printf("R%d %u\n",i,R[i]);}

gcc vm.c -ovm -m32 -wX86 POSIX uyumlu bir işletim sisteminde derleyin .
İle çalıştır ./vm < program, burada programbir ikili program dosyasıdır.


Hız için gidiyor. Program, giriş programının x86 makine koduna oldukça basit bir çevirisini gerçekleştirir ve gerisini CPU'nun yapmasını sağlar.

Örneğin, test programının çevirisi. ecx,esi Ve editekabül için R0, R1ve R2sırasıyla; bhdurum bayraklarını tutar; eaxve edxsıfırdan yazmaçlardır; çağrı yığını VM'nin yığınına karşılık gelir:

# Prologue
     0:   60                      pusha
     1:   8b ec                   mov    ebp,esp
     3:   b7 46                   mov    bh,0x46
# LOAD R0 0
     5:   b9 00 00 00 00          mov    ecx,0x0
# LOAD R2 0 <--outer loop value
     a:   bf 00 00 00 00          mov    edi,0x0
# LOAD R1 0 <--inner loop value
     f:   be 00 00 00 00          mov    esi,0x0
#      --Begin inner loop--
# PUSH R1 <--push inner loop value to the stack
    14:   56                      push   esi
# MUL R1 R2 <--(i*j)
    15:   8b c6                   mov    eax,esi
    15:   f7 e7                   mul    edi
    19:   8b f0                   mov    esi,eax
# PUSH R2
    1b:   57                      push   edi
# LOAD R2 3
    1c:   bf 03 00 00 00          mov    edi,0x3
# DIV R1 R2 <-- / 3
    21:   33 d2                   xor    edx,edx
    23:   8b c6                   mov    eax,esi
    25:   f7 f7                   div    edi
    27:   8b f0                   mov    esi,eax
# POP R2
    29:   5f                      pop    edi
# ADD R0 R1 <-- s+=
    2a:   03 ce                   add    ecx,esi
# POP R1
    2c:   5e                      pop    esi
# PUSH R2
    2d:   57                      push   edi
# LOAD R2 1
    2e:   bf 01 00 00 00          mov    edi,0x1
# ADD R1 R2 <--j++
    33:   03 f7                   add    esi,edi
# POP R2
    35:   5f                      pop    edi
# PUSH R2
    36:   57                      push   edi
# LOAD R2 10000
    37:   bf 10 27 00 00          mov    edi,0x2710
# CMP R1 R2 <-- j < 10000
    3c:   3b f7                   cmp    esi,edi
    3e:   9f                      lahf
    3f:   8a fc                   mov    bh,ah
# POP R2
    41:   5f                      pop    edi
# BRANCHLT 4 <--Go back to beginning inner loop
    42:   8a e7                   mov    ah,bh
    44:   9e                      sahf
    45:   0f 82 c9 ff ff ff       jb     0x14
# --Drop To outer loop--
# LOAD R1 1
    4b:   be 01 00 00 00          mov    esi,0x1
# ADD R2 R1 <--i++
    50:   03 fe                   add    edi,esi
# LOAD R1 10000
    52:   be 10 27 00 00          mov    esi,0x2710
# CMP R2 R1 <-- i < 10000
    57:   3b fe                   cmp    edi,esi
    59:   9f                      lahf
    5a:   8a fc                   mov    bh,ah
# LOAD R1 0 <--Reset inner loop
    5c:   be 00 00 00 00          mov    esi,0x0
# BRANCHLT 3
    61:   8a e7                   mov    ah,bh
    63:   9e                      sahf
    64:   0f 82 a5 ff ff ff       jb     0xf
# Epilogue
    6a:   3e 89 0d 60 ac 04 09    mov    DWORD PTR ds:0x904ac60,ecx
    71:   3e 89 35 64 ac 04 09    mov    DWORD PTR ds:0x904ac64,esi
    78:   3e 89 3d 68 ac 04 09    mov    DWORD PTR ds:0x904ac68,edi
    7f:   8b e5                   mov    esp,ebp
    81:   61                      popa
    82:   c3                      ret

Ungolfed


Vay canına ... benim JIT ~ 900 satır kod (c ++ ile yazılmış) idi ...
Rengarenk Monokrom

15 çalışma için çalışma başına ortalama 0,63 saniye.
Renkli Tek Renkli

2

CJam, 222 187 185 bayt * (çok yavaş / 2)

Sadece bir bayt kodu VM'sini CJam'de yazarak ne kadar kısa alabileceğimi görmek istedim. 200 bayttan azı oldukça iyi görünüyor. Yine de çok yavaş, çünkü CJam'ın kendisi yorumlanıyor. Test programını çalıştırmak uzun zaman alır.

304402480 6b:P;q:iD-);{(_P=@/(\L*@@+\}h;]:P;TTT]:R;{_Rf=~}:Q;{4G#%R@0=@t:R;}:O;{TP=("R\(\GG*bt:R;  ~R= R\~@t:R; Q+O Q4G#+-O Q*O Q/O ~(:T; Rf=~-:U; GG*bU0<{(:T}*;"S/=~T):TP,<}g3,{'R\_S\R=N}/

Çalıştırmak için bu sourceforge bağlantısından Java yorumlayıcısını indirin , kodu kaydedin vm.cjamve ile çalıştırın

java -jar cjam-0.6.2.jar vm.cjam

Program STDIN üzerindeki bayt kodunu bekler. İkili verileri bir programa aktarmanın bir yolunu bulamadım, PowerShell bir sondaki satır sonu ekleyerek ve dönüştürmek 0x0aiçin 0x0d 0x0agerçekten sinir bozucu. Kod D-);, toplam sayıya dahil etmediğim ( ) düzeltmek için 4 bayt içeriyor, çünkü programın gerçekten bytecode'un kendisini garip kodlanmış bazı sürümü yerine STDIN'de alması gerekiyorsa yapması gereken bir şey değil. . Birisi bunun için bir düzeltme biliyorsa, lütfen bana bildirin.

Hafifçe soluksuz:

304402480 6b:P; "Create lookup table for instruction sizes. Store in P.";
q:i             "Read program and convert bytes to integers.";
D-);            "Remove spurious carriage returns. This shouldn't be necessary.";
{(_P=@/(\L*@@+\}h;]:P; "Split into instructions. Store in P.";
"We'll use T for the instruction pointer as it's initialised to 0.";
"Likewise, we'll use U for the CMP flag.";
TTT]:R; "Store [0 0 0] in R for the registers.";
{_Rf=~}:Q; "Register lookup block.";
{4G#%R@0=@t:R;}:O; "Save in register block.";
{TP=("R\(\GG*bt:R;

~R=
R\~@t:R;
Q+O
Q4G#+-O
Q*O
Q/O
~(:T;
Rf=~-:U;
GG*bU0<{(:T}*;"N/=~T):TP,<}g "Run program.";
3,{'R\_S\R=N}/

Yarın uygun bir açıklama ekleyeceğim.

Kısacası, tüm kayıtları, komut göstergesini ve karşılaştırma bayrağını değişkenlerde saklıyorum, böylece CJam'ın yığınını VM'nin yığını olarak kullanmak için serbest tutabilirim.



1
20 yineleme için ortalama 15.279 saniye. - 15 test. Bu, test başına 2.12208333 saat anlamına gelir.
Renkli Tek Renkli

1

python / c ++, puan = 56.66

1435 karakter * .234 / 2 saniye * .5 [JIT] * .75 [Optimizasyon] * .90 [Ek talimatlar]

Girdi programını c ++ ile derler, üzerinde gcc çalıştırır, sonra sonucu çalıştırır. Çoğu zaman gcc içinde geçirilir.

Yaptığım bir optimizasyon, semantik olarak izin verilirse yığın işlemlerini açık değişkenlere indirmektir. Derlenmiş kodun yaklaşık 10 kat daha iyi çalışma süresine çok yardımcı olur (ortaya çıkan ikili dosyayı çalıştırmak için yaklaşık .056 sn). Gcc'nin ne yaptığından emin değilim, bu iyileşmeyi sağlar, ama iyi.

import sys,os
x=map(ord,sys.stdin.read())
w=lambda x:(x[0]<<24)+(x[1]<<16)+(x[2]<<8)+x[3]
I=[]
while x:
 if x[0]==0:f='r%d=%d'%(x[1],w(x[2:]));n=6
 if x[0]==1:f='r%d=r%d'%(x[1],x[2]);n=3
 if x[0]==2:f='P%d'%x[1];n=2
 if x[0]==3:f='O%d'%x[1];n=2
 if x[0]==4:f='r%d=r%d+r%d'%(x[1],x[1],x[2]);n=3
 if x[0]==5:f='r%d=r%d-r%d'%(x[1],x[1],x[2]);n=3
 if x[0]==6:f='r%d=r%d*r%d'%(x[1],x[1],x[2]);n=3
 if x[0]==7:f='r%d=r%d/r%d'%(x[1],x[1],x[2]);n=3
 if x[0]==8:f='goto L%d'%w(x[1:]);n=5
 if x[0]==9:f='a=r%d;b=r%d'%(x[1],x[2]);n=3
 if x[0]==10:f='if(a<b)goto L%d'%w(x[1:]);n=5
 if x[0]==11:f='if(a==b)goto L%d'%w(x[1:]);n=5
 if x[0]==12:f='if(a>b)goto L%d'%w(x[1:]);n=5
 if x[0]==13:f='if(a!=b)goto L%d'%w(x[1:]);n=5
 I+=[f];x=x[n:]
D=[]
d=0
for f in I:D+=[d];d+='P'==f[0];d-='O'==f[0]
J=[]
if all(d==D[int(f[f.find('L')+1:])]for f,d in zip(I,D)if f[0]in'gi'):
 H='uint32_t '+','.join('s%d'%i for i in range(max(D)))+';'
 for f,d in zip(I,D):
  if f[0]=='P':f='s%d=r'%d+f[1:]
  if f[0]=='O':f='r'+f[1:]+'=s%d'%(d-1)
  J+=[f]
else:
 H='std::vector<uint32_t>s;'
 for f,d in zip(I,D):
  if f[0]=='P':f='s.push_back(r'+f[1:]+')'
  if f[0]=='O':f='r'+f[1:]+'=s.back();s.pop_back()'
  J+=[f]
P='#include<vector>\n#include<cstdint>\nuint32_t r0,r1,r2,a,b;'+H+'int main(){'
for i,f in enumerate(J):P+='L%d:'%i+f+';'
P+=r'printf("R0 %u\nR1 %u\nR2 %u\n",r0,r1,r2);}'
c=open("t.cc", "w")
c.write(P)
c.close()
os.system("g++ -O1 t.cc")
os.system("./a.out")

Kesinlikle biraz daha golf olabilir.


15 çalıştırmada çalışma başına ortalama .477 saniye.
Renkli Tek Renkli

1

Lua 5.2 (veya LuaJIT), 740 bayt

İlk deneyin, sadece minimal golf. Bu sürüm (en azından test programında) çalışır ve ekstra opcodları uygular, ancak imzasız matematik gereksinimini karşılamaz ve özellikle hızlı değildir. Bir bonus olarak, bir VM'de çalışan bir VM'dir ve yorumlanabileceği (PUC-Lua ile çalıştırılabilir) veya bir çeşit JIT (LuaJIT ile çalıştır; hala yorumlanır, ancak yorumlayıcı şimdi yazılabilir) JITted).

EDIT: Daha iyi golf, hala büyük.

EDIT: Büyük bir hata düzeltildi ve şimdi aritmetiği unsigned longaralıkla kısıtlıyor . Her nasılsa, boyutun kontrolden çıkmasını engellemeyi başardı, ancak yine de yanlış cevap veriyor.

EDIT: Sonuç çıkıyor, sonuç doğruydu ama çıktı değildi. İle baskı hesabına geçildi %uyerine %dve tüm iyi. Ayrıca, boyutu ve hızı biraz artırmak için değişkenler için tablo tabanlı kayıtlar da devre dışı bırakıldı .

EDIT: Lua 5.2 gotodeyimi kullanarak (LuaJIT de kullanılabilir) Ben yorumlayıcı yerine doğrudan Lua VM kendisi tarafından çalıştırılan kodu üreten "JIT-to-Lua" ile değiştirdim. Bunun gerçekten JIT olarak sayıldığından emin değil, ancak hızı geliştiriyor.

U,S,P,F=table.unpack,table.insert,table.remove,math.floor X,r0,r1,r2,p,m,s=2^32,0,0,0,1,0,{}C={{'r%u=%u',1,4},{'r%u=r%u',1,1},{'S(s,r%u)',1},{'r%u=P(s)',1},{'r%u=(r%u+r%u)%%X',1,0,1},{'r%u=(r%u-r%u)%%X',1,0,1},{'r%u=(r%u*r%u)%%X',1,0,1},{'r%u=F(r%u/r%u)%%X',1,0,1},{'goto L%u',4},{'m=r%u-r%u',1,1},{'if m<0 then goto L%u end',4},{'if m==0 then goto L%u end',4},{'if m>0 then goto L%u end',4},{'if m~=0 then goto L%u end',4}}t={io.open(arg[1],'rb'):read('*a'):byte(1,-1)}i,n,r=1,0,{}while i<=#t do c,i,x,a=C[t[i]+1],i+1,0,{}for j=2,#c do y=c[j]if y>0 then x=0 for k=1,y do i,x=i+1,x*256+t[i]end end S(a,x)end S(r,('::L%d::'):format(n))n=n+1 S(r,c[1]:format(U(a)))end load(table.concat(r,' '))()print(('R0 %u\nR1 %u\nR2 %u'):format(r0,r1,r2))

İşte orijinal, okunabilir versiyon.

U,S,P,F=table.unpack,table.insert,table.remove,math.floor

X,r0,r1,r2,p,m,s=2^32,0,0,0,1,0,{}

C={
    {'r%u=%u',1,4},
    {'r%u=r%u',1,1},
    {'S(s,r%u)',1},
    {'r%u=P(s)',1},
    {'r%u=(r%u+r%u)%%X',1,0,1},
    {'r%u=(r%u-r%u)%%X',1,0,1},
    {'r%u=(r%u*r%u)%%X',1,0,1},
    {'r%u=F(r%u/r%u)%%X',1,0,1},
    {'goto L%u',4},
    {'m=r%u-r%u',1,1},
    {'if m<0 then goto L%u end',4},
    {'if m==0 then goto L%u end',4},
    {'if m>0 then goto L%u end',4},
    {'if m~=0 then goto L%u end',4},
}

t={io.open(arg[1],'rb'):read('*a'):byte(1,-1)}
i,n,r=1,0,{}
while i<=#t do
    c,i,x,a=C[t[i]+1],i+1,0,{}
    for j=2,#c do
        y=c[j]
        if y>0 then
            x=0 
            for k=1,y do 
                i,x=i+1,x*256+t[i]
            end 
        end
        S(a,x)
    end
    S(r,('::L%d::'):format(n)) 
    n=n+1
    S(r,c[1]:format(U(a)))
end
load(table.concat(r,' '))()
print(('R0 %u\nR1 %u\nR2 %u'):format(r0,r1,r2))

Programınızı çalıştırdığımda şu hatayı aldım: pastebin.com/qQBD7Rs8 . Bayt kodunu stdin üzerinden mi yoksa dosya olarak mı bekliyorsunuz?
Renkli Tek Renkli

Afedersiniz. Windows için ikili dosyam bozuldu. Böylece, tüm gcc / linux sürümleri çalıştı, ancak windows testleri çöktü. Bununla birlikte, R0 ve R1'in 0, R2'nin 1 olduğunu bildiriyor.
Rengarenk Tek Renkli

Aslında yürütme şüpheli: ortalama çalıştırmak için 33.8 ms sürdü (GCC ~ .25 saniye sürer).
Renkli Tek Renkli

Komut dosyası, dosya adı komut satırında iletilerek bayt kodunu bir dosya olarak bekler. Yine de haklısın, onu takip ettim ve sadece ilk dış döngüyü yapıyor gibi görünüyor. Çizim tahtasına geri dön ...
criptych Monica ile

C'de düşünmek ve Lua'da yazmak için aldığım şey: <döngülerim yerine<= , bu yüzden son şube talimatı bırakıldı. Hala yanlış yanıtı alıyor, ancak şimdi birkaç dakika sürüyor. :)
criptych Monica ile

1

C #

1505 1475 bayt

Bu benim yorumlayıcı, C # ile yazılmış versiyonu daha optimize / golf olabilir sanırım, ama gerçekten nerede bilmiyorum;)

golf versiyonu:

using System;using System.Collections.Generic;using System.IO;using System.Linq;class M{static void Main(string[]a){if(a.Length==1&&File.Exists(a[0])){B.E(B.P(File.ReadAllLines(a[0])));Console.WriteLine(B.O);}}}class B{public enum I{L=0x00,P=0x02,Q=0x03,A=0x04,S=0x05,M=0x06,D=0x07,J=0x08,C=0x09,BL=0x0a,BE=0x0b,BG=0x0c,BN=0x0d}public enum R{A,B,C}enum C{N,L,E,G}public static Dictionary<R,uint>r=new Dictionary<R,uint>{{R.A,0},{R.B,0},{R.C,0}};public static Stack<uint>s=new Stack<uint>();static C c=C.N;public static string O{get{return string.Format("R0 {0}\nR1 {1}\nR2 {2}",r[R.A],r[R.B],r[R.C]);}}public static void E(byte[][]l){for(uint i=0;i<l.Length;i++){var q=l[i];switch((I)q[0]){case I.L:r[(R)q[1]]=U(q,2);break;case I.P:r[(R)q[1]]=s.Pop();break;case I.Q:s.Push(r[(R)q[1]]);r[(R)q[1]]=0;break;case I.A:s.Push(r[(R)q[1]]+r[(R)q[2]]);break;case I.S:s.Push(r[(R)q[1]]-r[(R)q[2]]);break;case I.M:s.Push(r[(R)q[1]]*r[(R)q[2]]);break;case I.D:s.Push(r[(R)q[1]]/r[(R)q[2]]);break;case I.J:i=U(q,1)-1;break;case I.C:{uint x=r[(R)q[1]],y=r[(R)q[2]];c=x<y?C.L:x>y?C.G:C.E;}break;case I.BL:if(c==C.L)i=U(q,1)-1;break;case I.BG:if(c==C.G)i=U(q,1)-1;break;case I.BE:if(c==C.E)i=U(q,1)-1;break;case I.BN:if(c!=C.E)i=U(q,1)-1;break;}}}public static byte[][]P(string[]c){return c.Where(l=>!l.StartsWith("#")).Select(r=>r.Split(' ').Where(b=>b.Length>0).Select(b=>Convert.ToByte(b,16)).ToArray()).Where(l=>l.Length>0).ToArray();}static uint U(byte[]b,int i){return(uint)(b[i]<<24|b[i+1]<<16|b[i+2]<<8|b[i+3]);}}

Düzenle

bazı gereksiz publicve privatedeğiştiriciler kaldırıldı :

using System;using System.Collections.Generic;using System.IO;using System.Linq;class M{static void Main(string[]a){if(a.Length==1&&File.Exists(a[0])){B.E(B.P(File.ReadAllLines(a[0])));Console.Write(B.O);}}}class B{enum I{L=0x00,P=0x02,Q=0x03,A=0x04,S=0x05,M=0x06,D=0x07,J=0x08,C=0x09,BL=0x0a,BE=0x0b,BG=0x0c,BN=0x0d}enum R{A,B,C}enum C{N,L,E,G}static Dictionary<R,uint>r=new Dictionary<R,uint>{{R.A,0},{R.B,0},{R.C,0}};static Stack<uint>s=new Stack<uint>();static C c=C.N;public static string O{get{return string.Format("R0 {0}\nR1 {1}\nR2 {2}\n",r[R.A],r[R.B],r[R.C]);}}public static void E(byte[][]l){for(uint i=0;i<l.Length;i++){var q=l[i];switch((I)q[0]){case I.L:r[(R)q[1]]=U(q,2);break;case I.P:r[(R)q[1]]=s.Pop();break;case I.Q:s.Push(r[(R)q[1]]);r[(R)q[1]]=0;break;case I.A:s.Push(r[(R)q[1]]+r[(R)q[2]]);break;case I.S:s.Push(r[(R)q[1]]-r[(R)q[2]]);break;case I.M:s.Push(r[(R)q[1]]*r[(R)q[2]]);break;case I.D:s.Push(r[(R)q[1]]/r[(R)q[2]]);break;case I.J:i=U(q,1)-1;break;case I.C:{uint x=r[(R)q[1]],y=r[(R)q[2]];c=x<y?C.L:x>y?C.G:C.E;}break;case I.BL:if(c==C.L)i=U(q,1)-1;break;case I.BG:if(c==C.G)i=U(q,1)-1;break;case I.BE:if(c==C.E)i=U(q,1)-1;break;case I.BN:if(c!=C.E)i=U(q,1)-1;break;}}}public static byte[][]P(string[]c){return c.Where(l=>!l.StartsWith("#")).Select(r=>r.Split(' ').Where(b=>b.Length>0).Select(b=>Convert.ToByte(b,16)).ToArray()).Where(l=>l.Length>0).ToArray();}static uint U(byte[]b,int i){return(uint)(b[i]<<24|b[i+1]<<16|b[i+2]<<8|b[i+3]);}}

ile diyoruz executable.exe filenamenereye filenamekodu içeren dosya bulunduğu anlamına gelmektedir

"Test programım":

# LOAD R0 5
# CMP R0 R1
# BRANCHEQ 13
# LOAD R1 1
# LOAD R2 1
# CMP R0 R2
# MUL R1 R2
# LOAD R1 1
# ADD R2 R1
# PUSH R2
# PUSH R1 
# BRANCHEQ 13
# JMP 5
# POP R2
# POP R0
# POP R1
# PUSH R0

0x0 0x0 0x0 0x0 0x0 0x5
0x9 0x0 0x1 
0xb 0x0 0x0 0x0 0xd 
0x0 0x1 0x0 0x0 0x0 0x1 
0x0 0x2 0x0 0x0 0x0 0x1 
0x9 0x0 0x2 
0x6 0x1 0x2 
0x0 0x1 0x0 0x0 0x0 0x1 
0x4 0x2 0x1 
0x2 0x2 
0x2 0x1 
0xb 0x0 0x0 0x0 0xd 
0x8 0x0 0x0 0x0 0x5 
0x3 0x2 
0x3 0x0 
0x3 0x1 
0x2 0x0 

Tercüman uzun isim değişkenleri, sınıfları, ungolfed ...

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        if (args.Length == 1 && File.Exists(args[0]))
        {
            var code = ByteCodeInterpreter.ParseCode(File.ReadAllLines(args[0]));
            ByteCodeInterpreter.Execute(code);
            Console.WriteLine(ByteCodeInterpreter.Output);
        }
    }
}

public static class ByteCodeInterpreter
{
    public enum Instruction : byte
    {
        LOAD = 0x00,
        PUSH = 0x02,
        POP = 0x03,
        ADD = 0x04,
        SUB = 0x05,
        MUL = 0x06,
        DIV = 0x07,
        JMP = 0x08,
        CMP = 0x09,
        BRANCHLT = 0x0a,
        BRANCHEQ = 0x0b,
        BRANCHGT = 0x0c,
        BRANCHNE = 0x0d
    }

    public enum Register : byte
    {
        R0 = 0x00,
        R1 = 0x01,
        R2 = 0x02
    }

    private enum CompareFlag : byte
    {
        NONE = 0x00,
        LT = 0x01,
        EQ = 0x02,
        GT = 0x03,
    }

    public static readonly Dictionary<Register, uint> register = new Dictionary<Register, uint>
    {
        {Register.R0, 0},
        {Register.R1, 0},
        {Register.R2, 0}
    };

    public static readonly Stack<uint> stack = new Stack<uint>();
    private static CompareFlag compareFlag = CompareFlag.NONE;

    public static string Output
    {
        get
        {
            return string.Format("R0 {0}\nR1 {1}\nR2 {2}", register[Register.R0], register[Register.R1],
                register[Register.R2]);
        }
    }

    public static void Execute(byte[][] lines)
    {
        for (uint i = 0; i < lines.Length; i++)
        {
            var line = lines[i];
            switch ((Instruction)line[0])
            {
                case Instruction.LOAD:
                    register[(Register)line[1]] = GetUint(line, 2);
                    break;
                case Instruction.PUSH:
                    register[(Register)line[1]] = stack.Pop();
                    break;
                case Instruction.POP:
                    stack.Push(register[(Register)line[1]]);
                    register[(Register)line[1]] = 0;
                    break;
                case Instruction.ADD:
                    stack.Push(register[(Register)line[1]] + register[(Register)line[2]]);
                    break;
                case Instruction.SUB:
                    stack.Push(register[(Register)line[1]] - register[(Register)line[2]]);
                    break;
                case Instruction.MUL:
                    stack.Push(register[(Register)line[1]] * register[(Register)line[2]]);
                    break;
                case Instruction.DIV:
                    stack.Push(register[(Register)line[1]] / register[(Register)line[2]]);
                    break;
                case Instruction.JMP:
                    i = GetUint(line, 1) - 1;
                    break;
                case Instruction.CMP:
                    {
                        uint v0 = register[(Register)line[1]], v1 = register[(Register)line[2]];
                        if (v0 < v1)
                            compareFlag = CompareFlag.LT;
                        else if (v0 > v1)
                            compareFlag = CompareFlag.GT;
                        else
                            compareFlag = CompareFlag.EQ;
                    }
                    break;
                case Instruction.BRANCHLT:
                    if (compareFlag == CompareFlag.LT)
                        i = GetUint(line, 1) - 1;
                    break;
                case Instruction.BRANCHGT:
                    if (compareFlag == CompareFlag.GT)
                        i = GetUint(line, 1) - 1;
                    break;
                case Instruction.BRANCHEQ:
                    if (compareFlag == CompareFlag.EQ)
                        i = GetUint(line, 1) - 1;
                    break;
                case Instruction.BRANCHNE:
                    if (compareFlag != CompareFlag.EQ)
                        i = GetUint(line, 1) - 1;
                    break;
            }
        }
    }

    public static byte[][] ParseCode(string[] code)
    {
        return
            code.Where(line => !line.StartsWith("#"))
                .Select(line => line.Split(' ').Where(b => b.Length > 0).Select(b => Convert.ToByte(b, 16)).ToArray())
                .Where(line => line.Length > 0)
                .ToArray();
    }

    private static uint GetUint(byte[] bytes, int index)
    {
        return (uint)(bytes[index] << 24 | bytes[index + 1] << 16 | bytes[index + 2] << 8 | bytes[index + 3]);
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.