Transpile WordMath


25

Hepimiz şöyle görünen çevrimiçi "matematik haxını" gördük:

Think of a number, divide by 2, multiply by 0, add 8.

Ve sihirle, herkes 8 rakamıyla bitiyor!


Dil

Yukarıdaki metnin sözdizimini kullanan ve "WordMath" adı verilen bir programlama dili tanımlayalım. WordMath komut dosyaları bu şablonu izler:

Think of a number, <commandlist>.

Temel olarak şu anlama gelir: İlk akümülatör olarak bir sayı alın (STDIN'den gelen giriş olarak), üzerindeki tüm komutları uygulayın ve sonucu çıkartın.

Komutlar sınırlayıcı tarafından ayrılır ,(virgül + boşluk). Geçerli komutlar ( #negatif olmayan bir tamsayıyı gösterdiğine dikkat edin :) :

  • add #/ subtract #- Akümülatöre değer ekle / çıkar.
  • divide by #/ multiply by #- floordiv / akümülatörü verilen değer ile çarpın.
  • subtract from #- Benzer subtract, ancak acc = # - accyerineacc = acc - #
  • repeat- son komutu tekrar yap. Bu ilk komut olamaz, ancak art arda birden çok tekrarı desteklemelisiniz.

Meydan okuma

Göreviniz girdi olarak geçerli bir WordMath komut alır ve bir program veya fonksiyon oluşturmaktır transpiles kodunuzu olduğu aynı dilde - Geçerli bir tam programın içine.

Örneğin, kodum Python 2'deyse ve komut dosyası:

Think of a number, subtract from 10, add 10, multiply by 2.

Çıkarılan program şunlar olabilir:

a = input()
a = 10 - a
a += 10
a *= 2
print(a)

Veya alternatif olarak:

print(((10-input())+10)*2)

Dilin en yakın eşdeğerlerinden girdi alan ve çıktı alan tam bir program olduğu sürece .STDINSTDOUT


kurallar

  • Orijinal programınız, girişin her zaman geçerli bir WordMath betiği olduğunu varsayabilir.
  • Transpiled programları 0 ile bölme gibi matematiksel hataları ele almak zorunda değildir.
  • Kopyalanan programlar, girişin, dilinizin standart tamsayı aralığında geçerli bir işaretli tamsayıyı temsil ettiğini varsayabilir.
  • Bu , yani en kısa çözüm (bayt cinsinden) kazanır.
  • Orijinal programınızın sadece bayt sayısı önemlidir - çıkarılan kod istediğiniz kadar olabilir!

Örnek Scriptler

Örnek 1:

Think of a number. 

Girdi alın, hiçbir şey yapmayın, gösterin: WordMath'ın kedi programı.

Örnek 2:

Think of a number, divide by 5, subtract from 9.

Unutmayın, "bölme", ​​kat bölümüdür, bu nedenle bu program için 6 -> 8ve 29 -> 4.

Örnek 3:

Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.

Genişletilmiş kedi programı!

Örnek 4:

Think of a number, subtract 1, repeat, repeat.

Bir sayı alır ve 3 çıkarır.


Ardışık tekrarları desteklemek zorunda mıyız?
darrylyeo

1
Float dilinin varsayılan türü olduğunda / tamsayıları desteklemiyorsa kullanabilir miyiz?
Rainer P.

@RainerP. sadece dil, tamsayıları / tamsayı bölümünü desteklemiyorsa
FlipTack

1
Beklenen sonuç nedir -5/3? 0Negatif sonsuzluğa doğru ya da doğru mu dönüyoruz?
Martin Ender

1
@MartinEnder Zemin bölümü olarak negatif sonsuzluğa yuvarlanacağımı söyleyebilirim , ama eğer diliniz 0'a doğru bir tamsayı bölme yaparsa bu da iyidir.
FlipTack

Yanıtlar:


6

05AB1E , 59 56 54 52 bayt

„, ¡¦vyDþs.AJá'bK"dmas""/*+-"‡„-f„s-.:«D'rQi®}©}J'rK

Çevrimiçi deneyin!

Beynim bundan sonra cehennem gibi acıtıyor ... 05AB1E kodunu şöyle veriyor:

  • Think of a Number dolaylı giriş nedeniyle kaldırıldı.
  • Subtract From #kapsar #s-(değiştirir ave bçalıştırır).
  • Subtract #dönüştürür #-.
  • Add #dönüştürür #+.
  • Multiply by #dönüştürür #*.
  • Divide by #dönüştürür #/.
  • Repeat en son kayıt defterinde saklananı kapar ve birleştirir.

Açıklaması:

„, ¡                                                 # Split on ', '.
    ¦                                                # Remove the 'Think of a number'.
     vy                                        }     # Loop through chunks.
       Dþs                                           # Dupe, push only digits, swap.
          .AJá                                       # Acronymify without digits.
              'bK                                    # Remove the `b`.
                 "dmas""/*+-"‡                       # Replace letters with OPs.
                              „-f„s-.:               # Replace '-f' with 's-'.
                                      «              # Concat # with OP.
                                       D'rQ          # Dupe, push 1 if OP='r'.
                                           i®}       # If 'r', push last #OP.
                                              ©      # Store current OP.
                                                J'rK # Join, remove remaining r's.

