Bir Clem tercümanı yazın


11

Clem, birinci sınıf işlevlere sahip minimal yığın tabanlı bir programlama dilidir. Amacınız Clem dili için bir tercüman yazmaktır. Düzgün kullanılabilir referans uygulanması dahil tüm örneklerini yürütmek gerekir burada .

Clem dili

Clem, birinci sınıf işlevlere sahip yığın tabanlı bir programlama dilidir. Clem'i öğrenmenin en iyi yolu, clemyorumlayıcıyı argüman olmadan çalıştırmaktır . Kullanılabilir komutlarla oynamanıza izin veren etkileşimli modda başlayacaktır. Örnek programları çalıştırmak için şunu yazın: clem example.clmexample, programın adıdır. Bu kısa eğitici, başlamanız için yeterli olmalıdır.

İki ana işlev sınıfı vardır. Atom fonksiyonları ve bileşik fonksiyonlar. Bileşik fonksiyonlar, diğer bileşik fonksiyonlardan ve atom fonksiyonlarından oluşan listelerdir. Bileşik bir işlevin kendisini içeremeyeceğini unutmayın.

Atomik Fonksiyonlar

İlk atomik fonksiyon tipi sabittir . Bir sabit , sadece bir tamsayı değerdir. Örneğin, -10. Yorumlayıcı bir sabitle karşılaştığında , onu yığına doğru iter. clemŞimdi koş . Tip -10istemi de. Görmelisin

> -10
001: (-10)
>

Değer 001yığınında fonksiyonun konumunu açıklar ve (-10) bir sabit sadece girdi. Şimdi +11bilgi istemine girin . Görmelisin

> +11
002: (-10)
001: (11)
>

Uyarı (-10)yığındaki ikinci pozisyona taşındığı ve (11)şimdi ilk kaplar. Bu bir yığının doğasıdır! Bunun -da azalma komutu olduğunu göreceksiniz . Ne zaman -ya da +bir numara önüne, o sayının işaretini olup ilgili komutu belirtir. Diğer tüm atom fonksiyonları komuttur . Toplam 14 adet var:

@  Rotate the top three functions on the stack
#  Pop the function on top of the stack and push it twice
$  Swap the top two functions on top of the stack
%  Pop the function on top of the stack and throw it away
/  Pop a compound function. Split off the first function, push what's left, 
   then push the first function.
.  Pop two functions, concatenate them and push the result
+  Pop a function. If its a constant then increment it. Push it
-  Pop a function. If its a constant then decrement it. Push it
<  Get a character from STDIN and push it to the stack. Pushes -1 on EOF.
>  Pop a function and print its ASCII character if its a constant
c  Pop a function and print its value if its a constant
w  Pop a function from the stack. Peek at the top of the stack. While it is
   a non-zero constant, execute the function.

Komut istemine bir komut yazıldığında komut yürütülür. Tip #(yinelenen komutu) istemi de. Görmelisin

> #
003: (-10)
002: (11)
001: (11)
> 

(11) 'in kopyalandığına dikkat edin. Şimdi %bilgi istemine yazın (drop komutu). Görmelisin

> %
002: (-10)
001: (11)
> 

Yığına bir komut göndermek için parantez içine almanız yeterlidir. Tip (-)istemi de. Bu işlem azaltma operatörünü yığına itecektir. Görmelisin

> (-)
003: (-10)
002: (11)
001: (-)
> 

Bileşik fonksiyonlar

Bileşik bir fonksiyon oluşturmak için birden fazla atomik fonksiyonu parantez içine alabilirsiniz. Komut istemine bir bileşik işlevi girdiğinizde, işlev yığına itilir. Tip ($+$)istemi de. Görmelisin

> ($+$)
004: (-10)
003: (11)
002: (-)
001: ($ + $)
>

Teknik olarak, yığındaki her şey bileşik bir işlevdir. Bununla birlikte, yığındaki bileşik fonksiyonların bazıları tek bir atomik fonksiyondan oluşur (bu durumda, kolaylık sağlamak için bunları atomik fonksiyonlar olarak kabul edeceğiz). Yığındaki bileşik işlevleri değiştirirken, .komut (birleştirme) genellikle yararlıdır. Tip .şimdi. Görmelisin

> . 
003: (-10)
002: (11)
001: (- $ + $)
> 