Örnek:

Giriş:

Think of a number, divide by 2, multiply by 10, add 8, subtract 6, subtract from 9, repeat, repeat, subtract 41.

Çıktı:

2/10*8+6-9s-9s-9s-41-

10 girişli çözümü deneyin:

Çevrimiçi deneyin!

Google'da görün:

İşte google’a yazılan aynı denklemin bağlantısı.


13

C Ön İşlemcisi, 362 Bayt

Ben ALMOST, bu C ön işlemcisinin SADECE çalışmasını sağladı, ancak yineleme komutunun uygulanması çok zor görünüyor. Bunun yerine, önişlemciyi girişi daha sonra bazı ek kodlarla yorumlanan bir diziye dönüştürmek için kullandım.

main(){int c[]={
#define Think 
#define of
#define a
#define number 0
#define add 1,
#define subtract 2,
#define from 0,3,
#define multiply 4,
#define divide 5,
#define by
#define repeat 6, 0
#include "input.wm"
,'$'};int _,l,v;scanf("%d", &_);for(int i=1;c[i]-'$';++i){c[i]!=6?l=c[i],v=c[++i]:++i;l==1?_+=v:l==2?_-=v:l==3?_=v-_:l==4?_*=v:_/=v;}printf("%d",_);}

Giriş, "input.wm" içinde sağlanmalı veya kaynak koduna o satırdan atılmalıdır. Bayt'ı sayıma dahil ettim çünkü meydan okuma kurallarına göre biraz kırılgan ve hafifçe buluyorum, bu yüzden sadece uygun.

Her neyse, bir kez bir derleyicinin bulabileceği WordMath kaynağınızı input.wm'ye döktüğünüzde, WordMath kaynağının söylediğini yapan bir çalıştırılabilir dosya üretme uyarıları ile bunu derlemelisiniz.


2
Not: Bu ne yazık ki, tekrarlama bittiğinde bazı derleyiciler ile başarısız olur. Bunun nedeni, 0'dan sonra bir boşluk bıraktıkları ve daha sonra başıboş bir dönem gördükleri ve onunla ne yapacaklarını bilmedikleridir.
LambdaBeta

zekice, etkilendim.
kedi

7

Retina, 170 bayt

Çünkü bunu kim görmek istemez ki ?!

Bir Retina çözümü görmenin ne kadar harika olacağını düşündüm ve çabucak yaratmaya karar verdim. Sadece bir saat sürdü. Her zamanki gibi, bayt sayısı ISO 8859-1 kodlamasını kabul eder.

S`, 
\.

T.*
.*¶$$*
\;+`(.*)¶rep.*(¶?)
$1¶$1$2
\d+
$*
.*f.* (1*)
1¶x¶$¶$1¶+`x1¶
m.* 
1¶
di.* (1*)
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)
^$1¶
a.* 
^¶
\z
¶1

Çevrimiçi deneyin

Çıktı, elde edilen programı test ederken kopyalanmaması gereken yeni bir satırsonuna sahiptir. Program negatifleri desteklemiyor, çünkü Retina'nın standart tamsayı aralığı (unary).

Açıklama:

S`,                 # Split input on ", " putting each command on its own line
\.                  # Remove the period

T.*                 # Think of a number -> .*\n$* (replaces input with unary)
.*¶$$*
\;+`(.*)¶rep.*(¶?)  # Loop, replacing "repeat" with the line before it
$1¶$1$2
\d+                 # Replace all numbers with their unary representation
$*
.*f.* (1*)          # Replace "subtract from " with a subtract from program
1¶x¶$¶$1¶+`x1¶
m.*                 # Replace "multiply by " with a multiply program
1¶
di.* (1*)           # Replace "divide by " by my integer division program
^¶$1 ¶^(1+) (\1)+1*$¶x$$#+¶1+ 1*¶x0¶x\d+¶$$*
s.* (1*)            # Replace "subtract " with a subtraction program
^$1¶
a.*                 # Replace "add " with an addition program
^¶
\z                  # At the end, add a stage to change unary into decimal
¶1

Matematik programları:

Eklemek:

Başına olan sayısını ekleyin. 5 ekle:

^
1111

Çıkar:

Baştakilerin sayısını kaldırın. Çıkarma 5:

^11111

Şuradan çıkar:

1S girişini s ile değiştirin x. Sabit numaranın yanına koyun. Tekrar tekrar kaldırın x1. 10'dan çıkar:

1
x
$
1111111111
+`x1

İle çarpın:

Her birini 1belirli bir sayı ile değiştirin . 3 ile çarp:

1
111

Bölünür:

Bu benim Integer Bölümü için Retina programı kullanır . 2'ye bölün:

^                   # Place the fixed divisor before the dividend
11 
^(.+) (\1)+.*$      # Match the divisor, followed by each occurrence in the dividend.
x$#+                # Replace with the number of matches. Trailing ones are dropped
.+ .*               # If there are still two numbers, the result is zero
x0
x\d+                # Replace result (marked with an 'x') with unary
$*

Korkarım bunun nasıl işe yarayacağını bilmiyorum. Çıkarma komutları için hangi girişleri denersem deneyeyim, kırılmış sonuçlar elde ederim (çıktıda satır hataları var mı?). Bunun olumsuz girdileri veya olumsuz ara sonuçları nasıl ele aldığını da göremiyorum.
Martin Ender

@MartinEnder Bu basitleştirilmiş programın neden çıktıda iki program verdiğini açıklarsanız çıkarma işlemini düzeltebilirim. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007

Çünkü $ipin en sonunda ya da takip eden bir satır akışının önünde eşleşir. \zSadece eski olanı istiyorsan ihtiyacın var .
Martin Ender,

4

GNU awk, 139 bayt

BEGIN{RS="[,.]";c="{}{";ORS=";"}
/ad/{c="+="$2}
/c/{c="-="$2}
/om/{c="="$3"-$0"}
/l/{c="*="$3}
/v/{c="=int($0/"$3")"}
!NF{c="}1"}
$0="$0"c

çağırma:

$> awk `awk -f wordmath <<< "Think of a number, add 1, repeat, repeat."` <<< 0
$> 3

Test durumları:

$> awk -f wordmath <<< "Think of a number."  
$> $0{}{;$0}1;

$> awk -f wordmath <<< "Think of a number, divide by 5, subtract from 9."
$> $0{}{;$0=int($0/5);$0=9-$0;$0}1;

$> awk -f wordmath <<< "Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
$> $0{}{;$0+=5;$0+=10;$0*=2;$0-=15;$0-=15;$0=int($0/2);$0}1;

4

Haskell, 232 231 bayt

Elbette, işlevsel bir programcı, bir programı temsil eden bir dize yerine bir işlev döndürmeyi tercih eder, ancak işte başlıyoruz:

t l="main=getLine>>=print."++""%words l++"(0+).read"
x%((o:_):f:n:r)|o=='m'=h"*"n r|o=='d'=h"`div`"n r|f=="from"=h"(-)"n r
x%(s:n:r)|s=="add"=h"+"n r|s!!0=='s'=h s(' ':n)r
x%(_:r)=x%r++x
_%_=""
h s n r|x<-'(':s++init n++")."=x%r++x

Notlar: Her zaman sıfır eklemeye başlarız, aksi takdirde önemsiz WordMath programının aktarılması read, kullanılan türden çıkarım için yeterli bilgi vermez . subtract from nolarak uygulanabilir (n-), ancak ((-)n)daha fazla tek biçimlilik için kullanıyorum . Eğer girişi girdiden subtract nkopyaladığımda subtractyazmam gerekmiyor ama sonunda eksik olan alanı telafi etmem gerekiyor. repeatvarsayılan işlem olarak kullanılır; önceki boş bir işlemle birlikte bu ilk dört kelimenin görmezden gelinmesini sağlar.

Kullanım örneği:

*Main> t "Think of a number. "
"main=getLine>>=print.(0+).read" 

Diğer örnekler aşağıdaki sonuçları verir:

"main=getLine>>=print.((-)9).(`div`5).(0+).read"
"main=getLine>>=print.(`div`2).(subtract 15).(subtract 15).(*2).(+10).(+5).(0+).read"  
"main=getLine>>=print.(subtract 1).(subtract 1).(subtract 1).(0+).read"

Merak ediyorum, bir dize yerine döndürmek için nasıl bir işlev üretin?
Cyoce

İşlevsel bir programlama dilinde, bir işlev oluşturmak ve oluşturmak, bir dize oluşturmak ve eklemekten daha zor değildir. hgibi bir şeye benzeyebilir h s n r|x<-s.read.init$n=x%r.xve ilk argümanla bir fonksiyon gibi çağrılabilir h(+)n r(ve flipdoğru operatör sırasını almak için bir yerlerde olması gerekir), temel durum _%_=id. Ana fonksiyon tüm kazan plakasını önleyebilir ve sadece olabilir t l=id%words l. - Kıvırma sayesinde tercüman olarak görülebilir ve bu fikir daha kolay ve / veya daha kısa bir çözüme yol açabilir.
Christian Sievers,

4

Python 2,263 258 260 221 bayt

Bu muhtemelen hala çok daha kısa olabilir.

def r(s,o="",p=""):c=s.pop(0);c=[c,p]['re'in c];n=c.split()[-1];o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c];return s and r(s,"(%s)"%o,c)or o
lambda s:"print "+r(s.split(','))

Çevrimiçi deneyin

Bunun //yerine kullanıyorum /, çünkü son komutun .sonunda bir sonuç olacak ve herhangi bir sayıyı değiştiriyor. Bu yüzden bölünmeyi tutarlı tutmak için tamsayıyı kullanıyorum.

Test durumları çıkışı:

print input()
print 9.-((input())//5)
print ((((((input())+5)+10)+10)-15)-15)//2.
print (((input())-1)-1)-1

Eğer bu büyük bloğunu değiştirirseniz ifiçin s o(ı çalışması gerektiğini düşünüyorum) aşağıdakilere: o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c], sen 224 için aşağı alabilirsiniz
Kade

@Kade Evet, hala okunaklıydı. Buna sahip olamazsın.
mbomb007

@Cyoce Hayır, lambda olarak adlandırılan eylem muhtemelen kaydettiğinden daha pahalıya mal olacak. Ödeme yapmak için arama başına 4 veya 5 bayt kaydetmesi gerekirdi.
mbomb007

4

Befunge, 342 305 bayt

>~$1 +:89+`#v_801p
  v_^#`+85~$<