Yığındaki birinci ve ikinci işlevlerin birleştirildiğine ve yığındaki ikinci işlevin sonuç listesinde ilk geldiğine dikkat edin. Yığında bulunan bir işlevi yürütmek için (ister atomik ister bileşik olsun), wkomutu (while) vermeliyiz . wKomut yığında ilk işlev pop ve çok uzun yığında ikinci fonksiyon, bir sıfır olmayan sabit olduğu gibi tekrar tekrar çalıştırır. Yazarsak ne olacağını tahmin etmeye çalışın w. Şimdi yazın w. Görmelisin

> w
002: (1)
001: (0)
> 

Beklediğin bu mu? Yığın üstünde oturan iki sayı eklendi ve toplamları kaldı. Hadi tekrar dene. Önce sıfırı düşüreceğiz ve 10 yazarak yazacağız %10. Görmelisin

> %10
002: (1)
001: (10)
> 

Şimdi tüm işlevi bir çekimde yazacağız, ancak %sıfırdan kurtulmak için sonuna bir ekstra ekleyeceğiz . Tip (-$+$)w%istemi de. Görmelisin

> (-$+$)w%
001: (11)
> 

(Bu algoritmanın yalnızca yığındaki ilk sabit pozitifse işe yaradığını unutmayın).

Teller

Dizeler de mevcuttur. Çoğunlukla sözdizimsel şekerdir, ancak oldukça yararlı olabilirler. Yorumlayıcı bir dizeyle karşılaştığında, her karakteri sondan ilkeye yığına iter. Tip %Önceki örnekten 11 düşmesi. Şimdi 0 10 "Hi!"bilgi istemini yazın. 0Bir NULL Sonlandırıcı ekler ve 10yeni bir satır karakteri ekler. Görmelisin

> 0 10 "Hi!"
005: (0)
004: (10)
003: (33)
002: (105)
001: (72)
> 

Tür (>)wbiz NULL Sonlandırıcı karşılaşana kadar yığını karakterleri yazdırmak için. Görmelisin

> (>)w
Hi!
001: (0)
> 

Sonuçlar

Umarım bu, tercümanla başlamanız için yeterli olacaktır. Dil tasarımı nispeten basit olmalıdır. Bir şeyin son derece belirsiz olup olmadığını bana bildirin :) Birkaç şey kasıtlı olarak belirsiz bırakıldı: değerler imzalanmalı ve en az 16 bit olmalı, yığın tüm referans programlarını çalıştıracak kadar büyük olmalıdır. tam bir üflemeli dil belirtimi yayınlamak için büyük ölçüde büyük olacaktır (ve henüz bir tane yazmadım: P). Şüphe duyduğunuzda referans uygulamasını taklit edin.

Clem için esolangs.org sayfası

C'deki referans uygulaması


Henüz dil spesifikasyonunu yazmadığınızı söylediniz. O zaman dilin yaratıcısı olduğunuzu anladım?
COTO

@COTO Doğru. Dili ben yarattım.
Orby

5
Çok önemli bir soru: "klem" veya "see-lem" diye telaffuz eder misiniz?
Martin Ender

4
@ MartinBüttner: "klem" :)
Orby

2
@ Komutunun en üstteki 3 işlevi döndüreceği yönü belirtmek isteyebilirsiniz. (001 -> 002 -> 003 -> 001 veya 003 -> 002 -> 001 -> 003)
kwokkie

Yanıtlar:


1

Haskell, 931 921 875

Bu henüz tam golf değil ama muhtemelen asla olmayacak. Yine de, diğer tüm çözümlerden zaten daha kısadır. Ben daha yakında golf olacak. Bundan daha fazla golf oynamak istemiyorum.

C referans uygulamasıyla oynamadığım için muhtemelen birkaç ince hata var.

bu çözüm StateT [String] IO ()"runnable" bir clem programı saklamak için türü kullanır . programın çoğu "çalıştırılabilir programı" ayrıştıran bir ayrıştırıcıdır.

Bu kullanımı çalıştırmak için r "<insert clem program here>".