1+>~:5+88+/3-!#v_$
v`"/":~p8p10+1<>>:"/"`!|
 "+"\5+8p4+:1+^:p11:g10<  >:"+"\2+8p:"*"\3+8p:
_$7%:01g\!#v_\2-7g\:1+:01v^p8+1\"5":p8\"5":g10
#8\"\"$#:0#<^v<p8p8\<g80p<>\#+$#12#p
-/+* >:#,_@  #^p8g10<
".@"<^"&"
10<v0<\g8-\g11:<:p1>#1+g11:p10+g
-:^>1g\-8p1-::#^_$8g^  >$$01g11g

Çevrimiçi deneyin!

Çıktı

Ürettiği kod &(giriş değeri) komutuyla başlar ve .(çıkış değeri) ve @(çıkış) komutlarıyla biter . Biz şeklinde çeşitli hesaplamalar var Arada <number><operation>, operasyon olabilir +(eklenti), -(çıkarma), /(bölme ile), *(çarpın tarafından) ve \-(çıkarma).

Numara o ihtiyaçlara daha büyük şey elle hesaplanacak böylece Befunge sadece, aralık 0 ile 9 sayısal değişmezleri destekler çünkü kendisi biraz karışık. Zaten karakterdeki sayıları karakter karakterinde okuduğumuz için, her basamak okundukça sayıyı artırıyoruz 155+*2+55+*3+, örneğin 123 olur , yani (((1 * 10) + 2) * 10) + 3.

Örnekler

Input:  Think of a number.
Output: &.@

Input:  Think of a number, divide by 5, subtract from 9.
Output: &5/9\-.@

Input:  Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.
Output: &5+155+*0++2*155+*5+-155+*5+-2/.@

Input:  Think of a number, subtract 1, repeat, repeat.
Output: &1-1-1-.@

açıklama

Befunge, karakter dizilerini bu şekilde manipüle etme yeteneğine sahip değildir, bu yüzden ayrıştırmanın çoğu karakterleri saymakla ilgilenir. Biz sadece bir 18 rakamı geçerek başlıyoruz, bu da bizi bir Sayı Düşüncesini (artı virgül veya periyot) düşünmeden geçiriyor. Sonra bir sonraki karakter bir tür yeni satır veya EOF ise doğrudan çıktı rutine gideriz, aksi halde bir komut listesi aramaya devam ederiz.

Bir komutu ayrıştırmak için, bir rakam veya ayırıcıya ulaşana kadar karakterleri saymaya devam ediyoruz. Ayırıcı ise, özel bir durum olarak ele aldığımız yineleme komutu olmalı. Eğer bir rakamsa, onu çıkış tamponumuza ekleriz ve daha fazla rakam aramaya devam ederiz. Her bir rakam çıktılandığında önek ekleriz ( 55+*toplamı 10 ile çarpmak için) ve son ekini +(toplamı eklemek için). Rakamlar bittiğinde komut karakterini ekleriz.

Komut nasıl belirlendiğini gelince, biz ilk basamak karakter sayısını almak için 7. modulo eklemek için, (aşağıdaki alana dahil) bu 4'tür çıkarma durum 2 için, bölme bunun için, 3 var çarpın tarafından o 5 var ve için Çıkart o en 0. dan çıkarma ihtiyacı beri biraz ek işlem gerektirmez \-komut açılan, ancak diğerleri sadece tablodaki uygun komut karakterini arama kendi değerini kullanın.

Bu işlem, her komut için tekrarlanır, çıktıyı 8. satırda önceden oluşturulmuş bir dizgeye dönüştürür. Ek bir komut her eklendiğinde, her zaman düzgün bir şekilde sonlandırıldığından emin olmak için dizeye bir kapanış teklifi ekleriz. Sonunda girdilerimizin sonuna ulaştığımızda, yığına itmek için bu dizgiyi "yürütüyoruz", sonra hepsini yazmak için standart bir çıktı dizisi ile takip ediyoruz.


3

JavaScript (ES6), 163 bayt

w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

Dene:

f=w=>w.split`, `.map(l=>(o={a:'+',s:'-',m:'*',d:'/'}[a=l[0]])?p=(x=l.split` `.pop(),l[9]=='f'?x+`-n`:`n`+o+x+`|0`):a<'r'?'n=+prompt()':p).join`
n=`+`
console.log(n)`

const program = f('Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2.')
document.write('<pre>' + program + '</pre>' )

eval(program)

/*
Outputs:

n=+prompt()
n=n+5|0
n=n+10|0
n=n*2|0
n=n-15|0
n=n-15|0
n=n/2.|0
console.log(n)
*/


3

Vim 208 171 168 bayt

@ Flp.Tkc'ye göre arka arkaya birden fazla tekrar yapabilme özelliği eklendi, ancak hala bayt sayısını azaltabilecek kadar bayttan kurtuldum.

:map s :s;\v
c4wcw="s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(@qq@qx$xA

TryItOnline

Yazdırılamayan karakterler:

:map s :s;\v
c4wcw^V^R=^V^R"^[s, s\w* \w+ (\d+); *-1+\1);g
s, ([adms]).{-}(\d+); \1\2);g
qws(\S+), r\w+;\1 \1
@wq@ws.*;\=tr(submatch(0),'adms','+/*-')
qq])T=i(^[@qq@qx$xA
^V^[^[

Test durumları çıkışı:

  1. cw^R=^R" ^[ TryItOnline
  2. cw^R=((^R" /5) *-1+9) ^[ TryItOnline
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ TryItOnline

Bu art arda çoklu tekrarlar için işe görünmüyor.
FlipTack

@ Flp.Tkc düzeltildi, teşekkür ederim! Bunu daha önce farketmemiştim.
nmjcman101

2

lex, 246 bayt

%{
#define P printf
#define O P("n%s%d;",c,v);
int v;char*c;
%}
%%
T {P("%%%%\n.* {int n=atoi(yytext);");}
ad {c="+=";}
fr {c="=-n+";}
s {c="-=";}
v {c="/=";}
l {c="*=";}
re {O}
[0-9]+ {v=atoi(yytext);O}
\. P("printf(\"%%d\",n);}\n%%%%");
. ;
%%

lex, C'yi hedef aldığından, bir C derleyicisinin onu çalıştırılabilir bir şeyde derlemesi gerekir. Lexer kütüphanesinin ( ll) de bağlanması gerekir. Bu, bayt cezası ekleyebilir, ancak kaç bayt olduğundan emin değilim.

Program, transpillenmiş wordmath ifadesini değerlendiren bir lex programı (şartname başına) çıkarır. Arasındaki kod %{ve %}sadece "transpiler" içindir:

#define P printf              /* for brevity */
#define O P("n%s%d;",c,v)     /* expression builder, calls P = printf */
int v;char*c;                 /* v=most recent integer read */
                              /* c=the expression infix */

İki %%çizgi arasında regex / eylem kısmı var. Eşleştirilecek ilk kural T, başlangıç ​​ekini oluşturan (lex programları en azından kural bölümünü içermelidir ve yytexten son eşleşen metindir ) ("düşün ...") olacaktır. ).

Eşleştirilir tüm giriş bunun dışında programı atar ve diğer düzenlemeler ( ad, fr, kadar re) mümkün olduğu kadar az bir eşleşme özgü olacak şekilde olan wordmath sentezleme maddeleri işlemek. Bunların çoğunda, arandığında okunan son tamsayı carasında birleştirilmiş bir ifade ekine ayarlanır (bu nedenle, örneğin, "add 9" okumak, eki , v 'ye ayarlayacak ve çağrı yapılacak ) . (Bir kenara ilginç "8 çıkarma" olduğunu neden olacaktır hem ve kurallar eşleşti, ancak o zamandan beri almak için sadece numaradan denir uygun kural çıkışını alır tek ifadesidir). "Tekrar" sadece aramalar için kuralnO+=9On+=9;sfrOn=-n+8;reOYine, en son oluşturulan ifadenin çıktısını alır (ve sonraki eşleşmeler clobber olacağından yytext, "yinelemeyi" destekleyen [0-9]+kuralda tamsayı dönüşümünün gerekli olmasının nedenidir ). Son olarak, bir süre, program römorkunun sadece akümülatör %%çıktısı veren ve çıktı lex programının sonunu belirten çiftle kapanan çıktı olmasına neden olur .

Not: Ana aktarıcı programı veya çıkış programı sonlandırılmaz. Boru girişi işe yarayabilir veya EOF (ctrl-D) sağlar. İlk girişten sonra sonlandırma gerekiyorsa, exit () s eklenebilir.

Oluşturmak / çalıştırmak için:

Build the main program:
% lex -o wordmath.yy.c wordmath.l
% cc -o wordmath wordmath.yy.c -ll

Execute to create a specific transpiled program:
% echo "This is a number, add 8, subtract 5, repeat." | ./wordmath > program.l

Build the transpiled program:
% lex -o program.yy.c program.l
% cc -o program program.yy.c -ll

Execute the transpiled program (with input 3, called via a pipe or inline):
% echo 3 | ./program
1
% ./program
3
1
^D
%

Test 1:

%%
.* {int n=atoi(yytext);printf("%d",n);}
%%

Test 2:

%%
.* {int n=atoi(yytext);n/=5;n=-n+9;printf("%d",n);}
%%

Test 3:

%%
.* {int n=atoi(yytext);n+=5;n+=10;n*=2;n-=15;n-=15;n/=2;printf("%d",n);}
%%

Test 4:

%%
.* {int n=atoi(yytext);n-=1;n-=1;n-=1;printf("%d",n);}
%%

2

Pyth, 69 67 bayt

J\QVtcQ\,Iq@N1\r=NZ)=Jjd+@"+-/*"x"asdm"@N1.>,J-ecN)\.qh@cN)1\f=ZN)J

A'yı alan "quoted string"ve sonucu basan bir program .

Test odası

Nasıl çalışır

Pyth önek operatörlerine sahiptir, bu nedenle temel aritmetik işlemler (operator)(operand1)(operand2), önceden başlatılmış değişken Qgirdi verirken gerçekleştirilir. Bu nedenle, bir transpillenmiş WordMath programı dizeyle başlayarak 'Q've her aşamada operatörü hazırlayarak ve ardından operandı gerekli olarak hazırlayarak ya da ekleyerek oluşturulur.

J\QJTranspiled program dizgisini dizeye ayarlayın'Q'

tcQ\, Girişi virgüllere ayırın ve ilk öğeyi ('olan Think of a number') atın

V Bunun için N:

  • Iq@N1\r Karakteri de ise N[1]ise 'r'(tekrar):
    • =NZSet Niçin Z(bir önceki değeri Ndöngüsünün sonunda belirlenir)
  • x"asdm"@N1 Dizinini bulun N[1]içinde "asdm"(eklenti, çıkarma, bölme, çarpma)
  • @"+-/*""+-/*"İstenilen operatörü vererek bununla indeksleyin
  • ,J-eCN)\.Herhangi bir karakter kaldırılmış olarak [J, -eCN)\.]ikinci öğenin Nboşluktaki boşluktaki son öğe olduğu iki öğe listesini verin '.'(işlenen)
  • qh@cN)1\fNBeyazdaki bölünmüş ikinci öğenin ilk karakteri 'f'(çıkarma):
    • .> İki eleman listesinin elemanlarını değiştirme
  • + İşleci ve iki elemanlı listeyi tek bir listede birleştir
  • =JjdJAlanlarda birleştirilene ayarla
  • =ZN Set ZiçinN

J baskı J


Güzel cevap adam ... Beklediğimden daha korkutucu olan 05AB1E'de denememe ilham verdi.
Sihirli Ahtapot Urn

2

Pip , 58 bayt

Ne yazık ki, bu ters çıkarma operatörünü henüz uygulamadım.

{p:a:sNa?ap['Y("-y+  y- y// y+ y* "^sa@?Y`\d`)|'qa@y]}Mq^k

Program stdin'den bir WordMath betiği alır ve Pip kodunu stdout'a çıkarır. Çıktı yapan kod da benzer şekilde stdin'den bir sayı alır ve sonucu stdout'a verir. Çevrimiçi deneyin!

strateji

Bunun gibi bir giriş için:

Think of a number, multiply by 3, add 1.

şöyle çıktı istiyoruz:

YqYy*3Yy+1

aşağıdaki gibi çalışır:

Yq    Yank a line of stdin into y
Yy*3  Compute y*3 and yank result into y
Yy+1  Compute y+1 and yank result into y
      Last expression is autoprinted

Ungolfed + açıklama

{
 p : a : sNa ? a p
 [
  'Y
  ("-y+  y- y// y+ y* "^s a@?Y`\d`) | 'q
  a@y
 ]
} M q^k

Programın temel yapısı, (virgül boşluğu) üzerine bir satır (stdin çizgisi) {...}Mq^kbölen ve her bir elemana bir işlev sağlayan şeydir.qkM

Fonksiyonun içinde repeatdavayı ele alarak başlıyoruz . Pip'deki en kısa test gibi görünüyor sNa(komutta bir boşluk var). Eğer öyleyse kullanmak istiyoruz a; değilse pönceki komutu saklayan kullanın. Bu değeri tekrar ave sonra p(bir dahaki sefere) atayın .

Dönüş değerimizde, liste için varsayılan çıktı biçiminin her şeyi bir araya getirmek olduğu için iyi bir liste kullanırız. Sonuç her zaman ile başlar Y. Ardından, işlemler için bir arama tablosu gerekir.

add (4), subtract (9), divide by (10), multiply by (12) ve subtract from (14) uzunluklarının hepsinin farklı olduğunu gözlemleyin . Ayrıca, mod 7'de alındıklarında hala farklı olduklarını gözlemleyin. Böylece, her WordMath komutunu uygun Pip koduna (bu şekilde tasarlanmış şekilde) eşlemek için yedi öğeli bir listeye (beş kod parçacığı ve iki yer tutucu içeren) endekslemek için kullanabiliriz sadece sonuna kadar birleştirilebilir):

  • 0: -y+( subtract from)
  • 1: yer tutucu
  • 2: y-( subtract)
  • 3: y//( divide by)
  • 4: y+( add)
  • 5: y*( multiply by)
  • 6: yer tutucu

Endeksleri için, komuta ilk basamak dizinini almak için regex kullanın: a@?`\d`. yGelecekte kullanmak için regex'i de içine çekiyoruz . Arama tablosu dizesini bölerek oluşturulan "-y+ y- y// y+ y* "üzerinde s(boşluk).

Yine de koda çevrilmesi gereken ilk girişi ele almalıyız Yq. İtibaren Think of a numberherhangi bir basamak içermez, @?operatör döner nil. Nil'i arama tablosuna bir dizin olarak kullanmak da nil değerini döndürür. Nil sahtedir, bu yüzden yapmamız gereken tek şey bu dava için bir işlem yapmak yerine |'qkullanmak q.

Döndürülen listenin son elemanı sayının kendisidir. Bunu yoluyla elde ederiz a@y(tüm eşleşmeleri daha önce sıraladığımız rakam regex komutunda bulabilirsiniz). Bu, rakamların bir listesini döndürür, fakat yine de sorun değildir, çünkü çıktıda tüm listeler birleştirilir. İlk giriş için a@yrakamlarla eşleşmez ve çıkışa hiçbir şey eklemeyen boş bir liste verir.