import Text.Parsec
import Control.Monad.State
import Control.Monad.Trans.Class
import Data.Char
'#'%(x:y)=x:x:y
'%'%(x:y)=y
'@'%(x:y:z:w)=y:z:x:w
'$'%(x:y:z)=y:x:z
'/'%((a:b):s)=[a]:b:s
'+'%(a:b)=i a(show.succ)a:b
'.'%(a:b:c)=(a++b):c
_%x=x
b=concat&between(s"(")(s")")(many$many1(noneOf"()")<|>('(':)&((++")")&b))
e=choice[s"w">>c(do p<-t;let d=h>>= \x->if x=="0"then a else u p>>d in d),m&k,s"-">>(m&(' ':)&k<|>c(o(\(a:b)->i a(show.pred)a:b))),s"c">>c(do
 d<-t
 i d(j.putStr.show)a),o&(++)&map(show.ord)&between(s"\"")(s"\"")(many$noneOf"\""),(do
 s"<"
 c$j getChar>>=m.show.ord),(do
 s">"
 c$do
 g<-t
 i g(j.putChar.chr)a),m&b,o&(%)&anyChar]
k=many1 digit
i s f g|(reads s::[(Int,String)])>[]=f$(read s::Int)|0<1=g
t=h>>=(o tail>>).c
c n=return n
a=c()
h=head&get
(&)f=fmap f
m=o.(:)
o=modify
u=(\(Right r)->r).parse(sequence_&many e)""
r=(`runStateT`[]).u
s=string
j=lift

5

Python, 1684 1.281 karakter

Tüm temel golf şeyler yaptım. Tüm örnek programları çalıştırır ve karakter için çıktı karakteriyle eşleşir.

import sys,os,copy as C
L=len
S=[]
n=[S]
Q=lambda:S and S.pop()or 0
def P(o):
 if o:n[0].append(o)
def X():x=Q();P(x);P(C.deepcopy(x))
def W():S[-2::]=S[-1:-3:-1]
def R():a,b,c=Q(),Q(),Q();P(a);P(c);P(b)
def A(d):
 a=Q()
 if a and a[0]:a=[1,a[1]+d,lambda:P(a)]
 P(a)
def V():
 a=Q();P(a)
 if a and a[0]-1and L(a[2])>1:r=a[2].pop(0);P(r)
def T():
 b,a=Q(),Q()
 if a!=b:P([0,0,(a[2],[a])[a[0]]+(b[2],[b])[b[0]]])
 else:P(a);P(b)
def r():a=os.read(0,1);F(ord(a)if a else-1)
def q(f):
 a=Q()
 if a and a[0]:os.write(1,(chr(a[1]%256),str(a[1]))[f])
def e(f,x=0):f[2]()if f[0]+f[1]else([e(z)for z in f[2]]if x else P(f))
def w():
 a=Q()
 while a and S and S[-1][0]and S[-1][1]:e(a,1)
def Y():n[:0]=[[]]
def Z():
 x=n.pop(0)
 if x:n[0]+=([[0,0,x]],x)[L(x)+L(n)==2]
D={'%':Q,'#':X,'$':W,'@':R,'+':lambda:A(1),'-':lambda:A(-1),'/':V,'.':T,'<':r,'>':lambda:q(0),'c':lambda:q(1),'w':w,'(':Y,')':Z}
def g(c):D[c]()if L(n)<2or c in'()'else P([0,1,D[c]])
N=['']
def F(x):a=[1,x,lambda:P(a)];a[2]()
def E():
 if'-'==N[0]:g('-')
 elif N[0]:F(int(N[0]))
 N[0]=''
s=j=""
for c in open(sys.argv[1]).read()+' ':
 if j:j=c!="\n"
 elif'"'==c:E();s and map(F,map(ord,s[:0:-1]));s=(c,'')[L(s)>0]
 elif s:s+=c
 elif';'==c:E();j=1
 else:
    if'-'==c:E()
    if c in'-0123456789':N[0]+=c
    else:E();c in D and g(c)

Test :

Clemint.py , clemtest_data.py , clemtest.py ve derlenmiş bir clemikili dizini bir dizine toplayın ve çalıştırın clemtest.py.

Genişleme :

En ungolfed sürümüdür bu bir . Bunu takip et.

Sana yığın. Yığının her bir öğesi 3 listeden oluşur, bunlardan biri:

Constant: [1, value, f]
Atomic: [0, 1, f]
Compound: [0, 0, fs]

Sabitler için, sabiti fyığına iten bir işlevdir. Atmoics için fişlemlerin bir yürüten bir fonksiyonu (örneğin, bir -, +). Bileşikler için, fsbir öğe listesidir.

xecbir öğeyi yürütür. Bir sabit veya atomsa, sadece işlevi yürütür. Bileşikse, henüz özyineleme yapılmadıysa, her işlevi yürütür. Yani yürütme (10 20 - 30)fonksiyonlarının her çalıştırır 10, 20, -ve 30bırakarak 10 19 30yığını üzerinde. Özyineleme varsa, bileşik işlevini yığının üzerine iter. Yürütürken Örneğin (10 20 (3 4) 30), sonuç olmalıdır 10 20 (3 4) 30değil 10 20 3 4 30.

Yuvalama biraz zor oldu. Okurken ne yaparsınız (1 (2 (3 4)))? Çözüm yığın yığınına sahip olmaktır. Her yuvalama seviyesinde, yığın yığınına yeni bir yığın itilir ve tüm itme işlemleri bu yığın üzerine gider. Ayrıca, yuvalama yapılmışsa, yerine atomik fonksiyonlar itilir. Gördüğünüz Yani 10 20 (- 30) 40, 10itilir, daha sonra 20, daha sonra yeni yığını oluşturulur, -ve 30yeni yığını üzerine itilir ve )yeni yığın kapalı açılan pencereleri, yığın bir düzey aşağı üzerine bir öğeye haline döner ve kesmeler onu. endnest()kolları ). Sadece bir öğenin itildiği ve ana yığını geri ittiğimiz özel bir durum olduğu için biraz zor oldu. Yani, (10)sabiti itmeli10, tek sabit ile bir bileşik değil, çünkü o zaman -ve +çalışmıyor. Bunun ilkeli olup olmadığından emin değilim ama bu şekilde çalışıyor ...

Tercüm karakter karakter işlemcidir - jeton oluşturmaz - bu nedenle sayılar, dizeler ve yorumlar başa çıkmak biraz sinir bozucuydu. Ayrı bir yığın var, Nşu anda işlenmekte olan bir sayı için ve sayı olmayan bir karakter işlendiğinde, endnum()önce bu sayıyı tamamlayıp yığına koymam gerekip gerekmediğini görmek için aramalıyım . Bir dizede veya yorumda olmamız boole değişkenleri tarafından izlenir; bir dize kapatıldığında yığındaki tüm iç kısımları iter. Negatif sayılar için de bazı özel işlemler gerekiyordu.

Genel bakış için bu kadar. Geri kalan tüm yerleşik ins uygulanması ve derin kopyalarını yapmak emin olmaktı +, -ve #.


Kudos! Eğlendin mi? :)
Orby

@Orby: Kesinlikle öyle! İlginç bir dil, kesinlikle garip bir dil. 1k'dan küçük bir tercüman bulabileceğimi umuyorum. Diğer gönderimlerden ne bekleyeceğinizden emin değilim.
Claudiu

4

C 837

@Ceilingcat'e çok daha iyi (ve daha kısa) bir versiyon bulduğu için teşekkürler

Bu, her şeyi basit dizeler olarak ele alır - tüm yığın öğeleri dizelerdir, sabitler bile dizelerdir.

#define Q strcpy
#define F(x)bcopy(b,f,p-b);f[p-b-x]=!Q(r,p);
#define C(x,y)Q(S[s-x],S[s-y]);
#define N[9999]
#define A Q(S[s++]
#define D sprintf(S[s++],"%d"
#define G(x)}if(*f==x){
#define H(x)G(x)s--;
#define R return
#define Z(x)T(t,u,v)-1||putchar(x);H(
char S N N;s;c;T(b,f,r)char*b,*f,*r;{char*p;strtol(b+=strspn(b," "),&p,0);if(p>b){F(0)R 1;}if(c=*b==40){for(p=++b;c;)c+=(*p==40)-(*p++==41);F(1)R-1;}p++;F(0)*r*=!!*b;R 0;}*P(char*p){if(*p==34)R++p;char*r=P(p+1);D,*p);R r;}E(char*x){char*p,c N,f N,r N,t N,u N,v N;for(Q(c,x);*c;Q(c,p)){Q(t,S[s-1]);if(T(c,f,p=r))A,f);else{{G(64)C(0,1)C(1,2)C(2,3)C(3,0)G(35)A,t);G(36)C(0,2)C(2,1)C(1,0)H(37)H(47)T(t,u,v);*v&&A,v);A,u);H(46)strcat(strcat(S[s-1]," "),t);H(43)D,atoi(t)+1);H(45)D,atoi(t)-1);G(60)D,getchar());H(62)Z(atoi(u))99)Z(*u)119)for(Q(u,t);atoi(S[s-1]);)E(u);G(34)p=P(p);}}}}