Örneğin

Giriş ile

Think of a number, subtract from 20, add 2, repeat.

harita ifadesi listeyi verir

[["Y";"q";[]]; ["Y";"-y+";[2;0]]; ["Y";"y+";[2]]; ["Y";"y+";[2]]]

birleştirildiğinde, çıktılar

YqY-y+20Yy+2Yy+2

2

Python 2 , 154 153 146 bayt

Bu işlem sırasında sabit ve hatta birkaç bayt kaydedildi. ^ __ ^

for c in input()[9:-1].split(","):s=c.rfind(" ");p=o=s and"x="+"-x+ input() x- x// x+ x*".split()[s%7]+c[s:]*(c[0]<"a")or p;print o
print"print x"

Çevrimiçi deneyin!

Pip cevabımla aynı stratejiye dayanarak . Python'a özgü özellikler:

  • Think of ve .bölme ( input()[9:-1]) ' den önce kapanış ipten çıkarılır . Süre, ana döngüde kullanılamayacak kadar sinir bozucuydu. İlk dokuz karakteri kaldırmak farklı bir nedenden dolayı yardımcı olur (aşağıya bakınız).
  • Her komutun uzunluğunu regex arayarak bir rakam (Python'da pahalı) arayarak almak yerine komuttaki son boşluğu bulmak için import rekullanırız rfind(" "). Bunu repeatdavayı kontrol etmek için de kullanabiliriz .
  • Python Pip'in döngüsel endekslemesine sahip değil, bu yüzden açıkça mod 7'yi almalıyız. Öte yandan, bu, dizin tablosundaki 7 asla 6 olmadığından, arama tablosundaki son boş değeri kaldırabileceğimiz anlamına gelir.
  • İlk kez "komut" a number, boşluk indeksinin bulunduğu yerdir 1. Bu dizin arama tablosundaki diğer deliği rahatlıkla dolduruyor. Giriş döngüsünün ana döngüde işlenmesiyle ilgili diğer problem, bununla +c[s:]sonuçlanacak bölümdü x=input() number. Bu sorunu çözmek için, şu şekilde dize çarpıyoruz c[0]<"a": içinde bir boşlukla başlayan, ancak başlangıçtaki 1tüm normal komutlar için .c0a number

1

WinDbg, 449 388 bayt

as, }@$t1
as. }0;?@$t0
asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
aSa " "
asQ .printf";r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0
as/c add Q +"
aSby " "
as/c divide Q /"
asfrom 0;r$t0=-@$t0+
as/c multiply Q *"
aSnumber " "
aSof " "
asrepeat +1
as/c subtract Q -"
.for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."

Tekrarlanan kod için takma isim tanımlayarak -61 bayt

LambdaBeta'nın kullanımından ilham aldı #define. Bu yaklaşım değiştirir WordMath sözdizimi hafifçe ( ,ve .boşlukla ayrılmış başka deyişle gibi olmalıdır ve ,takip etmez repeat) ve modifiye WordMath sözdizimi geçerli WinDbg kodu olacak şekilde takma oluşturur. Son satır, girdiyi değiştirilen sözdizimine dönüştürerek sorunun ne sorduğunu ve aktardığını yapar.

Bir hafıza adresinde bir dize ayarlayarak ve sözde kayıt defterini $t0bu adrese ayarlayarak giriş yapılır . Not: Bu üzerine yazacaktır intde 0x2000000orada bütün dize başlatmak eğer öyleyse, kısmen üzerine yazılır edeceğiz. $t0ayrıca üzerine yazılacaktır.

Diğer adlar oluşturduğundan, bu kodun dize ayarından önce veya sonra çalışıp çalışmadığına bağlı olarak, çıkış kodu farklı olacaktır (takma ad veya değil). Ne yazık ki, boşlukların sınırlandırılmadan takma adların düzgün şekilde genişlemesini sağlamanın bir yolunu bulamadım (yani, WordMath komut dosyası yalnızca önce dönüştürülmeden doğrudan çalıştırılamazdı).

Nasıl çalışır:

* $t1 is used for repeating and $t0 is used to read the input and hold the accumulator
* Alias , to }@$t1 -- closing do-while loop and allowing repeat
as , }@$t1

* Alias . to }0;?@$t0 -- close do-while loop and evaluate $t0 (accumulator)
as . }0;?@$t0