Çevrimiçi deneyin!

Orijinalimin daha az golf edilmiş bir versiyonu (golfed versiyonunun aksine, boş değilse bittiği zaman yığını yazdırır ve bir dosyadan okumak yerine komut satırında komut dosyasını belirleyebilmeniz için bir -e parametresi alır):

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define FIRST_REST(x) memcpy(first, b, p - b); first[p - b - x] = '\0'; strcpy(rest, p);
#define COPY(dest,src) strcpy(stack[size + dest], stack[size + src]);
char stack[9999][9999]; int size = 0;
int token(char *b, char *first, char *rest)
{
    while (*b == 32) b++;
    char *p; int x = strtol(b, &p, 0);
    if (p > b) { FIRST_REST(0) return 1; }
    if (*b == '(') { int c = 1; for (p = ++b; c; ++p) c += (*p == '(') - (*p == ')'); FIRST_REST(1) return -1; }
    p++; FIRST_REST(0) if (!*b) *rest = '\0'; return 0;
}
char *push(char *pointer)
{
    if (*pointer == '\"') return pointer+1;
    char *result = push(pointer+1);
    sprintf(stack[size++], "%d", *pointer);
    return result;
}
void eval(char *x)
{
    char program[9999], first[9999], rest[9999], tos[9999], tmp1[9999], tmp2[9999];
    char *pointer;
    for (strcpy(program, x); *program; strcpy(program, pointer))
    {
        *stack[size] = '\0';
        strcpy(tos, stack[size-1]);
        if (token(program, first, rest))
        {
            pointer = rest;
            strcpy(stack[size++], first);
        }
        else
        {
            pointer = rest;
            if (*first == '@'){
                COPY(0, -1) COPY(-1, -2) COPY(-2, -3) COPY(-3, 0) }
            if (*first == '#')
                strcpy(stack[size++], tos);
            if (*first == '$'){
                COPY(0, -2) COPY(-2, -1) COPY(-1, 0) }
            if (*first == '%')
                size--;
            if (*first == '/'){
                size--; token(tos, tmp1, tmp2); if (*tmp2) strcpy(stack[size++], tmp2); strcpy(stack[size++], tmp1); }
            if (*first == '.'){
                size--; strcat(stack[size - 1], " "); strcat(stack[size - 1], tos); }
            if (*first == '+'){
                size--; sprintf(stack[size++], "%d", atoi(tos) + 1); }
            if (*first == '-'){
                size--; sprintf(stack[size++], "%d", atoi(tos) - 1); }
            if (*first == '<')
                sprintf(stack[size++], "%d", getchar());
            if (*first == '>'){
                size--; if (token(tos, tmp1, tmp2) == 1) putchar(atoi(tmp1)); }
            if (*first == 'c'){
                size--; if (token(tos, tmp1, tmp2) == 1) printf("%s", tmp1); }
            if (*first == 'w'){
                size--; strcpy(tmp1, tos); while (atoi(stack[size - 1])) eval(tmp1); }
            if (*first == '\"')
                pointer=push(pointer);
        }
    }
}
int main(int argc, char **argv)
{
    char program[9999] = "";
    int i = 0, comment = 0, quote = 0, space = 0;
    if (!strcmp(argv[1], "-e"))
        strcpy(program, argv[2]);
    else
    {
        FILE* f = fopen(argv[1], "r");
        for (;;) {
            char ch = fgetc(f);
            if (ch < 0) break;
            if (!quote) {
                if (ch == '\n') comment = 0;
                if (ch == ';') comment = 1;
                if (comment) continue;
                if (ch <= ' ') { ch = ' '; if (space++) continue; }
                else space = 0;
            }
            if (ch == '\"') quote = 1 - quote;
            program[i++] = ch;
        }
        fclose(f);
    }
    eval(program);
    for (int i = 0; i < size; i++) printf("%03d: (%s)\r\n",size-i,stack[i]);
    return 0;
}

Güzel! Python çözümünü C'de yendi. Kısa versiyonumu yüklemeliyim, 60 bayt kadar tıraş etmeyi başardım .. Hala 1000 karakterden az yol verecek farklı bir yaklaşım olup olmadığını merak ediyorum
Claudiu

@Claudiu Ben de öyle düşündüm - ama nasıl olduğunu anlayamadım.
Jerry Jeremiah
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.