* Alias Think to (note this is one line)
as Think n10;               * Set base 10
         ed 8<<22;          * Read ints to address 0x2000000. Enter nothing to exit input mode
         r$t0 = dwo(8<<22); * Set $t0 = first int
         r$t1=0;.do{        * Open do-while

* Alias a to nothing
aS a " "

* Alias add to (note one line):
as add ;                       * Close previous statement
       r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
       r$t0=@$t0+              * Add number to $t0

* Alias by to nothing
aS by " "

* Alias divide to (note one line):
as divide ;                       * Close previous statement
          r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
          r$t0=@$t0/              * Divide next number from $t0

* Alias from to (note one line):
as from 0;         * Preceding subtract statement subtracts 0
       r$t0=-@$t0+ * Subtract $t0 from next number

* Alias multiply to (note one line):
as multiply ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0*              * Multiply next number with $t0

* Alias number to nothing
aS number " "

* Alias of to nothing
aS of " "

* Alias repeat to +1 making do-while (once) loops into do-while (once)+1
as repeat +1

* Alias subtract to (note one line):
as subtract ;                       * Close previous statement
            r$t1=1;.do{r$t1=@$t1-1; * Open do-while (once) loop
            r$t0=@$t0-              * Subtract next number from $t0


.for (r$t9=1; by(@$t0); r$t0=@$t0+1) * Enumerate the string
{
    j 44!=by(@$t0)                   * If not comma
        .printf "%c",by(@$t0);       * Print the char
    * implicit else
        .if 116!=by(@$t0-1)          * Else if the previous char is not t
        {
          .printf " , "              * Print the comma with spaces around it
        }
};
.printf "\b ."                       * Replacing ending "." with " ."

Bu kodu bir kez çalıştırmadan önce dizgeye giren örnek çıktı (elde edilen program WordMath'a benzer):

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0

0:000> Think of a number ,  add 5 ,  add 10 ,  multiply by 2 ,  subtract 15 ,  repeat divide by 2 }0;?@$t0
base is 10
02000000 6e696854 18
18
02000004 666f206b 

Evaluate expression: 18 = 00000012

Bu kodun bir kere çalıştırılmasından sonra dizgeye girilen örnek çıktı (dize girilirken takma ad genişletilir, böylece ortaya çıkan program o kadar güzel olmaz):

0:000> r$t0=8<<22
0:000> eza8<<22"Think of a number, add 5, add 10, multiply by 2, subtract 15, repeat, divide by 2."
0:000> as, }@$t1
0:000> as. }0;?@$t0
0:000> asThink n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{
0:000> aSa " "
0:000> asadd ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+
0:000> aSby " "
0:000> asdivide ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/
0:000> asfrom 0;r$t0=-@$t0+
0:000> asmultiply ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*
0:000> aSnumber " "
0:000> aSof " "
0:000> asrepeat +1
0:000> assubtract ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0-
0:000> .for(r$t9=1;by(@$t0);r$t0=@$t0+1){j44!=by(@$t0) .printf"%c",by(@$t0);.if116!=by(@$t0-1){.printf" , "}};.printf"\b ."
n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0

0:000> n10;ed8<<22;r$t0=dwo(8<<22);r$t1=0;.do{     number ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 5 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0+ 10 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0*   2 ,  ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0- 15 ,  repeat ;r$t1=1;.do{r$t1=@$t1-1;r$t0=@$t0/   2 }0;?@$t0
base is 10
02000000 3b30316e 26
26
02000004 3c386465 

Evaluate expression: 26 = 0000001a

Sadece biraz değiştirilmiş WordMath sözdizimini kullanarak daha fazla örnek çıktı:

0:000> Think of a number , add 1 , repeat repeat repeat divide by 3 .
base is 10
02000000 0000001a 3
3
02000004 3c386465 

Evaluate expression: 2 = 00000002


0:000> Think of a number , divide by 5 , subtract from 9 .
base is 10
02000000 00000003 29
29
02000004 3c386465 

Evaluate expression: 4 = 00000004

0

Scala, 338 bayt

Ideone'da kendin dene

s=>{val n=(_:String)filter(_.isDigit)toInt;(Seq("").tail/:s.split(",").tail)((a,&)=> &match{case&if&contains "v"=>a:+"x/="+n(&)
case&if&contains "d"=>a:+"x+="+n(&)
case&if&contains "y"=>a:+"x*="+n(&)
case&if&contains "f"=>a:+"x="+n(&)+"-x"
case&if&contains "s"=>a:+"x-="+n(&)
case p=>a:+a.last})mkString("var x=readInt;",";",";print(x)")}

Açıklama:

// define a function with a parameter s
s => {
    // define a function with a String parameter to extract a number from a string
    val n =
        // filter out the chars that arent't digits
        (_: String) filter (_.isDigit)
        // and parse the number
        toInt;
    // take the tail of a list with an empty string,
    // which is the empty list of type Seq[String].
    // This is the start value for the fold...
    (Seq("").tail /:
        // ... of the tail of the sentence splitted at commas
        s.split(",").tail
    ) (
        // This is the function for the fold.
        // a is the accumulator (the list), and the current element is called &
        (a, &) => & match {
            // if & contains a "v", append "x/=" + n(&) to a.
            case & if & contains "v" => a :+ "x/=" + n(&)
            // the other cases are similar
            case & if & contains "d" => a :+ "x+=" + n(&)
            case & if & contains "y" => a :+ "x*=" + n(&)
            case & if & contains "f" => a :+ "x=" + n(&) + "-x"
            case & if & contains "s" => a :+ "x-=" + n(&)
            // for the repeat, apppend the last value of a to a
            case p                   => a :+ a.last
        }
     )
     // make a string out of the parts by joining them with semicolons,
     // prepending "var x=readInt;" and appending ";print(x)"
     mkString("var x=readInt;", ";", ";print(x)")
}
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.